1use crate::raw_condvar::RawCondvar;
9
10pub use lock_api::WaitTimeoutResult;
11
12pub type Condvar = lock_api::Condvar<RawCondvar>;
70
71#[cfg(test)]
72mod tests {
73 use crate::{Condvar, Mutex, MutexGuard};
74 use std::sync::mpsc::channel;
75 use std::sync::Arc;
76 use std::thread;
77 use std::thread::sleep;
78 use std::thread::JoinHandle;
79 use std::time::Duration;
80 use std::time::Instant;
81
82 #[test]
83 fn smoke() {
84 let c = Condvar::new();
85 c.notify_one();
86 c.notify_all();
87 }
88
89 #[test]
90 fn notify_one() {
91 let m = Arc::new(Mutex::new(()));
92 let m2 = m.clone();
93 let c = Arc::new(Condvar::new());
94 let c2 = c.clone();
95
96 let mut g = m.lock();
97 let _t = thread::spawn(move || {
98 let _g = m2.lock();
99 c2.notify_one();
100 });
101 c.wait(&mut g);
102 }
103
104 #[test]
105 fn notify_all() {
106 const N: usize = 10;
107
108 let data = Arc::new((Mutex::new(0), Condvar::new()));
109 let (tx, rx) = channel();
110 for _ in 0..N {
111 let data = data.clone();
112 let tx = tx.clone();
113 thread::spawn(move || {
114 let (lock, cond) = &*data;
115 let mut cnt = lock.lock();
116 *cnt += 1;
117 if *cnt == N {
118 tx.send(()).unwrap();
119 }
120 while *cnt != 0 {
121 cond.wait(&mut cnt);
122 }
123 tx.send(()).unwrap();
124 });
125 }
126 drop(tx);
127
128 let (lock, cond) = &*data;
129 rx.recv().unwrap();
130 let mut cnt = lock.lock();
131 *cnt = 0;
132 cond.notify_all();
133 drop(cnt);
134
135 for _ in 0..N {
136 rx.recv().unwrap();
137 }
138 }
139
140 #[test]
141 fn notify_one_return_true() {
142 let m = Arc::new(Mutex::new(()));
143 let m2 = m.clone();
144 let c = Arc::new(Condvar::new());
145 let c2 = c.clone();
146
147 let mut g = m.lock();
148 let _t = thread::spawn(move || {
149 let _g = m2.lock();
150 assert!(c2.notify_one());
151 });
152 c.wait(&mut g);
153 }
154
155 #[test]
156 fn notify_one_return_false() {
157 let m = Arc::new(Mutex::new(()));
158 let c = Arc::new(Condvar::new());
159
160 let _t = thread::spawn(move || {
161 let _g = m.lock();
162 assert!(!c.notify_one());
163 });
164 }
165
166 #[test]
167 fn notify_all_return() {
168 const N: usize = 10;
169
170 let data = Arc::new((Mutex::new(0), Condvar::new()));
171 let (tx, rx) = channel();
172 for _ in 0..N {
173 let data = data.clone();
174 let tx = tx.clone();
175 thread::spawn(move || {
176 let (lock, cond) = &*data;
177 let mut cnt = lock.lock();
178 *cnt += 1;
179 if *cnt == N {
180 tx.send(()).unwrap();
181 }
182 while *cnt != 0 {
183 cond.wait(&mut cnt);
184 }
185 tx.send(()).unwrap();
186 });
187 }
188 drop(tx);
189
190 let (lock, cond) = &*data;
191 rx.recv().unwrap();
192 let mut cnt = lock.lock();
193 *cnt = 0;
194 assert_eq!(cond.notify_all(), N);
195 drop(cnt);
196
197 for _ in 0..N {
198 rx.recv().unwrap();
199 }
200
201 assert_eq!(cond.notify_all(), 0);
202 }
203
204 #[test]
205 fn wait_for() {
206 let m = Arc::new(Mutex::new(()));
207 let m2 = m.clone();
208 let c = Arc::new(Condvar::new());
209 let c2 = c.clone();
210
211 let mut g = m.lock();
212 let no_timeout = c.wait_for(&mut g, Duration::from_millis(1));
213 assert!(no_timeout.timed_out());
214
215 let _t = thread::spawn(move || {
216 let _g = m2.lock();
217 c2.notify_one();
218 });
219 let timeout_res = c.wait_for(&mut g, Duration::from_secs(u64::max_value()));
220 assert!(!timeout_res.timed_out());
221
222 drop(g);
223 }
224
225 #[test]
226 fn wait_until() {
227 let m = Arc::new(Mutex::new(()));
228 let m2 = m.clone();
229 let c = Arc::new(Condvar::new());
230 let c2 = c.clone();
231
232 let mut g = m.lock();
233 let no_timeout = c.wait_until(&mut g, Instant::now() + Duration::from_millis(1));
234 assert!(no_timeout.timed_out());
235 let _t = thread::spawn(move || {
236 let _g = m2.lock();
237 c2.notify_one();
238 });
239 let timeout_res = c.wait_until(
240 &mut g,
241 Instant::now() + Duration::from_millis(u32::max_value() as u64),
242 );
243 assert!(!timeout_res.timed_out());
244 drop(g);
245 }
246
247 fn spawn_wait_while_notifier(
248 mutex: Arc<Mutex<u32>>,
249 cv: Arc<Condvar>,
250 num_iters: u32,
251 timeout: Option<Instant>,
252 ) -> JoinHandle<()> {
253 thread::spawn(move || {
254 for epoch in 1..=num_iters {
255 let mut sleep_backoff = Duration::from_millis(1);
259 let _mutex_guard = loop {
260 let mutex_guard = mutex.lock();
261
262 if let Some(timeout) = timeout {
263 if Instant::now() >= timeout {
264 return;
265 }
266 }
267
268 if *mutex_guard == epoch {
269 break mutex_guard;
270 }
271
272 drop(mutex_guard);
273
274 sleep(sleep_backoff);
277 sleep_backoff *= 2;
278 };
279
280 cv.notify_one();
281 }
282 })
283 }
284
285 #[test]
286 fn wait_while_until_internal_does_not_wait_if_initially_false() {
287 let mutex = Arc::new(Mutex::new(0));
288 let cv = Arc::new(Condvar::new());
289
290 let condition = |counter: &mut u32| {
291 *counter += 1;
292 false
293 };
294
295 let mut mutex_guard = mutex.lock();
296 cv.wait_while(&mut mutex_guard, condition);
297
298 assert!(*mutex_guard == 1);
299 }
300
301 #[test]
302 fn wait_while_until_internal_times_out_before_false() {
303 let mutex = Arc::new(Mutex::new(0));
304 let cv = Arc::new(Condvar::new());
305
306 let num_iters = 3;
307 let condition = |counter: &mut u32| {
308 *counter += 1;
309 true
310 };
311
312 let mut mutex_guard = mutex.lock();
313 let timeout = Instant::now() + Duration::from_millis(500);
314 let handle = spawn_wait_while_notifier(mutex.clone(), cv.clone(), num_iters, Some(timeout));
315
316 let timeout_result = cv.wait_while_until(&mut mutex_guard, condition, timeout);
317
318 assert!(timeout_result.timed_out());
319 assert!(*mutex_guard == num_iters + 1);
320
321 drop(mutex_guard);
323 handle.join().unwrap();
324 }
325
326 #[test]
327 fn wait_while_until_internal() {
328 let mutex = Arc::new(Mutex::new(0));
329 let cv = Arc::new(Condvar::new());
330
331 let num_iters = 4;
332
333 let condition = |counter: &mut u32| {
334 *counter += 1;
335 *counter <= num_iters
336 };
337
338 let mut mutex_guard = mutex.lock();
339 let handle = spawn_wait_while_notifier(mutex.clone(), cv.clone(), num_iters, None);
340
341 cv.wait_while(&mut mutex_guard, condition);
342
343 assert!(*mutex_guard == num_iters + 1);
344
345 cv.wait_while(&mut mutex_guard, condition);
346 handle.join().unwrap();
347
348 assert!(*mutex_guard == num_iters + 2);
349 }
350
351 #[test]
352 #[should_panic]
353 fn two_mutexes() {
354 let m = Arc::new(Mutex::new(()));
355 let m2 = m.clone();
356 let m3 = Arc::new(Mutex::new(()));
357 let c = Arc::new(Condvar::new());
358 let c2 = c.clone();
359
360 struct PanicGuard<'a>(&'a Condvar);
362 impl<'a> Drop for PanicGuard<'a> {
363 fn drop(&mut self) {
364 self.0.notify_one();
365 }
366 }
367
368 let (tx, rx) = channel();
369 let g = m.lock();
370 let _t = thread::spawn(move || {
371 let mut g = m2.lock();
372 tx.send(()).unwrap();
373 c2.wait(&mut g);
374 });
375 drop(g);
376 rx.recv().unwrap();
377 let _g = m.lock();
378 let _guard = PanicGuard(&c);
379 c.wait(&mut m3.lock());
380 }
381
382 #[test]
383 fn two_mutexes_disjoint() {
384 let m = Arc::new(Mutex::new(()));
385 let m2 = m.clone();
386 let m3 = Arc::new(Mutex::new(()));
387 let c = Arc::new(Condvar::new());
388 let c2 = c.clone();
389
390 let mut g = m.lock();
391 let _t = thread::spawn(move || {
392 let _g = m2.lock();
393 c2.notify_one();
394 });
395 c.wait(&mut g);
396 drop(g);
397
398 let _ = c.wait_for(&mut m3.lock(), Duration::from_millis(1));
399 }
400
401 #[test]
402 fn test_debug_condvar() {
403 let c = Condvar::new();
404 assert_eq!(format!("{:?}", c), "Condvar { .. }");
405 }
406
407 #[test]
408 fn test_condvar_requeue() {
409 let m = Arc::new(Mutex::new(()));
410 let m2 = m.clone();
411 let c = Arc::new(Condvar::new());
412 let c2 = c.clone();
413 let t = thread::spawn(move || {
414 let mut g = m2.lock();
415 c2.wait(&mut g);
416 });
417
418 let mut g = m.lock();
419 while !c.notify_one() {
420 MutexGuard::bump(&mut g);
422 thread::yield_now();
424 }
425 drop(g);
427 t.join().unwrap();
428 }
429
430 #[test]
431 fn test_issue_129() {
432 let locks = Arc::new((Mutex::new(0), Condvar::new()));
433
434 let (tx, rx) = channel();
435 for _ in 0..4 {
436 let locks = locks.clone();
437 let tx = tx.clone();
438 thread::spawn(move || {
439 let mut guard = locks.0.lock();
440 *guard += 1;
441 locks.1.wait(&mut guard);
442 locks.1.wait_for(&mut guard, Duration::from_millis(1));
443 locks.1.notify_one();
444 tx.send(()).unwrap();
445 });
446 }
447
448 while *locks.0.lock() != 4 {
449 thread::sleep(Duration::from_millis(100));
450 }
451 locks.1.notify_one();
452
453 for _ in 0..4 {
454 assert_eq!(rx.recv_timeout(Duration::from_millis(500)), Ok(()));
455 }
456 }
457}
458
459#[cfg(test)]
462#[cfg(not(miri))] mod webkit_queue_test {
464 use crate::{Condvar, Mutex, MutexGuard};
465 use std::{collections::VecDeque, sync::Arc, thread, time::Duration};
466
467 #[derive(Clone, Copy)]
468 enum Timeout {
469 Bounded(Duration),
470 Forever,
471 }
472
473 #[derive(Clone, Copy)]
474 enum NotifyStyle {
475 One,
476 All,
477 }
478
479 struct Queue {
480 items: VecDeque<usize>,
481 should_continue: bool,
482 }
483
484 impl Queue {
485 fn new() -> Self {
486 Self {
487 items: VecDeque::new(),
488 should_continue: true,
489 }
490 }
491 }
492
493 fn wait<T: ?Sized>(
494 condition: &Condvar,
495 lock: &mut MutexGuard<'_, T>,
496 predicate: impl Fn(&mut MutexGuard<'_, T>) -> bool,
497 timeout: &Timeout,
498 ) {
499 while !predicate(lock) {
500 match timeout {
501 Timeout::Forever => condition.wait(lock),
502 Timeout::Bounded(bound) => {
503 condition.wait_for(lock, *bound);
504 }
505 }
506 }
507 }
508
509 fn notify(style: NotifyStyle, condition: &Condvar, should_notify: bool) {
510 match style {
511 NotifyStyle::One => {
512 condition.notify_one();
513 }
514 NotifyStyle::All => {
515 if should_notify {
516 condition.notify_all();
517 }
518 }
519 }
520 }
521
522 fn run_queue_test(
523 num_producers: usize,
524 num_consumers: usize,
525 max_queue_size: usize,
526 messages_per_producer: usize,
527 notify_style: NotifyStyle,
528 timeout: Timeout,
529 delay: Duration,
530 ) {
531 let input_queue = Arc::new(Mutex::new(Queue::new()));
532 let empty_condition = Arc::new(Condvar::new());
533 let full_condition = Arc::new(Condvar::new());
534
535 let output_vec = Arc::new(Mutex::new(vec![]));
536
537 let consumers = (0..num_consumers)
538 .map(|_| {
539 consumer_thread(
540 input_queue.clone(),
541 empty_condition.clone(),
542 full_condition.clone(),
543 timeout,
544 notify_style,
545 output_vec.clone(),
546 max_queue_size,
547 )
548 })
549 .collect::<Vec<_>>();
550 let producers = (0..num_producers)
551 .map(|_| {
552 producer_thread(
553 messages_per_producer,
554 input_queue.clone(),
555 empty_condition.clone(),
556 full_condition.clone(),
557 timeout,
558 notify_style,
559 max_queue_size,
560 )
561 })
562 .collect::<Vec<_>>();
563
564 thread::sleep(delay);
565
566 for producer in producers.into_iter() {
567 producer.join().expect("Producer thread panicked");
568 }
569
570 {
571 let mut input_queue = input_queue.lock();
572 input_queue.should_continue = false;
573 }
574 empty_condition.notify_all();
575
576 for consumer in consumers.into_iter() {
577 consumer.join().expect("Consumer thread panicked");
578 }
579
580 let mut output_vec = output_vec.lock();
581 assert_eq!(output_vec.len(), num_producers * messages_per_producer);
582 output_vec.sort();
583 for msg_idx in 0..messages_per_producer {
584 for producer_idx in 0..num_producers {
585 assert_eq!(msg_idx, output_vec[msg_idx * num_producers + producer_idx]);
586 }
587 }
588 }
589
590 fn consumer_thread(
591 input_queue: Arc<Mutex<Queue>>,
592 empty_condition: Arc<Condvar>,
593 full_condition: Arc<Condvar>,
594 timeout: Timeout,
595 notify_style: NotifyStyle,
596 output_queue: Arc<Mutex<Vec<usize>>>,
597 max_queue_size: usize,
598 ) -> thread::JoinHandle<()> {
599 thread::spawn(move || loop {
600 let (should_notify, result) = {
601 let mut queue = input_queue.lock();
602 wait(
603 &empty_condition,
604 &mut queue,
605 |state| -> bool { !state.items.is_empty() || !state.should_continue },
606 &timeout,
607 );
608 if queue.items.is_empty() && !queue.should_continue {
609 return;
610 }
611 let should_notify = queue.items.len() == max_queue_size;
612 let result = queue.items.pop_front();
613 std::mem::drop(queue);
614 (should_notify, result)
615 };
616 notify(notify_style, &full_condition, should_notify);
617
618 if let Some(result) = result {
619 output_queue.lock().push(result);
620 }
621 })
622 }
623
624 fn producer_thread(
625 num_messages: usize,
626 queue: Arc<Mutex<Queue>>,
627 empty_condition: Arc<Condvar>,
628 full_condition: Arc<Condvar>,
629 timeout: Timeout,
630 notify_style: NotifyStyle,
631 max_queue_size: usize,
632 ) -> thread::JoinHandle<()> {
633 thread::spawn(move || {
634 for message in 0..num_messages {
635 let should_notify = {
636 let mut queue = queue.lock();
637 wait(
638 &full_condition,
639 &mut queue,
640 |state| state.items.len() < max_queue_size,
641 &timeout,
642 );
643 let should_notify = queue.items.is_empty();
644 queue.items.push_back(message);
645 std::mem::drop(queue);
646 should_notify
647 };
648 notify(notify_style, &empty_condition, should_notify);
649 }
650 })
651 }
652
653 macro_rules! run_queue_tests {
654 ( $( $name:ident(
655 num_producers: $num_producers:expr,
656 num_consumers: $num_consumers:expr,
657 max_queue_size: $max_queue_size:expr,
658 messages_per_producer: $messages_per_producer:expr,
659 notification_style: $notification_style:expr,
660 timeout: $timeout:expr,
661 delay_seconds: $delay_seconds:expr);
662 )* ) => {
663 $(#[test]
664 fn $name() {
665 let delay = Duration::from_secs($delay_seconds);
666 run_queue_test(
667 $num_producers,
668 $num_consumers,
669 $max_queue_size,
670 $messages_per_producer,
671 $notification_style,
672 $timeout,
673 delay,
674 );
675 })*
676 };
677 }
678
679 run_queue_tests! {
680 sanity_check_queue(
681 num_producers: 1,
682 num_consumers: 1,
683 max_queue_size: 1,
684 messages_per_producer: 100_000,
685 notification_style: NotifyStyle::All,
686 timeout: Timeout::Bounded(Duration::from_secs(1)),
687 delay_seconds: 0
688 );
689 sanity_check_queue_timeout(
690 num_producers: 1,
691 num_consumers: 1,
692 max_queue_size: 1,
693 messages_per_producer: 100_000,
694 notification_style: NotifyStyle::All,
695 timeout: Timeout::Forever,
696 delay_seconds: 0
697 );
698 new_test_without_timeout_5(
699 num_producers: 1,
700 num_consumers: 5,
701 max_queue_size: 1,
702 messages_per_producer: 100_000,
703 notification_style: NotifyStyle::All,
704 timeout: Timeout::Forever,
705 delay_seconds: 0
706 );
707 one_producer_one_consumer_one_slot(
708 num_producers: 1,
709 num_consumers: 1,
710 max_queue_size: 1,
711 messages_per_producer: 100_000,
712 notification_style: NotifyStyle::All,
713 timeout: Timeout::Forever,
714 delay_seconds: 0
715 );
716 one_producer_one_consumer_one_slot_timeout(
717 num_producers: 1,
718 num_consumers: 1,
719 max_queue_size: 1,
720 messages_per_producer: 100_000,
721 notification_style: NotifyStyle::All,
722 timeout: Timeout::Forever,
723 delay_seconds: 1
724 );
725 one_producer_one_consumer_hundred_slots(
726 num_producers: 1,
727 num_consumers: 1,
728 max_queue_size: 100,
729 messages_per_producer: 1_000_000,
730 notification_style: NotifyStyle::All,
731 timeout: Timeout::Forever,
732 delay_seconds: 0
733 );
734 ten_producers_one_consumer_one_slot(
735 num_producers: 10,
736 num_consumers: 1,
737 max_queue_size: 1,
738 messages_per_producer: 10000,
739 notification_style: NotifyStyle::All,
740 timeout: Timeout::Forever,
741 delay_seconds: 0
742 );
743 ten_producers_one_consumer_hundred_slots_notify_all(
744 num_producers: 10,
745 num_consumers: 1,
746 max_queue_size: 100,
747 messages_per_producer: 10000,
748 notification_style: NotifyStyle::All,
749 timeout: Timeout::Forever,
750 delay_seconds: 0
751 );
752 ten_producers_one_consumer_hundred_slots_notify_one(
753 num_producers: 10,
754 num_consumers: 1,
755 max_queue_size: 100,
756 messages_per_producer: 10000,
757 notification_style: NotifyStyle::One,
758 timeout: Timeout::Forever,
759 delay_seconds: 0
760 );
761 one_producer_ten_consumers_one_slot(
762 num_producers: 1,
763 num_consumers: 10,
764 max_queue_size: 1,
765 messages_per_producer: 10000,
766 notification_style: NotifyStyle::All,
767 timeout: Timeout::Forever,
768 delay_seconds: 0
769 );
770 one_producer_ten_consumers_hundred_slots_notify_all(
771 num_producers: 1,
772 num_consumers: 10,
773 max_queue_size: 100,
774 messages_per_producer: 100_000,
775 notification_style: NotifyStyle::All,
776 timeout: Timeout::Forever,
777 delay_seconds: 0
778 );
779 one_producer_ten_consumers_hundred_slots_notify_one(
780 num_producers: 1,
781 num_consumers: 10,
782 max_queue_size: 100,
783 messages_per_producer: 100_000,
784 notification_style: NotifyStyle::One,
785 timeout: Timeout::Forever,
786 delay_seconds: 0
787 );
788 ten_producers_ten_consumers_one_slot(
789 num_producers: 10,
790 num_consumers: 10,
791 max_queue_size: 1,
792 messages_per_producer: 50000,
793 notification_style: NotifyStyle::All,
794 timeout: Timeout::Forever,
795 delay_seconds: 0
796 );
797 ten_producers_ten_consumers_hundred_slots_notify_all(
798 num_producers: 10,
799 num_consumers: 10,
800 max_queue_size: 100,
801 messages_per_producer: 50000,
802 notification_style: NotifyStyle::All,
803 timeout: Timeout::Forever,
804 delay_seconds: 0
805 );
806 ten_producers_ten_consumers_hundred_slots_notify_one(
807 num_producers: 10,
808 num_consumers: 10,
809 max_queue_size: 100,
810 messages_per_producer: 50000,
811 notification_style: NotifyStyle::One,
812 timeout: Timeout::Forever,
813 delay_seconds: 0
814 );
815 }
816}