]> git.proxmox.com Git - rustc.git/blame - library/std/src/sync/once/tests.rs
New upstream version 1.51.0+dfsg1
[rustc.git] / library / std / src / sync / once / tests.rs
CommitLineData
1b1a35ee
XL
1use super::Once;
2use crate::panic;
3use crate::sync::mpsc::channel;
4use crate::thread;
5
6#[test]
7fn 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]
17fn 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]
53fn 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]
81fn 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}