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