@@ -66,6 +66,27 @@ pub(super) use declare_id;
66
66
67
67
declare_id ! ( MutexId ) ;
68
68
69
+ /// The mutex kind.
70
+ #[ derive( Debug , Clone , Copy ) ]
71
+ #[ non_exhaustive]
72
+ pub enum MutexKind {
73
+ Invalid ,
74
+ Normal ,
75
+ Default ,
76
+ Recursive ,
77
+ ErrorCheck ,
78
+ }
79
+
80
+ #[ derive( Debug ) ]
81
+ /// Additional data that may be used by shim implementations.
82
+ pub struct AdditionalMutexData {
83
+ /// The mutex kind, used by some mutex implementations like pthreads mutexes.
84
+ pub kind : MutexKind ,
85
+
86
+ /// The address of the mutex.
87
+ pub address : u64 ,
88
+ }
89
+
69
90
/// The mutex state.
70
91
#[ derive( Default , Debug ) ]
71
92
struct Mutex {
@@ -77,6 +98,9 @@ struct Mutex {
77
98
queue : VecDeque < ThreadId > ,
78
99
/// Mutex clock. This tracks the moment of the last unlock.
79
100
clock : VClock ,
101
+
102
+ /// Additional data that can be set by shim implementations.
103
+ data : Option < AdditionalMutexData > ,
80
104
}
81
105
82
106
declare_id ! ( RwLockId ) ;
@@ -168,13 +192,15 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
168
192
/// Returns `None` if memory stores a non-zero invalid ID.
169
193
///
170
194
/// `get_objs` must return the `IndexVec` that stores all the objects of this type.
195
+ /// `create_obj` must create the new object if initialization is needed.
171
196
#[ inline]
172
- fn get_or_create_id < Id : SyncId + Idx , T : Default > (
197
+ fn get_or_create_id < Id : SyncId + Idx , T > (
173
198
& mut self ,
174
199
lock_op : & OpTy < ' tcx > ,
175
200
lock_layout : TyAndLayout < ' tcx > ,
176
201
offset : u64 ,
177
202
get_objs : impl for < ' a > Fn ( & ' a mut MiriInterpCx < ' tcx > ) -> & ' a mut IndexVec < Id , T > ,
203
+ create_obj : impl for < ' a > FnOnce ( & ' a mut MiriInterpCx < ' tcx > ) -> InterpResult < ' tcx , T > ,
178
204
) -> InterpResult < ' tcx , Option < Id > > {
179
205
let this = self . eval_context_mut ( ) ;
180
206
let value_place =
@@ -196,7 +222,8 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
196
222
Ok ( if success. to_bool ( ) . expect ( "compare_exchange's second return value is a bool" ) {
197
223
// We set the in-memory ID to `next_index`, now also create this object in the machine
198
224
// state.
199
- let new_index = get_objs ( this) . push ( T :: default ( ) ) ;
225
+ let obj = create_obj ( this) ?;
226
+ let new_index = get_objs ( this) . push ( obj) ;
200
227
assert_eq ! ( next_index, new_index) ;
201
228
Some ( new_index)
202
229
} else {
@@ -210,6 +237,32 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
210
237
} )
211
238
}
212
239
240
+ /// Eagerly creates a Miri sync structure.
241
+ ///
242
+ /// `create_id` will store the index of the sync_structure in the memory pointed to by
243
+ /// `lock_op`, so that future calls to `get_or_create_id` will see it as initialized.
244
+ /// - `lock_op` must hold a pointer to the sync structure.
245
+ /// - `lock_layout` must be the memory layout of the sync structure.
246
+ /// - `offset` must be the offset inside the sync structure where its miri id will be stored.
247
+ /// - `get_objs` is described in `get_or_create_id`.
248
+ /// - `obj` must be the new sync object.
249
+ fn create_id < Id : SyncId + Idx , T > (
250
+ & mut self ,
251
+ lock_op : & OpTy < ' tcx > ,
252
+ lock_layout : TyAndLayout < ' tcx > ,
253
+ offset : u64 ,
254
+ get_objs : impl for < ' a > Fn ( & ' a mut MiriInterpCx < ' tcx > ) -> & ' a mut IndexVec < Id , T > ,
255
+ obj : T ,
256
+ ) -> InterpResult < ' tcx , Id > {
257
+ let this = self . eval_context_mut ( ) ;
258
+ let value_place =
259
+ this. deref_pointer_and_offset ( lock_op, offset, lock_layout, this. machine . layouts . u32 ) ?;
260
+
261
+ let new_index = get_objs ( this) . push ( obj) ;
262
+ this. write_scalar ( Scalar :: from_u32 ( new_index. to_u32 ( ) ) , & value_place) ?;
263
+ Ok ( new_index)
264
+ }
265
+
213
266
fn condvar_reacquire_mutex (
214
267
& mut self ,
215
268
mutex : MutexId ,
@@ -236,15 +289,53 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
236
289
// situations.
237
290
impl < ' tcx > EvalContextExt < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
238
291
pub trait EvalContextExt < ' tcx > : crate :: MiriInterpCxExt < ' tcx > {
292
+ /// Eagerly create and initialize a new mutex.
293
+ fn mutex_create (
294
+ & mut self ,
295
+ lock_op : & OpTy < ' tcx > ,
296
+ lock_layout : TyAndLayout < ' tcx > ,
297
+ offset : u64 ,
298
+ data : Option < AdditionalMutexData > ,
299
+ ) -> InterpResult < ' tcx , MutexId > {
300
+ let this = self . eval_context_mut ( ) ;
301
+ this. create_id (
302
+ lock_op,
303
+ lock_layout,
304
+ offset,
305
+ |ecx| & mut ecx. machine . sync . mutexes ,
306
+ Mutex { data, ..Default :: default ( ) } ,
307
+ )
308
+ }
309
+
310
+ /// Lazily create a new mutex.
311
+ /// `initialize_data` must return any additional data that a user wants to associate with the mutex.
239
312
fn mutex_get_or_create_id (
240
313
& mut self ,
241
314
lock_op : & OpTy < ' tcx > ,
242
315
lock_layout : TyAndLayout < ' tcx > ,
243
316
offset : u64 ,
317
+ initialize_data : impl for < ' a > FnOnce (
318
+ & ' a mut MiriInterpCx < ' tcx > ,
319
+ ) -> InterpResult < ' tcx , Option < AdditionalMutexData > > ,
244
320
) -> InterpResult < ' tcx , MutexId > {
245
321
let this = self . eval_context_mut ( ) ;
246
- this. get_or_create_id ( lock_op, lock_layout, offset, |ecx| & mut ecx. machine . sync . mutexes ) ?
247
- . ok_or_else ( || err_ub_format ! ( "mutex has invalid ID" ) . into ( ) )
322
+ this. get_or_create_id (
323
+ lock_op,
324
+ lock_layout,
325
+ offset,
326
+ |ecx| & mut ecx. machine . sync . mutexes ,
327
+ |ecx| initialize_data ( ecx) . map ( |data| Mutex { data, ..Default :: default ( ) } ) ,
328
+ ) ?
329
+ . ok_or_else ( || err_ub_format ! ( "mutex has invalid ID" ) . into ( ) )
330
+ }
331
+
332
+ /// Retrieve the additional data stored for a mutex.
333
+ fn mutex_get_data < ' a > ( & ' a mut self , id : MutexId ) -> Option < & ' a AdditionalMutexData >
334
+ where
335
+ ' tcx : ' a ,
336
+ {
337
+ let this = self . eval_context_ref ( ) ;
338
+ this. machine . sync . mutexes [ id] . data . as_ref ( )
248
339
}
249
340
250
341
fn rwlock_get_or_create_id (
@@ -254,8 +345,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
254
345
offset : u64 ,
255
346
) -> InterpResult < ' tcx , RwLockId > {
256
347
let this = self . eval_context_mut ( ) ;
257
- this. get_or_create_id ( lock_op, lock_layout, offset, |ecx| & mut ecx. machine . sync . rwlocks ) ?
258
- . ok_or_else ( || err_ub_format ! ( "rwlock has invalid ID" ) . into ( ) )
348
+ this. get_or_create_id (
349
+ lock_op,
350
+ lock_layout,
351
+ offset,
352
+ |ecx| & mut ecx. machine . sync . rwlocks ,
353
+ |_| Ok ( Default :: default ( ) ) ,
354
+ ) ?
355
+ . ok_or_else ( || err_ub_format ! ( "rwlock has invalid ID" ) . into ( ) )
259
356
}
260
357
261
358
fn condvar_get_or_create_id (
@@ -265,8 +362,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
265
362
offset : u64 ,
266
363
) -> InterpResult < ' tcx , CondvarId > {
267
364
let this = self . eval_context_mut ( ) ;
268
- this. get_or_create_id ( lock_op, lock_layout, offset, |ecx| & mut ecx. machine . sync . condvars ) ?
269
- . ok_or_else ( || err_ub_format ! ( "condvar has invalid ID" ) . into ( ) )
365
+ this. get_or_create_id (
366
+ lock_op,
367
+ lock_layout,
368
+ offset,
369
+ |ecx| & mut ecx. machine . sync . condvars ,
370
+ |_| Ok ( Default :: default ( ) ) ,
371
+ ) ?
372
+ . ok_or_else ( || err_ub_format ! ( "condvar has invalid ID" ) . into ( ) )
270
373
}
271
374
272
375
#[ inline]
0 commit comments