Skip to content

Commit 86eb262

Browse files
Vytautas Astrauskasvakaras
authored andcommitted
Cleanup Condvar tests.
1 parent 4a303b1 commit 86eb262

File tree

4 files changed

+102
-178
lines changed

4 files changed

+102
-178
lines changed

src/shims/sync.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::time::{Duration, SystemTime};
2+
use std::convert::TryInto;
23

34
use rustc_middle::ty::{layout::TyAndLayout, TyKind, TypeAndMut};
45
use rustc_target::abi::{LayoutOf, Size};
@@ -719,12 +720,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
719720
let mut offset = Size::from_bytes(0);
720721
let layout = this.libc_ty_layout("time_t")?;
721722
let seconds_place = tp.offset(offset, MemPlaceMeta::None, layout, this)?;
722-
let seconds = this.read_scalar(seconds_place.into())?.to_u64()?;
723+
let seconds = this.read_scalar(seconds_place.into())?;
723724
offset += layout.size;
724725
let layout = this.libc_ty_layout("c_long")?;
725726
let nanoseconds_place = tp.offset(offset, MemPlaceMeta::None, layout, this)?;
726-
let nanoseconds = this.read_scalar(nanoseconds_place.into())?.to_u64()?;
727-
Duration::new(seconds, nanoseconds as u32)
727+
let nanoseconds = this.read_scalar(nanoseconds_place.into())?;
728+
let (seconds, nanoseconds) = if this.pointer_size().bytes() == 8 {
729+
(seconds.to_u64()?, nanoseconds.to_u64()?.try_into().unwrap())
730+
} else {
731+
(seconds.to_u32()?.into(), nanoseconds.to_u32()?)
732+
};
733+
Duration::new(seconds, nanoseconds)
728734
};
729735

730736
let timeout_time = if clock_id == this.eval_libc_i32("CLOCK_REALTIME")? {
Lines changed: 44 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -1,199 +1,75 @@
11
// ignore-windows: No libc on Windows
2+
// ignore-macos: pthread_condattr_setclock is not supported on MacOS.
23
// compile-flags: -Zmiri-disable-isolation
34

45
#![feature(rustc_private)]
56

7+
/// Test that conditional variable timeouts are working properly with both
8+
/// monotonic and system clocks.
69
extern crate libc;
710

8-
use std::cell::UnsafeCell;
9-
use std::mem::{self, MaybeUninit};
10-
use std::sync::Arc;
11-
use std::thread;
11+
use std::mem;
12+
use std::time::Instant;
1213

13-
struct Mutex {
14-
inner: UnsafeCell<libc::pthread_mutex_t>,
15-
}
16-
17-
unsafe impl Sync for Mutex {}
18-
19-
impl std::fmt::Debug for Mutex {
20-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21-
write!(f, "Mutex")
22-
}
23-
}
24-
25-
struct Cond {
26-
inner: UnsafeCell<libc::pthread_cond_t>,
27-
}
28-
29-
unsafe impl Sync for Cond {}
30-
31-
impl std::fmt::Debug for Cond {
32-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33-
write!(f, "Cond")
34-
}
35-
}
36-
37-
unsafe fn create_cond_attr_monotonic() -> libc::pthread_condattr_t {
38-
let mut attr = MaybeUninit::<libc::pthread_condattr_t>::uninit();
39-
assert_eq!(libc::pthread_condattr_init(attr.as_mut_ptr()), 0);
40-
assert_eq!(libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC), 0);
41-
attr.assume_init()
42-
}
43-
44-
unsafe fn create_cond(attr: Option<libc::pthread_condattr_t>) -> Cond {
45-
let cond: Cond = mem::zeroed();
46-
if let Some(mut attr) = attr {
47-
assert_eq!(libc::pthread_cond_init(cond.inner.get() as *mut _, &attr as *const _), 0);
48-
assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0);
49-
} else {
50-
assert_eq!(libc::pthread_cond_init(cond.inner.get() as *mut _, 0 as *const _), 0);
51-
}
52-
cond
53-
}
54-
55-
unsafe fn create_mutex() -> Mutex {
56-
mem::zeroed()
57-
}
58-
59-
unsafe fn create_timeout(seconds: i64) -> libc::timespec {
60-
let mut now: libc::timespec = mem::zeroed();
61-
assert_eq!(libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now), 0);
62-
libc::timespec { tv_sec: now.tv_sec + seconds, tv_nsec: now.tv_nsec }
63-
}
64-
65-
fn test_pthread_condattr_t() {
14+
fn test_timed_wait_timeout_monotonic() {
6615
unsafe {
67-
let mut attr = create_cond_attr_monotonic();
68-
let mut clock_id = MaybeUninit::<libc::clockid_t>::uninit();
69-
assert_eq!(libc::pthread_condattr_getclock(&attr as *const _, clock_id.as_mut_ptr()), 0);
70-
assert_eq!(clock_id.assume_init(), libc::CLOCK_MONOTONIC);
71-
assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0);
72-
}
73-
}
16+
let mut attr: libc::pthread_condattr_t = mem::zeroed();
17+
assert_eq!(libc::pthread_condattr_init(&mut attr as *mut _), 0);
18+
assert_eq!(libc::pthread_condattr_setclock(&mut attr as *mut _, libc::CLOCK_MONOTONIC), 0);
7419

