Skip to content

Commit 90590a3

Browse files
committed
Small fixes.
1 parent 6ff0af3 commit 90590a3

File tree

5 files changed

+60
-11
lines changed

5 files changed

+60
-11
lines changed

src/shims/sync.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,8 @@ fn post_cond_signal<'mir, 'tcx: 'mir>(
301301
mutex: MutexId,
302302
) -> InterpResult<'tcx> {
303303
reacquire_cond_mutex(ecx, thread, mutex)?;
304+
// Waiting for the mutex is not included in the waiting time because we need
305+
// to acquire the mutex always even if we get a timeout.
304306
ecx.unregister_timeout_callback_if_exists(thread)
305307
}
306308

@@ -343,10 +345,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
343345
let kind = this.read_scalar(kind_op)?.not_undef()?;
344346
if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? {
345347
// In `glibc` implementation, the numeric values of
346-
// `PTHREAD_MUTEX_NORMAL` and `PTHREAD_MUTEX_DEFAULT` are equal, but
347-
// they have different behaviour in some cases. Therefore, we add
348-
// this flag to ensure that we can distinguish
349-
// `PTHREAD_MUTEX_NORMAL` from `PTHREAD_MUTEX_DEFAULT`.
348+
// `PTHREAD_MUTEX_NORMAL` and `PTHREAD_MUTEX_DEFAULT` are equal.
349+
// However, a mutex created by explicitly passing
350+
// `PTHREAD_MUTEX_NORMAL` type has in some cases different behaviour
351+
// from the default mutex for which the type was not explicitly
352+
// specified. For a more detailed discussion, please see
353+
// https://github.com/rust-lang/miri/issues/1419.
354+
//
355+
// To distinguish these two cases in already constructed mutexes, we
356+
// use the same trick as glibc: for the case when
357+
// `pthread_mutexattr_settype` is caled explicitly, we set the
358+
// `PTHREAD_MUTEX_NORMAL_FLAG` flag.
350359
let normal_kind = kind.to_i32()? | PTHREAD_MUTEX_NORMAL_FLAG;
351360
// Check that after setting the flag, the kind is distinguishable
352361
// from all other kinds.
@@ -414,7 +423,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
414423
} else {
415424
// Trying to acquire the same mutex again.
416425
if is_mutex_kind_default(this, kind)? {
417-
throw_ub_format!("trying to acquire already locked PTHREAD_MUTEX_DEFAULT");
426+
throw_ub_format!("trying to acquire already locked default mutex");
418427
} else if is_mutex_kind_normal(this, kind)? {
419428
throw_machine_stop!(TerminationInfo::Deadlock);
420429
} else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? {
@@ -484,7 +493,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
484493
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_unlock.html.
485494
if is_mutex_kind_default(this, kind)? {
486495
throw_ub_format!(
487-
"unlocked a PTHREAD_MUTEX_DEFAULT mutex that was not locked by the current thread"
496+
"unlocked a default mutex that was not locked by the current thread"
488497
);
489498
} else if is_mutex_kind_normal(this, kind)? {
490499
throw_ub_format!(

src/thread.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,9 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
377377
}
378378

379379
/// Register the given `callback` to be called once the `call_time` passes.
380+
///
381+
/// The callback will be called with `thread` being the active thread, and
382+
/// the callback may not change the active thread.
380383
fn register_timeout_callback(
381384
&mut self,
382385
thread: ThreadId,
@@ -452,10 +455,8 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
452455
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html#
453456
let potential_sleep_time =
454457
self.timeout_callbacks.values().map(|info| info.call_time.get_wait_time()).min();
455-
if let Some(sleep_time) = potential_sleep_time {
456-
if sleep_time == Duration::new(0, 0) {
457-
return Ok(SchedulingAction::ExecuteTimeoutCallback);
458-
}
458+
if potential_sleep_time == Some(Duration::new(0, 0)) {
459+
return Ok(SchedulingAction::ExecuteTimeoutCallback);
459460
}
460461
// No callbacks scheduled, pick a regular thread to execute.
461462
if self.threads[self.active_thread].state == ThreadState::Enabled
@@ -699,6 +700,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
699700
let this = self.eval_context_mut();
700701
let (thread, callback) =
701702
this.machine.threads.get_ready_callback().expect("no callback found");
703+
// This back-and-forth with `set_active_thread` is here because of two
704+
// design decisions:
705+
// 1. Make the caller and not the callback responsible for changing
706+
// thread.
707+
// 2. Make the scheduler the only place that can change the active
708+
// thread.
702709
let old_thread = this.set_active_thread(thread)?;
703710
callback(this)?;
704711
this.set_active_thread(old_thread)?;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// ignore-windows: No libc on Windows
2+
//
3+
// Check that if we pass NULL attribute, then we get the default mutex type.
4+
5+
#![feature(rustc_private)]
6+
7+
extern crate libc;
8+
9+
fn main() {
10+
unsafe {
11+
let mut mutex: libc::pthread_mutex_t = std::mem::zeroed();
12+
assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, std::ptr::null() as *const _), 0);
13+
assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
14+
libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR Undefined Behavior: trying to acquire already locked default mutex
15+
}
16+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// ignore-windows: No libc on Windows
2+
//
3+
// Check that if we do not set the mutex type, it is the default.
4+
5+
#![feature(rustc_private)]
6+
7+
extern crate libc;
8+
9+
fn main() {
10+
unsafe {
11+
let mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed();
12+
let mut mutex: libc::pthread_mutex_t = std::mem::zeroed();
13+
assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0);
14+
assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
15+
libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR Undefined Behavior: trying to acquire already locked default mutex
16+
}
17+
}

tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ fn main() {
2424

2525
let lock_copy = lock.clone();
2626
thread::spawn(move || {
27-
assert_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: Undefined Behavior: unlocked a PTHREAD_MUTEX_DEFAULT mutex that was not locked
27+
assert_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: Undefined Behavior: unlocked a default mutex that was not locked by the current thread
2828
})
2929
.join()
3030
.unwrap();

0 commit comments

Comments
 (0)