Skip to content

Commit e3cfe45

Browse files
committed
make lazy_sync_get_data also take a closure to initialize if needed
1 parent 0f7d321 commit e3cfe45

3 files changed

Lines changed: 32 additions & 51 deletions

File tree

‎src/tools/miri/src/concurrency/sync.rs‎

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -201,12 +201,11 @@ pub fn lazy_sync_init<'tcx, T: 'static + Copy>(
201201
init_offset:Size,
202202
data:T,
203203
) -> InterpResult<'tcx>{
204-
let init_field = primitive.offset(init_offset, ecx.machine.layouts.u32, ecx)?;
205-
206204
let(alloc, offset, _) = ecx.ptr_get_alloc_id(primitive.ptr(),0)?;
207205
let(alloc_extra, _machine) = ecx.get_alloc_extra_mut(alloc)?;
208206
alloc_extra.sync.insert(offset,Box::new(data));
209207
// Mark this as "initialized".
208+
let init_field = primitive.offset(init_offset, ecx.machine.layouts.u32, ecx)?;
210209
ecx.write_scalar_atomic(
211210
Scalar::from_u32(LAZY_INIT_COOKIE),
212211
&init_field,
@@ -217,18 +216,19 @@ pub fn lazy_sync_init<'tcx, T: 'static + Copy>(
217216

218217
/// Helper for lazily initialized `alloc_extra.sync` data:
219218
/// Checks if the primitive is initialized, and return its associated data if so.
220-
/// Otherwise, return None.
219+
/// Otherwise, calls `new_data` to initialize the primitive.
221220
pubfnlazy_sync_get_data<'tcx,T:'static + Copy>(
222221
ecx:&mutMiriInterpCx<'tcx>,
223222
primitive:&MPlaceTy<'tcx>,
224223
init_offset:Size,
225224
name:&str,
226-
) -> InterpResult<'tcx,Option<T>>{
227-
let init_field = primitive.offset(init_offset, ecx.machine.layouts.u32, ecx)?;
225+
new_data:implFnOnce(&mutMiriInterpCx<'tcx>) -> InterpResult<'tcx,T>,
226+
) -> InterpResult<'tcx,T>{
228227
// Check if this is already initialized. Needs to be atomic because we can race with another
229228
// thread initializing. Needs to be an RMW operation to ensure we read the *latest* value.
230229
// So we just try to replace MUTEX_INIT_COOKIE with itself.
231230
let init_cookie = Scalar::from_u32(LAZY_INIT_COOKIE);
231+
let init_field = primitive.offset(init_offset, ecx.machine.layouts.u32, ecx)?;
232232
let(_init, success) = ecx
233233
.atomic_compare_exchange_scalar(
234234
&init_field,
@@ -239,6 +239,7 @@ pub fn lazy_sync_get_data<'tcx, T: 'static + Copy>(
239239
/* can_fail_spuriously */false,
240240
)?
241241
.to_scalar_pair();
242+
242243
if success.to_bool()? {
243244
// If it is initialized, it must be found in the "sync primitive" table,
244245
// or else it has been moved illegally.
@@ -247,9 +248,11 @@ pub fn lazy_sync_get_data<'tcx, T: 'static + Copy>(
247248
let data = alloc_extra
248249
.get_sync::<T>(offset)
249250
.ok_or_else(|| err_ub_format!("`{name}` can't be moved after first use"))?;
250-
interp_ok(Some(*data))
251+
interp_ok(*data)
251252
}else{
252-
interp_ok(None)
253+
let data = new_data(ecx)?;
254+
lazy_sync_init(ecx, primitive, init_offset, data)?;
255+
interp_ok(data)
253256
}
254257
}
255258

‎src/tools/miri/src/shims/unix/sync.rs‎

Lines changed: 12 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -190,19 +190,11 @@ fn mutex_get_data<'tcx, 'a>(
190190
mutex_ptr:&OpTy<'tcx>,
191191
) -> InterpResult<'tcx,MutexData>{
192192
let mutex = ecx.deref_pointer(mutex_ptr)?;
193-
194-
ifletSome(data) =
195-
lazy_sync_get_data::<MutexData>(ecx,&mutex,mutex_init_offset(ecx)?,"pthread_mutex_t")?
196-
{
197-
interp_ok(data)
198-
}else{
199-
// Not yet initialized. This must be a static initializer, figure out the kind
200-
// from that. We don't need to worry about races since we are the interpreter
201-
// and don't let any other tread take a step.
193+
lazy_sync_get_data(ecx,&mutex,mutex_init_offset(ecx)?,"pthread_mutex_t", |ecx| {
202194
let kind = mutex_kind_from_static_initializer(ecx,&mutex)?;
203-
// And then create the mutex like this.
204-
mutex_create(ecx, mutex_ptr, kind)
205-
}
195+
let id = ecx.machine.sync.mutex_create();
196+
interp_ok(MutexData{ id, kind})
197+
})
206198
}
207199

208200
/// Returns the kind of a static initializer.
@@ -271,13 +263,7 @@ fn rwlock_get_data<'tcx>(
271263
rwlock_ptr:&OpTy<'tcx>,
272264
) -> InterpResult<'tcx,RwLockData>{
273265
let rwlock = ecx.deref_pointer(rwlock_ptr)?;
274-
let init_offset = rwlock_init_offset(ecx)?;
275-
276-
ifletSome(data) =
277-
lazy_sync_get_data::<RwLockData>(ecx,&rwlock, init_offset,"pthread_rwlock_t")?
278-
{
279-
interp_ok(data)
280-
}else{
266+
lazy_sync_get_data(ecx,&rwlock,rwlock_init_offset(ecx)?,"pthread_rwlock_t", |ecx| {
281267
if !bytewise_equal_atomic_relaxed(
282268
ecx,
283269
&rwlock,
@@ -286,10 +272,8 @@ fn rwlock_get_data<'tcx>(
286272
throw_unsup_format!("unsupported static initializer used for `pthread_rwlock_t`");
287273
}
288274
let id = ecx.machine.sync.rwlock_create();
289-
let data = RwLockData{ id };
290-
lazy_sync_init(ecx,&rwlock, init_offset, data)?;
291-
interp_ok(data)
292-
}
275+
interp_ok(RwLockData{ id })
276+
})
293277
}
294278