75-
fn test_signal() {
76-
unsafe {
77-
let cond = Arc::new(create_cond(None));
78-
let mutex = Arc::new(create_mutex());
20+
let mut cond: libc::pthread_cond_t = mem::zeroed();
21+
assert_eq!(libc::pthread_cond_init(&mut cond as *mut _, &attr as *const _), 0);
22+
assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0);
7923

80-
assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0);
24+
let mut mutex: libc::pthread_mutex_t = mem::zeroed();
8125

82-
let spawn_mutex = Arc::clone(&mutex);
83-
let spawn_cond = Arc::clone(&cond);
84-
let handle = thread::spawn(move || {
85-
assert_eq!(libc::pthread_mutex_lock(spawn_mutex.inner.get() as *mut _), 0);
86-
assert_eq!(libc::pthread_cond_signal(spawn_cond.inner.get() as *mut _), 0);
87-
assert_eq!(libc::pthread_mutex_unlock(spawn_mutex.inner.get() as *mut _), 0);
88-
});
26+
let mut now: libc::timespec = mem::zeroed();
27+
assert_eq!(libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now), 0);
28+
let timeout = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: now.tv_nsec };
8929

30+
assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
31+
let current_time = Instant::now();
9032
assert_eq!(
91-
libc::pthread_cond_wait(cond.inner.get() as *mut _, mutex.inner.get() as *mut _),
92-
0
33+
libc::pthread_cond_timedwait(&mut cond as *mut _, &mut mutex as *mut _, &timeout),
34+
libc::ETIMEDOUT
9335
);
94-
assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0);
95-
96-
handle.join().unwrap();
97-
98-
let mutex = Arc::try_unwrap(mutex).unwrap();
99-
assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0);
100-
let cond = Arc::try_unwrap(cond).unwrap();
101-
assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0);
36+
assert!(current_time.elapsed().as_millis() >= 900);
37+
assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
38+
assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0);
39+
assert_eq!(libc::pthread_cond_destroy(&mut cond as *mut _), 0);
10240
}
10341
}
10442

105-
fn test_broadcast() {
43+
fn test_timed_wait_timeout_realtime() {
10644
unsafe {
107-
let cond = Arc::new(create_cond(None));
108-
let mutex = Arc::new(create_mutex());
109-
110-
assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0);
111-
112-
let spawn_mutex = Arc::clone(&mutex);
113-
let spawn_cond = Arc::clone(&cond);
114-
let handle = thread::spawn(move || {
115-
assert_eq!(libc::pthread_mutex_lock(spawn_mutex.inner.get() as *mut _), 0);
116-
assert_eq!(libc::pthread_cond_broadcast(spawn_cond.inner.get() as *mut _), 0);
117-
assert_eq!(libc::pthread_mutex_unlock(spawn_mutex.inner.get() as *mut _), 0);
118-
});
45+
let mut attr: libc::pthread_condattr_t = mem::zeroed();
46+
assert_eq!(libc::pthread_condattr_init(&mut attr as *mut _), 0);
47+
assert_eq!(libc::pthread_condattr_setclock(&mut attr as *mut _, libc::CLOCK_REALTIME), 0);
11948

120-
assert_eq!(
121-
libc::pthread_cond_wait(cond.inner.get() as *mut _, mutex.inner.get() as *mut _),
122-
0
123-
);
124-
assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0);
49+
let mut cond: libc::pthread_cond_t = mem::zeroed();
50+
assert_eq!(libc::pthread_cond_init(&mut cond as *mut _, &attr as *const _), 0);
51+
assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0);
12552

126-
handle.join().unwrap();
53+
let mut mutex: libc::pthread_mutex_t = mem::zeroed();
12754

128-
let mutex = Arc::try_unwrap(mutex).unwrap();
129-
assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0);
130-
let cond = Arc::try_unwrap(cond).unwrap();
131-
assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0);
132-
}
133-
}
55+
let mut now: libc::timespec = mem::zeroed();
56+
assert_eq!(libc::clock_gettime(libc::CLOCK_REALTIME, &mut now), 0);
57+
let timeout = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: now.tv_nsec };
13458

