rust/tests/pass/concurrency/libc_pthread_cond.rs

89 lines
3.4 KiB
Rust
Raw Normal View History

// ignore-windows: No libc on Windows
// ignore-apple: pthread_condattr_setclock is not supported on MacOS.
// compile-flags: -Zmiri-disable-isolation
#![feature(rustc_private)]
2020-04-30 17:37:27 -05:00
/// Test that conditional variable timeouts are working properly with both
/// monotonic and system clocks.
extern crate libc;
2021-12-06 15:50:14 -06:00
use std::mem::MaybeUninit;
2020-04-30 17:37:27 -05:00
use std::time::Instant;
2020-05-19 09:47:25 -05:00
fn test_timed_wait_timeout(clock_id: i32) {
unsafe {
2021-12-06 15:50:14 -06:00
let mut attr: MaybeUninit<libc::pthread_condattr_t> = MaybeUninit::uninit();
assert_eq!(libc::pthread_condattr_init(attr.as_mut_ptr()), 0);
assert_eq!(libc::pthread_condattr_setclock(attr.as_mut_ptr(), clock_id), 0);
2021-12-06 15:50:14 -06:00
let mut cond: MaybeUninit<libc::pthread_cond_t> = MaybeUninit::uninit();
assert_eq!(libc::pthread_cond_init(cond.as_mut_ptr(), attr.as_ptr()), 0);
assert_eq!(libc::pthread_condattr_destroy(attr.as_mut_ptr()), 0);
2021-12-06 15:50:14 -06:00
let mut mutex: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER;
2021-12-06 15:50:14 -06:00
let mut now_mu: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
assert_eq!(libc::clock_gettime(clock_id, now_mu.as_mut_ptr()), 0);
let now = now_mu.assume_init();
2020-06-03 02:40:21 -05:00
// Waiting for a second... mostly because waiting less requires mich more tricky arithmetic.
// FIXME: wait less.
2020-04-30 17:37:27 -05:00
let timeout = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: now.tv_nsec };
2020-04-30 17:37:27 -05:00
assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
let current_time = Instant::now();
assert_eq!(
2021-12-06 15:50:14 -06:00
libc::pthread_cond_timedwait(cond.as_mut_ptr(), &mut mutex as *mut _, &timeout),
2020-04-30 17:37:27 -05:00
libc::ETIMEDOUT
);
2020-05-19 09:47:25 -05:00
let elapsed_time = current_time.elapsed().as_millis();
2020-05-25 01:07:07 -05:00
assert!(900 <= elapsed_time && elapsed_time <= 1300);
// Test calling `pthread_cond_timedwait` again with an already elapsed timeout.
assert_eq!(
2021-12-06 15:50:14 -06:00
libc::pthread_cond_timedwait(cond.as_mut_ptr(), &mut mutex as *mut _, &timeout),
libc::ETIMEDOUT
);
2020-09-07 10:54:39 -05:00
// Test that invalid nanosecond values (above 10^9 or negative) are rejected with the
// correct error code.
let invalid_timeout_1 = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: 1_000_000_000 };
assert_eq!(
libc::pthread_cond_timedwait(
2021-12-06 15:50:14 -06:00
cond.as_mut_ptr(),
&mut mutex as *mut _,
&invalid_timeout_1
),
libc::EINVAL
);
let invalid_timeout_2 = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: -1 };
assert_eq!(
libc::pthread_cond_timedwait(
2021-12-06 15:50:14 -06:00
cond.as_mut_ptr(),
&mut mutex as *mut _,
&invalid_timeout_2
),
libc::EINVAL
);
2020-09-07 10:54:39 -05:00
// Test that invalid second values (negative) are rejected with the correct error code.
let invalid_timeout_3 = libc::timespec { tv_sec: -1, tv_nsec: 0 };
assert_eq!(
libc::pthread_cond_timedwait(
2021-12-06 15:50:14 -06:00
cond.as_mut_ptr(),
2020-09-07 10:54:39 -05:00
&mut mutex as *mut _,
&invalid_timeout_3
),
libc::EINVAL
);
2020-04-30 17:37:27 -05:00
assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0);
2021-12-06 15:50:14 -06:00
assert_eq!(libc::pthread_cond_destroy(cond.as_mut_ptr()), 0);
}
}
fn main() {
2020-05-19 09:47:25 -05:00
test_timed_wait_timeout(libc::CLOCK_MONOTONIC);
test_timed_wait_timeout(libc::CLOCK_REALTIME);
}