Skip to content

Commit 342251c

Browse files
beepster4096RalfJung
authored andcommitted
add test for init once
1 parent 3244c11 commit 342251c

File tree

2 files changed

+144
-0
lines changed

2 files changed

+144
-0
lines changed
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
//@only-target-windows: Uses win32 api functions
2+
// We are making scheduler assumptions here.
3+
//@compile-flags: -Zmiri-preemption-rate=0
4+
5+
use std::ffi::c_void;
6+
use std::ptr::null_mut;
7+
use std::thread;
8+
9+
#[derive(Copy, Clone)]
10+
struct SendPtr<T>(*mut T);
11+
12+
unsafe impl<T> Send for SendPtr<T> {}
13+
14+
extern "system" {
15+
fn InitOnceBeginInitialize(
16+
init: *mut *mut c_void,
17+
flags: u32,
18+
pending: *mut i32,
19+
context: *mut c_void,
20+
) -> i32;
21+
22+
fn InitOnceComplete(init: *mut *mut c_void, flags: u32, context: *mut c_void) -> i32;
23+
}
24+
25+
const TRUE: i32 = 1;
26+
const FALSE: i32 = 0;
27+
28+
const INIT_ONCE_INIT_FAILED: u32 = 4;
29+
30+
fn single_thread() {
31+
let mut init_once = null_mut();
32+
let mut pending = 0;
33+
34+
unsafe {
35+
assert_eq!(InitOnceBeginInitialize(&mut init_once, 0, &mut pending, null_mut()), TRUE);
36+
assert_eq!(pending, TRUE);
37+
38+
assert_eq!(InitOnceComplete(&mut init_once, 0, null_mut()), TRUE);
39+
40+
assert_eq!(InitOnceBeginInitialize(&mut init_once, 0, &mut pending, null_mut()), TRUE);
41+
assert_eq!(pending, FALSE);
42+
}
43+
44+
let mut init_once = null_mut();
45+
46+
unsafe {
47+
assert_eq!(InitOnceBeginInitialize(&mut init_once, 0, &mut pending, null_mut()), TRUE);
48+
assert_eq!(pending, TRUE);
49+
50+
assert_eq!(InitOnceComplete(&mut init_once, INIT_ONCE_INIT_FAILED, null_mut()), TRUE);
51+
52+
assert_eq!(InitOnceBeginInitialize(&mut init_once, 0, &mut pending, null_mut()), TRUE);
53+
assert_eq!(pending, TRUE);
54+
}
55+
}
56+
57+
fn block_until_complete() {
58+
let mut init_once = null_mut();
59+
let mut pending = 0;
60+
61+
unsafe {
62+
assert_eq!(InitOnceBeginInitialize(&mut init_once, 0, &mut pending, null_mut()), TRUE);
63+
assert_eq!(pending, TRUE);
64+
}
65+
66+
let init_once_ptr = SendPtr(&mut init_once);
67+
68+
let waiter = move || unsafe {
69+
let mut pending = 0;
70+
71+
assert_eq!(InitOnceBeginInitialize(init_once_ptr.0, 0, &mut pending, null_mut()), TRUE);
72+
assert_eq!(pending, FALSE);
73+
74+
println!("finished waiting for initialization");
75+
};
76+
77+
let waiter1 = thread::spawn(waiter);
78+
let waiter2 = thread::spawn(waiter);
79+
80+
// this yield ensures `waiter1` & `waiter2` are blocked on the main thread
81+
thread::yield_now();
82+
83+
println!("completing initialization");
84+
85+
unsafe {
86+
assert_eq!(InitOnceComplete(init_once_ptr.0, 0, null_mut()), TRUE);
87+
}
88+
89+
waiter1.join().unwrap();
90+
waiter2.join().unwrap();
91+
}
92+
93+
fn retry_on_fail() {
94+
let mut init_once = null_mut();
95+
let mut pending = 0;
96+
97+
unsafe {
98+
assert_eq!(InitOnceBeginInitialize(&mut init_once, 0, &mut pending, null_mut()), TRUE);
99+
assert_eq!(pending, TRUE);
100+
}
101+
102+
let init_once_ptr = SendPtr(&mut init_once);
103+
104+
let waiter = move || unsafe {
105+
let mut pending = 0;
106+
107+
assert_eq!(InitOnceBeginInitialize(init_once_ptr.0, 0, &mut pending, null_mut()), TRUE);
108+
109+
if pending == 1 {
110+
println!("retrying initialization");
111+
112+
assert_eq!(InitOnceComplete(init_once_ptr.0, 0, null_mut()), TRUE);
113+
} else {
114+
println!("finished waiting for initialization");
115+
}
116+
};
117+
118+
let waiter1 = thread::spawn(waiter);
119+
let waiter2 = thread::spawn(waiter);
120+
121+
// this yield ensures `waiter1` & `waiter2` are blocked on the main thread
122+
thread::yield_now();
123+
124+
println!("failing initialization");
125+
126+
unsafe {
127+
assert_eq!(InitOnceComplete(init_once_ptr.0, INIT_ONCE_INIT_FAILED, null_mut()), TRUE);
128+
}
129+
130+
waiter1.join().unwrap();
131+
waiter2.join().unwrap();
132+
}
133+
134+
fn main() {
135+
single_thread();
136+
block_until_complete();
137+
retry_on_fail();
138+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
completing initialization
2+
finished waiting for initialization
3+
finished waiting for initialization
4+
failing initialization
5+
retrying initialization
6+
finished waiting for initialization

0 commit comments

Comments
 (0)