]>
Commit | Line | Data |
---|---|---|
1b1a35ee XL |
1 | use super::Once; |
2 | use crate::panic; | |
3 | use crate::sync::mpsc::channel; | |
4 | use crate::thread; | |
5 | ||
6 | #[test] | |
7 | fn smoke_once() { | |
8 | static O: Once = Once::new(); | |
9 | let mut a = 0; | |
10 | O.call_once(|| a += 1); | |
11 | assert_eq!(a, 1); | |
12 | O.call_once(|| a += 1); | |
13 | assert_eq!(a, 1); | |
14 | } | |
15 | ||
16 | #[test] | |
17 | fn stampede_once() { | |
18 | static O: Once = Once::new(); | |
19 | static mut RUN: bool = false; | |
20 | ||
21 | let (tx, rx) = channel(); | |
22 | for _ in 0..10 { | |
23 | let tx = tx.clone(); | |
24 | thread::spawn(move || { | |
25 | for _ in 0..4 { | |
26 | thread::yield_now() | |
27 | } | |
28 | unsafe { | |
29 | O.call_once(|| { | |
30 | assert!(!RUN); | |
31 | RUN = true; | |
32 | }); | |
33 | assert!(RUN); | |
34 | } | |
35 | tx.send(()).unwrap(); | |
36 | }); | |
37 | } | |
38 | ||
39 | unsafe { | |
40 | O.call_once(|| { | |
41 | assert!(!RUN); | |
42 | RUN = true; | |
43 | }); | |
44 | assert!(RUN); | |
45 | } | |
46 | ||
47 | for _ in 0..10 { | |
48 | rx.recv().unwrap(); | |
49 | } | |
50 | } | |
51 | ||
52 | #[test] | |
53 | fn poison_bad() { | |
54 | static O: Once = Once::new(); | |
55 | ||
56 | // poison the once | |
57 | let t = panic::catch_unwind(|| { | |
58 | O.call_once(|| panic!()); | |
59 | }); | |
60 | assert!(t.is_err()); | |
61 | ||
62 | // poisoning propagates | |
63 | let t = panic::catch_unwind(|| { | |
64 | O.call_once(|| {}); | |
65 | }); | |
66 | assert!(t.is_err()); | |
67 | ||
68 | // we can subvert poisoning, however | |
69 | let mut called = false; | |
70 | O.call_once_force(|p| { | |
71 | called = true; | |
5869c6ff | 72 | assert!(p.is_poisoned()) |
1b1a35ee XL |
73 | }); |
74 | assert!(called); | |
75 | ||
76 | // once any success happens, we stop propagating the poison | |
77 | O.call_once(|| {}); | |
78 | } | |
79 | ||
80 | #[test] | |
81 | fn wait_for_force_to_finish() { | |
82 | static O: Once = Once::new(); | |
83 | ||
84 | // poison the once | |
85 | let t = panic::catch_unwind(|| { | |
86 | O.call_once(|| panic!()); | |
87 | }); | |
88 | assert!(t.is_err()); | |
89 | ||
90 | // make sure someone's waiting inside the once via a force | |
91 | let (tx1, rx1) = channel(); | |
92 | let (tx2, rx2) = channel(); | |
93 | let t1 = thread::spawn(move || { | |
94 | O.call_once_force(|p| { | |
5869c6ff | 95 | assert!(p.is_poisoned()); |
1b1a35ee XL |
96 | tx1.send(()).unwrap(); |
97 | rx2.recv().unwrap(); | |
98 | }); | |
99 | }); | |
100 | ||
101 | rx1.recv().unwrap(); | |
102 | ||
103 | // put another waiter on the once | |
104 | let t2 = thread::spawn(|| { | |
105 | let mut called = false; | |
106 | O.call_once(|| { | |
107 | called = true; | |
108 | }); | |
109 | assert!(!called); | |
110 | }); | |
111 | ||
112 | tx2.send(()).unwrap(); | |
113 | ||
114 | assert!(t1.join().is_ok()); | |
115 | assert!(t2.join().is_ok()); | |
116 | } |