135-
fn test_timed_wait_timeout() {
136-
unsafe {
137-
let attr = create_cond_attr_monotonic();
138-
let cond = create_cond(Some(attr));
139-
let mutex = create_mutex();
140-
let timeout = create_timeout(1);
141-
142-
assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0);
59+
assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
60+
let current_time = Instant::now();
14361
assert_eq!(
144-
libc::pthread_cond_timedwait(
145-
cond.inner.get() as *mut _,
146-
mutex.inner.get() as *mut _,
147-
&timeout
148-
),
62+
libc::pthread_cond_timedwait(&mut cond as *mut _, &mut mutex as *mut _, &timeout),
14963
libc::ETIMEDOUT
15064
);
151-
assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0);
152-
assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0);
153-
assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0);
154-
}
155-
}
156-
157-
fn test_timed_wait_notimeout() {
158-
unsafe {
159-
let attr = create_cond_attr_monotonic();
160-
let cond = Arc::new(create_cond(Some(attr)));
161-
let mutex = Arc::new(create_mutex());
162-
let timeout = create_timeout(100);
163-
164-
assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0);
165-
166-
let spawn_mutex = Arc::clone(&mutex);
167-
let spawn_cond = Arc::clone(&cond);
168-
let handle = thread::spawn(move || {
169-
assert_eq!(libc::pthread_mutex_lock(spawn_mutex.inner.get() as *mut _), 0);
170-
assert_eq!(libc::pthread_cond_signal(spawn_cond.inner.get() as *mut _), 0);
171-
assert_eq!(libc::pthread_mutex_unlock(spawn_mutex.inner.get() as *mut _), 0);
172-
});
173-
174-
assert_eq!(
175-
libc::pthread_cond_timedwait(
176-
cond.inner.get() as *mut _,
177-
mutex.inner.get() as *mut _,
178-
&timeout
179-
),
180-
0
181-
);
182-
assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0);
183-
184-
handle.join().unwrap();
185-
186-
let mutex = Arc::try_unwrap(mutex).unwrap();
187-
assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0);
188-
let cond = Arc::try_unwrap(cond).unwrap();
189-
assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0);
65+
assert!(current_time.elapsed().as_millis() >= 900);
66+
assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
67+
assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0);
68+
assert_eq!(libc::pthread_cond_destroy(&mut cond as *mut _), 0);
19069
}
19170
}
19271

19372
fn main() {
194-
test_pthread_condattr_t();
195-
test_signal();
196-
test_broadcast();
197-
test_timed_wait_timeout();
198-
test_timed_wait_notimeout();
73+
test_timed_wait_timeout_monotonic();
74+
test_timed_wait_timeout_realtime();
19975
}

tests/run-pass/concurrency/libc_pthread_cond.stderr

Lines changed: 0 additions & 2 deletions
This file was deleted.

tests/run-pass/concurrency/sync.rs

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ fn check_barriers() {
3131
// Check if Rust conditional variables are working.
3232

3333
/// The test taken from the Rust documentation.
34-
fn check_conditional_variables() {
34+
fn check_conditional_variables_notify_one() {
3535
let pair = Arc::new((Mutex::new(false), Condvar::new()));
3636
let pair2 = pair.clone();
3737

@@ -52,17 +52,59 @@ fn check_conditional_variables() {
5252
}
5353
}
5454

55+
/// The test taken from the Rust documentation.
56+
fn check_conditional_variables_notify_all() {
57+
let pair = Arc::new((Mutex::new(false), Condvar::new()));
58+
let pair2 = pair.clone();
59+
60+
thread::spawn(move || {
61+
let (lock, cvar) = &*pair2;
62+
let mut started = lock.lock().unwrap();
63+
*started = true;
64+
// We notify the condvar that the value has changed.
65+
cvar.notify_all();
66+
});
67+
68+
// Wait for the thread to start up.
69+
let (lock, cvar) = &*pair;
70+
let mut started = lock.lock().unwrap();
71+
// As long as the value inside the `Mutex<bool>` is `false`, we wait.
72+
while !*started {
73+
started = cvar.wait(started).unwrap();
74+
}
75+
}
76+
5577
/// Test that waiting on a conditional variable with a timeout does not
5678
/// deadlock.
57-
fn check_conditional_variables_timeout() {
79+
fn check_conditional_variables_timed_wait_timeout() {
5880
let lock = Mutex::new(());
5981
let cvar = Condvar::new();
6082
let guard = lock.lock().unwrap();
6183
let now = Instant::now();
62-
let _guard = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap().0;
84+
let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap();
85+
assert!(timeout.timed_out());
6386
assert!(now.elapsed().as_millis() >= 100);
6487
}
6588

89+
/// Test that signaling a conditional variable when waiting with a timeout works
90+
/// as expected.
91+
fn check_conditional_variables_timed_wait_notimeout() {
92+
let pair = Arc::new((Mutex::new(()), Condvar::new()));
93+
let pair2 = pair.clone();
94+
95+
let (lock, cvar) = &*pair;
96+
let guard = lock.lock().unwrap();
97+
98+
let handle = thread::spawn(move || {
99+
let (_lock, cvar) = &*pair2;
100+
cvar.notify_one();
101+
});
102+
103+
let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap();
104+
assert!(!timeout.timed_out());
105+
handle.join().unwrap();
106+
}
107+
66108
// Check if locks are working.
67109

68110
fn check_mutex() {
@@ -218,8 +260,10 @@ fn check_once() {
218260

219261
fn main() {
220262
check_barriers();
221-
check_conditional_variables();
222-
check_conditional_variables_timeout();
263+
check_conditional_variables_notify_one();
264+
check_conditional_variables_notify_all();
265+
check_conditional_variables_timed_wait_timeout();
266+
check_conditional_variables_timed_wait_notimeout();
223267
check_mutex();
224268
check_rwlock_write();
225269
check_rwlock_read_no_deadlock();

0 commit comments

Comments
 (0)