Skip to content

Commit 958ca31

Browse files
committedNov 5, 2022
fix shared behavior and add tests
1 parent f8ff88f commit 958ca31

File tree

3 files changed

+290
-3
lines changed

3 files changed

+290
-3
lines changed
 

‎src/shims/windows/sync.rs

+3-3
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(
@@ -26,13 +26,13 @@ pub trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tc
2626

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

0 commit comments

Comments
 (0)
Please sign in to comment.