Skip to content

Commit 3beb3fc

Browse files
committed
address comments
1 parent d1d15a4 commit 3beb3fc

File tree

1 file changed

+44
-35
lines changed

1 file changed

+44
-35
lines changed

src/shims/unix/sync.rs

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,22 @@ fn condattr_get_clock_id<'tcx>(
286286
.to_i32()
287287
}
288288

289+
fn translate_clock_id<'tcx>(
290+
ecx: &MiriInterpCx<'tcx>,
291+
raw_id: i32,
292+
) -> InterpResult<'tcx, ClockType> {
293+
// To ensure compatibility with PTHREAD_COND_INITIALIZER on all platforms,
294+
// we can't just compare with CLOCK_REALTIME: on Solarish, PTHREAD_COND_INITIALIZER
295+
// makes the clock 0 but CLOCK_REALTIME is 3.
296+
Ok(if raw_id == ecx.eval_libc_i32("CLOCK_REALTIME") || raw_id == 0 {
297+
ClockType::Realtime
298+
} else if raw_id == ecx.eval_libc_i32("CLOCK_MONOTONIC") {
299+
ClockType::Monotonic
300+
} else {
301+
throw_unsup_format!("unsupported type of clock id: {raw_id}");
302+
})
303+
}
304+
289305
fn condattr_set_clock_id<'tcx>(
290306
ecx: &mut MiriInterpCx<'tcx>,
291307
attr_ptr: &OpTy<'tcx>,
@@ -331,16 +347,6 @@ fn cond_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
331347
Ok(offset)
332348
}
333349

334-
/// Determines whether this clock represents the real-time clock, CLOCK_REALTIME.
335-
fn is_cond_clock_realtime<'tcx>(ecx: &MiriInterpCx<'tcx>, clock_id: i32) -> bool {
336-
// To ensure compatibility with PTHREAD_COND_INITIALIZER on all platforms,
337-
// we can't just compare with CLOCK_REALTIME: on Solarish, PTHREAD_COND_INITIALIZER
338-
// makes the clock 0 but CLOCK_REALTIME is 3.
339-
// However, we need to always be able to distinguish this from CLOCK_MONOTONIC.
340-
clock_id == ecx.eval_libc_i32("CLOCK_REALTIME")
341-
|| (clock_id == 0 && clock_id != ecx.eval_libc_i32("CLOCK_MONOTONIC"))
342-
}
343-
344350
fn cond_clock_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> u64 {
345351
// macOS doesn't have a clock attribute, but to keep the code uniform we store
346352
// a clock ID in the pthread_cond_t anyway. There's enough space.
@@ -355,20 +361,30 @@ fn cond_clock_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> u64 {
355361
.offset(Size::from_bytes(offset), ecx.machine.layouts.i32, ecx)
356362
.unwrap();
357363
let id = ecx.read_scalar(&id_field).unwrap().to_i32().unwrap();
364+
let id = translate_clock_id(ecx, id).expect("static initializer should be valid");
358365
assert!(
359-
is_cond_clock_realtime(ecx, id),
366+
matches!(id, ClockType::Realtime),
360367
"PTHREAD_COND_INITIALIZER is incompatible with our pthread_cond layout: clock is not CLOCK_REALTIME"
361368
);
362369
}
363370

364371
offset
365372
}
366373

374+
#[derive(Debug, Clone, Copy)]
375+
enum ClockType {
376+
Realtime,
377+
Monotonic,
378+
}
379+
367380
#[derive(Debug)]
368381
/// Additional data that we attach with each cond instance.
369382
struct AdditionalCondData {
370383
/// The address of the cond.
371384
address: u64,
385+
386+
/// The clock type of the cond.
387+
clock_type: ClockType,
372388
}
373389

