Small changes.

This commit is contained in:
Vytautas Astrauskas 2020-05-19 16:47:25 +02:00
parent 0838347d8f
commit 8b5a9836be
4 changed files with 30 additions and 45 deletions
src
tests/run-pass/concurrency

@ -254,7 +254,8 @@ fn cond_set_clock_id<'mir, 'tcx: 'mir>(
set_at_offset(ecx, cond_op, 8, clock_id, ecx.machine.layouts.i32, PTHREAD_COND_T_MIN_SIZE)
}
/// Try to reacquire the mutex associated with the condition variable after we were signaled.
/// Try to reacquire the mutex associated with the condition variable after we
/// were signaled.
fn reacquire_cond_mutex<'mir, 'tcx: 'mir>(
ecx: &mut MiriEvalContext<'mir, 'tcx>,
thread: ThreadId,
@ -269,6 +270,17 @@ fn reacquire_cond_mutex<'mir, 'tcx: 'mir>(
Ok(())
}
/// Reacquire the conditional variable and remove the timeout callback if any
/// was registered.
fn post_cond_signal<'mir, 'tcx: 'mir>(
ecx: &mut MiriEvalContext<'mir, 'tcx>,
thread: ThreadId,
mutex: MutexId,
) -> InterpResult<'tcx> {
reacquire_cond_mutex(ecx, thread, mutex)?;
ecx.unregister_timeout_callback_if_exists(thread)
}
/// Release the mutex associated with the condition variable because we are
/// entering the waiting state.
fn release_cond_mutex<'mir, 'tcx: 'mir>(
@ -648,8 +660,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let this = self.eval_context_mut();
let id = cond_get_or_create_id(this, cond_op)?;
if let Some((thread, mutex)) = this.condvar_signal(id) {
reacquire_cond_mutex(this, thread, mutex)?;
this.unregister_timeout_callback_if_exists(thread)?;
post_cond_signal(this, thread, mutex)?;
}
Ok(0)
@ -660,8 +671,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let id = cond_get_or_create_id(this, cond_op)?;
while let Some((thread, mutex)) = this.condvar_signal(id) {
reacquire_cond_mutex(this, thread, mutex)?;
this.unregister_timeout_callback_if_exists(thread)?;
post_cond_signal(this, thread, mutex)?;
}
Ok(0)
@ -730,7 +740,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
} else if clock_id == this.eval_libc_i32("CLOCK_MONOTONIC")? {
Time::Monotonic(this.machine.time_anchor.checked_add(duration).unwrap())
} else {
throw_ub_format!("Unsupported clock id.");
throw_unsup_format!("Unsupported clock id.");
};
// Register the timeout callback.
@ -738,13 +748,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
active_thread,
timeout_time,
Box::new(move |ecx| {
// Try to reacquire the mutex.
// We are not waiting for the condvar any more, wait for the
// mutex instead.
reacquire_cond_mutex(ecx, active_thread, mutex_id)?;
// Remove the thread from the conditional variable.
ecx.condvar_remove_waiter(id, active_thread);
// Set the timeout value.
// Set the return value: we timed out.
let timeout = ecx.eval_libc_i32("ETIMEDOUT")?;
ecx.write_scalar(Scalar::from_i32(timeout), dest)?;

@ -179,6 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
/// Put the thread into the queue waiting for the lock.
fn mutex_enqueue(&mut self, id: MutexId, thread: ThreadId) {
let this = self.eval_context_mut();
assert!(this.mutex_is_locked(id), "queing on unlocked mutex");
this.machine.threads.sync.mutexes[id].queue.push_back(thread);
}

@ -11,11 +11,11 @@ extern crate libc;
use std::mem;
use std::time::Instant;
fn test_timed_wait_timeout_monotonic() {
fn test_timed_wait_timeout(clock_id: i32) {
unsafe {
let mut attr: libc::pthread_condattr_t = mem::zeroed();
assert_eq!(libc::pthread_condattr_init(&mut attr as *mut _), 0);
assert_eq!(libc::pthread_condattr_setclock(&mut attr as *mut _, libc::CLOCK_MONOTONIC), 0);
assert_eq!(libc::pthread_condattr_setclock(&mut attr as *mut _, clock_id), 0);
let mut cond: libc::pthread_cond_t = mem::zeroed();
assert_eq!(libc::pthread_cond_init(&mut cond as *mut _, &attr as *const _), 0);
@ -24,7 +24,7 @@ fn test_timed_wait_timeout_monotonic() {
let mut mutex: libc::pthread_mutex_t = mem::zeroed();
let mut now: libc::timespec = mem::zeroed();
assert_eq!(libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now), 0);
assert_eq!(libc::clock_gettime(clock_id, &mut now), 0);
let timeout = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: now.tv_nsec };
assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
@ -33,36 +33,8 @@ fn test_timed_wait_timeout_monotonic() {
libc::pthread_cond_timedwait(&mut cond as *mut _, &mut mutex as *mut _, &timeout),
libc::ETIMEDOUT
);
assert!(current_time.elapsed().as_millis() >= 900);
assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_cond_destroy(&mut cond as *mut _), 0);
}
}
fn test_timed_wait_timeout_realtime() {
unsafe {
let mut attr: libc::pthread_condattr_t = mem::zeroed();
assert_eq!(libc::pthread_condattr_init(&mut attr as *mut _), 0);
assert_eq!(libc::pthread_condattr_setclock(&mut attr as *mut _, libc::CLOCK_REALTIME), 0);
let mut cond: libc::pthread_cond_t = mem::zeroed();
assert_eq!(libc::pthread_cond_init(&mut cond as *mut _, &attr as *const _), 0);
assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0);
let mut mutex: libc::pthread_mutex_t = mem::zeroed();
let mut now: libc::timespec = mem::zeroed();
assert_eq!(libc::clock_gettime(libc::CLOCK_REALTIME, &mut now), 0);
let timeout = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: now.tv_nsec };
assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
let current_time = Instant::now();
assert_eq!(
libc::pthread_cond_timedwait(&mut cond as *mut _, &mut mutex as *mut _, &timeout),
libc::ETIMEDOUT
);
assert!(current_time.elapsed().as_millis() >= 900);
let elapsed_time = current_time.elapsed().as_millis();
assert!(900 <= elapsed_time && elapsed_time <= 1100);
assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_cond_destroy(&mut cond as *mut _), 0);
@ -70,6 +42,6 @@ fn test_timed_wait_timeout_realtime() {
}
fn main() {
test_timed_wait_timeout_monotonic();
test_timed_wait_timeout_realtime();
test_timed_wait_timeout(libc::CLOCK_MONOTONIC);
test_timed_wait_timeout(libc::CLOCK_REALTIME);
}

@ -35,8 +35,9 @@ fn check_conditional_variables_notify_one() {
let pair = Arc::new((Mutex::new(false), Condvar::new()));
let pair2 = pair.clone();
// Inside of our lock, spawn a new thread, and then wait for it to start.
// Spawn a new thread.
thread::spawn(move || {
thread::yield_now();
let (lock, cvar) = &*pair2;
let mut started = lock.lock().unwrap();
*started = true;
@ -44,7 +45,7 @@ fn check_conditional_variables_notify_one() {
cvar.notify_one();
});
// Wait for the thread to start up.
// Wait for the thread to fully start up.
let (lock, cvar) = &*pair;
let mut started = lock.lock().unwrap();
while !*started {