295279
// # pthread_condattr_t
@@ -405,21 +389,18 @@ fn cond_get_data<'tcx>(
405389
cond_ptr:&OpTy<'tcx>,
406390
) -> InterpResult<'tcx,CondData>{
407391
let cond = ecx.deref_pointer(cond_ptr)?;
408-
let init_offset = cond_init_offset(ecx)?;
409-
410-
ifletSome(data) = lazy_sync_get_data::<CondData>(ecx,&cond, init_offset,"pthread_cond_t")? {
411-
interp_ok(data)
412-
}else{
413-
// This used the static initializer. The clock there is always CLOCK_REALTIME.
392+
lazy_sync_get_data(ecx,&cond,cond_init_offset(ecx)?,"pthread_cond_t", |ecx| {
414393
if !bytewise_equal_atomic_relaxed(
415394
ecx,
416395
&cond,
417396
&ecx.eval_path(&["libc","PTHREAD_COND_INITIALIZER"]),
418397
)? {
419398
throw_unsup_format!("unsupported static initializer used for `pthread_cond_t`");
420399
}
421-
cond_create(ecx, cond_ptr,ClockId::Realtime)
422-
}
400+
// This used the static initializer. The clock there is always CLOCK_REALTIME.
401+
let id = ecx.machine.sync.condvar_create();
402+
interp_ok(CondData{ id,clock:ClockId::Realtime})
403+
})
423404
}
424405

425406
impl<'tcx>EvalContextExt<'tcx>forcrate::MiriInterpCx<'tcx>{}

‎src/tools/miri/src/shims/windows/sync.rs‎

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::time::Duration;
33
use rustc_target::abi::Size;
44

55
usecrate::concurrency::init_once::InitOnceStatus;
6-
usecrate::concurrency::sync::{lazy_sync_get_data, lazy_sync_init};
6+
usecrate::concurrency::sync::lazy_sync_get_data;
77
usecrate::*;
88

99
#[derive(Copy,Clone)]
@@ -16,23 +16,20 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
1616
// Windows sync primitives are pointer sized.
1717
// We only use the first 4 bytes for the id.
1818

19-
fninit_once_get_id(&mutself,init_once_ptr:&OpTy<'tcx>) -> InterpResult<'tcx,InitOnceId>{
19+
fninit_once_get_data(
20+
&mutself,
21+
init_once_ptr:&OpTy<'tcx>,
22+
) -> InterpResult<'tcx,InitOnceData>{
2023
let this = self.eval_context_mut();
2124

2225
let init_once = this.deref_pointer(init_once_ptr)?;
2326
let init_offset = Size::ZERO;
2427

25-
ifletSome(data) =
26-
lazy_sync_get_data::<InitOnceData>(this,&init_once, init_offset,"INIT_ONCE")?
27-
{
28-
interp_ok(data.id)
29-
}else{
28+
lazy_sync_get_data(this,&init_once, init_offset,"INIT_ONCE", |this| {
3029
// TODO: check that this is still all-zero.
3130
let id = this.machine.sync.init_once_create();
32-
let data = InitOnceData{ id };
33-
lazy_sync_init(this,&init_once, init_offset, data)?;
34-
interp_ok(id)
35-
}
31+
interp_ok(InitOnceData{ id })
32+
})
3633
}
3734

3835
/// Returns `true` if we were succssful, `false` if we would block.
@@ -74,7 +71,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
7471
) -> InterpResult<'tcx>{
7572
let this = self.eval_context_mut();
7673

77-
let id = this.init_once_get_id(init_once_op)?;
74+
let id = this.init_once_get_data(init_once_op)?.id;
7875
let flags = this.read_scalar(flags_op)?.to_u32()?;
7976
let pending_place = this.deref_pointer(pending_op)?;
8077
let context = this.read_pointer(context_op)?;
@@ -120,7 +117,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
120117
) -> InterpResult<'tcx,Scalar>{
121118
let this = self.eval_context_mut();
122119

123-
let id = this.init_once_get_id(init_once_op)?;
120+
let id = this.init_once_get_data(init_once_op)?.id;
124121
let flags = this.read_scalar(flags_op)?.to_u32()?;
125122
let context = this.read_pointer(context_op)?;
126123

0 commit comments

Comments
 (0)