374390
fn cond_get_id<'tcx>(
@@ -377,8 +393,14 @@ fn cond_get_id<'tcx>(
377393
) -> InterpResult<'tcx, CondvarId> {
378394
let cond = ecx.deref_pointer(cond_ptr)?;
379395
let address = cond.ptr().addr().bytes();
380-
let id = ecx.condvar_get_or_create_id(&cond, cond_id_offset(ecx)?, |_| {
381-
Ok(Some(Box::new(AdditionalCondData { address })))
396+
let id = ecx.condvar_get_or_create_id(&cond, cond_id_offset(ecx)?, |ecx| {
397+
let raw_id = if ecx.tcx.sess.target.os == "macos" {
398+
ecx.eval_libc_i32("CLOCK_REALTIME")
399+
} else {
400+
cond_get_clock_id(ecx, cond_ptr)?
401+
};
402+
let clock_type = translate_clock_id(ecx, raw_id)?;
403+
Ok(Some(Box::new(AdditionalCondData { address, clock_type })))
382404
})?;
383405

384406
// Check that the mutex has not been moved since last use.
@@ -405,20 +427,6 @@ fn cond_get_clock_id<'tcx>(
405427
.to_i32()
406428
}
407429

408-
fn cond_set_clock_id<'tcx>(
409-
ecx: &mut MiriInterpCx<'tcx>,
410-
cond_ptr: &OpTy<'tcx>,
411-
clock_id: i32,
412-
) -> InterpResult<'tcx, ()> {
413-
ecx.deref_pointer_and_write(
414-
cond_ptr,
415-
cond_clock_offset(ecx),
416-
Scalar::from_i32(clock_id),
417-
ecx.libc_ty_layout("pthread_cond_t"),
418-
ecx.machine.layouts.i32,
419-
)
420-
}
421-
422430
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
423431
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
424432
fn pthread_mutexattr_init(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
@@ -827,17 +835,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
827835
} else {
828836
condattr_get_clock_id(this, attr_op)?
829837
};
838+
let clock_type = translate_clock_id(this, clock_id)?;
830839

831840
let cond = this.deref_pointer(cond_op)?;
832841
let address = cond.ptr().addr().bytes();
833842
this.condvar_create(
834843
&cond,
835844
cond_id_offset(this)?,
836-
Some(Box::new(AdditionalCondData { address })),
845+
Some(Box::new(AdditionalCondData { address, clock_type })),
837846
)?;
838847

839-
cond_set_clock_id(this, cond_op, clock_id)?;
840-
841848
Ok(())
842849
}
843850

@@ -891,7 +898,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
891898
let mutex_id = mutex_get_id(this, mutex_op)?;
892899

893900
// Extract the timeout.
894-
let clock_id = cond_get_clock_id(this, cond_op)?;
901+
let clock_type = this
902+
.condvar_get_data::<AdditionalCondData>(id)
903+
.expect("additional data should always be present for pthreads")
904+
.clock_type;
895905
let duration = match this
896906
.read_timespec(&this.deref_pointer_as(abstime_op, this.libc_ty_layout("timespec"))?)?
897907
{
@@ -902,13 +912,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
902912
return Ok(());
903913
}
904914
};
905-
let timeout_clock = if is_cond_clock_realtime(this, clock_id) {
915+
let timeout_clock = if matches!(clock_type, ClockType::Realtime) {
906916
this.check_no_isolation("`pthread_cond_timedwait` with `CLOCK_REALTIME`")?;
907917
TimeoutClock::RealTime
908-
} else if clock_id == this.eval_libc_i32("CLOCK_MONOTONIC") {
918+
} else if let ClockType::Monotonic = clock_type {
909919
TimeoutClock::Monotonic
910920
} else {
911-
throw_unsup_format!("unsupported clock id: {}", clock_id);
921+
throw_unsup_format!("unsupported clock id: {clock_type:?}");
912922
};
913923

914924
this.condvar_wait(
@@ -933,7 +943,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
933943

934944
// Destroying an uninit pthread_cond is UB, so check to make sure it's not uninit.
935945
cond_get_id(this, cond_op)?;
936-
cond_get_clock_id(this, cond_op)?;
937946

938947
// This might lead to false positives, see comment in pthread_mutexattr_destroy
939948
this.write_uninit(&this.deref_pointer_as(cond_op, this.libc_ty_layout("pthread_cond_t"))?)?;

0 commit comments

Comments
 (0)