Skip to content

Commit e59ecbb

Browse files
committed
fix shared behavior and add tests
1 parent 9135232 commit e59ecbb

File tree

3 files changed

+286
-3
lines changed

3 files changed

+286
-3
lines changed

src/shims/windows/sync.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const INIT_ONCE_ID_OFFSET: u64 = 0;
1212
const CONDVAR_ID_OFFSET: u64 = 0;
1313

1414
impl<'mir, 'tcx> EvalContextExtPriv<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
15-
pub trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
15+
trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
1616
/// Try to reacquire the lock associated with the condition variable after we
1717
/// were signaled.
1818
fn reacquire_cond_lock(
@@ -25,13 +25,13 @@ pub trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tc
2525
this.unblock_thread(thread);
2626

2727
if shared {
28-
if this.rwlock_is_locked(lock) {
28+
if this.rwlock_is_write_locked(lock) {
2929
this.rwlock_enqueue_and_block_reader(lock, thread);
3030
} else {
3131
this.rwlock_reader_lock(lock, thread);
3232
}
3333
} else {
34-
if this.rwlock_is_write_locked(lock) {
34+
if this.rwlock_is_locked(lock) {
3535
this.rwlock_enqueue_and_block_writer(lock, thread);
3636
} else {
3737
this.rwlock_writer_lock(lock, thread);
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
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 SleepConditionVariableSRW(
16+
condvar: *mut *mut c_void,
17+
lock: *mut *mut c_void,
18+
timeout: u32,
19+
flags: u32,
20+
) -> i32;
21+
fn WakeAllConditionVariable(condvar: *mut *mut c_void);
22+
23+
fn AcquireSRWLockExclusive(lock: *mut *mut c_void);
24+
fn AcquireSRWLockShared(lock: *mut *mut c_void);
25+
fn ReleaseSRWLockExclusive(lock: *mut *mut c_void);
26+
fn ReleaseSRWLockShared(lock: *mut *mut c_void);
27+
}
28+
29+
const CONDITION_VARIABLE_LOCKMODE_SHARED: u32 = 1;
30+
const INFINITE: u32 = u32::MAX;
31+
32+
/// threads should be able to reacquire the lock while it is locked by multiple other threads in shared mode
33+
fn all_shared() {
34+
println!("all_shared");
35+
36+
let mut lock = null_mut();
37+
let mut condvar = null_mut();
38+
39+
let lock_ptr = SendPtr(&mut lock);
40+
let condvar_ptr = SendPtr(&mut condvar);
41+
42+
let mut handles = Vec::with_capacity(10);
43+
44+
// waiters
45+
for _ in 0..5 {
46+
handles.push(thread::spawn(move || {
47+
unsafe {
48+
AcquireSRWLockShared(lock_ptr.0);
49+
}
50+
println!("waiter locked");
51+
52+
let r = unsafe {
53+
SleepConditionVariableSRW(
54+
condvar_ptr.0,
55+
lock_ptr.0,
56+
INFINITE,
57+
CONDITION_VARIABLE_LOCKMODE_SHARED,
58+
)
59+
};
60+
assert_ne!(r, 0);
61+
62+
println!("reacquired lock");
63+
}));
64+
}
65+
66+
// ensures each waiter is waiting by this point
67+
thread::yield_now();
68+
69+
// readers
70+
for _ in 0..5 {
71+
handles.push(thread::spawn(move || {
72+
unsafe {
73+
AcquireSRWLockShared(lock_ptr.0);
74+
}
75+
println!("reader locked");
76+
77+
// switch to next reader or main thread
78+
thread::yield_now();
79+
80+
unsafe {
81+
ReleaseSRWLockShared(lock_ptr.0);
82+
}
83+
println!("reader unlocked");
84+
}));
85+
}
86+
87+
// ensures each reader has acquired the lock
88+
thread::yield_now();
89+
90+
unsafe {
91+
WakeAllConditionVariable(condvar_ptr.0);
92+
}
93+
94+
for handle in handles {
95+
handle.join().unwrap();
96+
}
97+
}
98+
99+
// reacquiring a lock should wait until the lock is not exclusively locked
100+
fn shared_sleep_and_exclusive_lock() {
101+
println!("shared_sleep_and_exclusive_lock");
102+
103+
let mut lock = null_mut();
104+
let mut condvar = null_mut();
105+
106+
let lock_ptr = SendPtr(&mut lock);
107+
let condvar_ptr = SendPtr(&mut condvar);
108+
109+
let mut waiters = Vec::with_capacity(5);
110+
for _ in 0..5 {
111+
waiters.push(thread::spawn(move || {
112+
unsafe {
113+
AcquireSRWLockShared(lock_ptr.0);
114+
}
115+
println!("waiter locked");
116+
117+
let r = unsafe {
118+
SleepConditionVariableSRW(
119+
condvar_ptr.0,
120+
lock_ptr.0,
121+
INFINITE,
122+
CONDITION_VARIABLE_LOCKMODE_SHARED,
123+
)
124+
};
125+
assert_ne!(r, 0);
126+
127+
println!("reacquired lock");
128+
}));
129+
}
130+
131+
// ensures each waiter is waiting by this point
132+
thread::yield_now();
133+
134+
unsafe {
135+
AcquireSRWLockExclusive(lock_ptr.0);
136+
}
137+
println!("main locked");
138+
139+
unsafe {
140+
WakeAllConditionVariable(condvar_ptr.0);
141+
}
142+
143+
// waiters are now waiting for the lock to be unlocked
144+
thread::yield_now();
145+
146+
unsafe {
147+
ReleaseSRWLockExclusive(lock_ptr.0);
148+
}
149+
println!("main unlocked");
150+
151+
for handle in waiters {
152+
handle.join().unwrap();
153+
}
154+
}
155+
156+
// threads reacquiring locks should wait for all locks to be released first
157+
fn exclusive_sleep_and_shared_lock() {
158+
println!("exclusive_sleep_and_shared_lock");
159+
160+
let mut lock = null_mut();
161+
let mut condvar = null_mut();
162+
163+
let lock_ptr = SendPtr(&mut lock);
164+
let condvar_ptr = SendPtr(&mut condvar);
165+
166+
let mut handles = Vec::with_capacity(10);
167+
for _ in 0..5 {
168+
handles.push(thread::spawn(move || {
169+
unsafe {
170+
AcquireSRWLockExclusive(lock_ptr.0);
171+
}
172+
173+
println!("waiter locked");
174+
175+
let r = unsafe { SleepConditionVariableSRW(condvar_ptr.0, lock_ptr.0, INFINITE, 0) };
176+
assert_ne!(r, 0);
177+
178+
println!("reacquired lock");
179+
180+
// switch to next waiter or main thread
181+
thread::yield_now();
182+
183+
unsafe {
184+
ReleaseSRWLockExclusive(lock_ptr.0);
185+
}
186+
println!("waiter unlocked");
187+
}));
188+
}
189+
190+
for _ in 0..5 {
191+
handles.push(thread::spawn(move || {
192+
unsafe {
193+
AcquireSRWLockShared(lock_ptr.0);
194+
}
195+
println!("reader locked");
196+
197+
// switch to next reader or main thread
198+
thread::yield_now();
199+
200+
unsafe {
201+
ReleaseSRWLockShared(lock_ptr.0);
202+
}
203+
println!("reader unlocked");
204+
}));
205+
}
206+
207+
// ensures each reader has acquired the lock
208+
thread::yield_now();
209+
210+
unsafe {
211+
WakeAllConditionVariable(condvar_ptr.0);
212+
}
213+
214+
for handle in handles {
215+
handle.join().unwrap();
216+
}
217+
}
218+
219+
fn main() {
220+
all_shared();
221+
shared_sleep_and_exclusive_lock();
222+
exclusive_sleep_and_shared_lock();
223+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
all_shared
2+
waiter locked
3+
waiter locked
4+
waiter locked
5+
waiter locked
6+
waiter locked
7+
reader locked
8+
reader locked
9+
reader locked
10+
reader locked
11+
reader locked
12+
reacquired lock
13+
reacquired lock
14+
reacquired lock
15+
reacquired lock
16+
reacquired lock
17+
reader unlocked
18+
reader unlocked
19+
reader unlocked
20+
reader unlocked
21+
reader unlocked
22+
shared_sleep_and_exclusive_lock
23+
waiter locked
24+
waiter locked
25+
waiter locked
26+
waiter locked
27+
waiter locked
28+
main locked
29+
main unlocked
30+
reacquired lock
31+
reacquired lock
32+
reacquired lock
33+
reacquired lock
34+
reacquired lock
35+
exclusive_sleep_and_shared_lock
36+
waiter locked
37+
waiter locked
38+
waiter locked
39+
waiter locked
40+
waiter locked
41+
reader locked
42+
reader locked
43+
reader locked
44+
reader locked
45+
reader locked
46+
reader unlocked
47+
reader unlocked
48+
reader unlocked
49+
reader unlocked
50+
reader unlocked
51+
reacquired lock
52+
waiter unlocked
53+
reacquired lock
54+
waiter unlocked
55+
reacquired lock
56+
waiter unlocked
57+
reacquired lock
58+
waiter unlocked
59+
reacquired lock
60+
waiter unlocked

0 commit comments

Comments
 (0)