@@ -8,6 +8,38 @@ use crate::*;
8
8
9
9
const SRWLOCK_ID_OFFSET : u64 = 0 ;
10
10
const INIT_ONCE_ID_OFFSET : u64 = 0 ;
11
+ const CONDVAR_ID_OFFSET : u64 = 0 ;
12
+
13
+ impl < ' mir , ' tcx > EvalContextExtPriv < ' mir , ' tcx > for crate :: MiriInterpCx < ' mir , ' tcx > { }
14
+ pub trait EvalContextExtPriv < ' mir , ' tcx : ' mir > : crate :: MiriInterpCxExt < ' mir , ' tcx > {
15
+ /// Try to reacquire the lock associated with the condition variable after we
16
+ /// were signaled.
17
+ fn reacquire_cond_lock (
18
+ & mut self ,
19
+ thread : ThreadId ,
20
+ lock : RwLockId ,
21
+ shared : bool ,
22
+ ) -> InterpResult < ' tcx > {
23
+ let this = self . eval_context_mut ( ) ;
24
+ this. unblock_thread ( thread) ;
25
+
26
+ if shared {
27
+ if this. rwlock_is_locked ( lock) {
28
+ this. rwlock_enqueue_and_block_reader ( lock, thread) ;
29
+ } else {
30
+ this. rwlock_reader_lock ( lock, thread) ;
31
+ }
32
+ } else {
33
+ if this. rwlock_is_write_locked ( lock) {
34
+ this. rwlock_enqueue_and_block_writer ( lock, thread) ;
35
+ } else {
36
+ this. rwlock_writer_lock ( lock, thread) ;
37
+ }
38
+ }
39
+
40
+ Ok ( ( ) )
41
+ }
42
+ }
11
43
12
44
impl < ' mir , ' tcx > EvalContextExt < ' mir , ' tcx > for crate :: MiriInterpCx < ' mir , ' tcx > { }
13
45
#[ allow( non_snake_case) ]
@@ -327,4 +359,118 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
327
359
328
360
Ok ( ( ) )
329
361
}
362
+
363
+ fn SleepConditionVariableSRW (
364
+ & mut self ,
365
+ condvar_op : & OpTy < ' tcx , Provenance > ,
366
+ lock_op : & OpTy < ' tcx , Provenance > ,
367
+ timeout_op : & OpTy < ' tcx , Provenance > ,
368
+ flags_op : & OpTy < ' tcx , Provenance > ,
369
+ dest : & PlaceTy < ' tcx , Provenance > ,
370
+ ) -> InterpResult < ' tcx , Scalar < Provenance > > {
371
+ let this = self . eval_context_mut ( ) ;
372
+
373
+ let condvar_id = this. condvar_get_or_create_id ( condvar_op, CONDVAR_ID_OFFSET ) ?;
374
+ let lock_id = this. rwlock_get_or_create_id ( lock_op, SRWLOCK_ID_OFFSET ) ?;
375
+ let timeout_ms = this. read_scalar ( timeout_op) ?. to_u32 ( ) ?;
376
+ let flags = this. read_scalar ( flags_op) ?. to_u32 ( ) ?;
377
+
378
+ let timeout_time = if timeout_ms == this. eval_windows ( "c" , "INFINITE" ) ?. to_u32 ( ) ? {
379
+ None
380
+ } else {
381
+ let duration = Duration :: from_millis ( timeout_ms. into ( ) ) ;
382
+ Some ( this. machine . clock . now ( ) . checked_add ( duration) . unwrap ( ) )
383
+ } ;
384
+
385
+ let shared_mode = 0x1 ; // CONDITION_VARIABLE_LOCKMODE_SHARED is not in std
386
+ let shared = flags == shared_mode;
387
+
388
+ let active_thread = this. get_active_thread ( ) ;
389
+
390
+ let was_locked = if shared {
391
+ this. rwlock_reader_unlock ( lock_id, active_thread)
392
+ } else {
393
+ this. rwlock_writer_unlock ( lock_id, active_thread)
394
+ } ;
395
+
396
+ if !was_locked {
397
+ throw_ub_format ! (
398
+ "calling SleepConditionVariableSRW with an SRWLock that is not locked by the current thread"
399
+ ) ;
400
+ }
401
+
402
+ this. block_thread ( active_thread) ;
403
+ this. condvar_wait ( condvar_id, active_thread, lock_id. to_u32 ( ) , shared) ;
404
+
405
+ if let Some ( timeout_time) = timeout_time {
406
+ struct Callback < ' tcx > {
407
+ thread : ThreadId ,
408
+ condvar_id : CondvarId ,
409
+ lock_id : RwLockId ,
410
+ shared : bool ,
411
+ dest : PlaceTy < ' tcx , Provenance > ,
412
+ }
413
+
414
+ impl < ' tcx > VisitTags for Callback < ' tcx > {
415
+ fn visit_tags ( & self , visit : & mut dyn FnMut ( SbTag ) ) {
416
+ let Callback { thread : _, condvar_id : _, lock_id : _, shared : _, dest } = self ;
417
+ dest. visit_tags ( visit) ;
418
+ }
419
+ }
420
+
421
+ impl < ' mir , ' tcx : ' mir > MachineCallback < ' mir , ' tcx > for Callback < ' tcx > {
422
+ fn call ( & self , this : & mut MiriInterpCx < ' mir , ' tcx > ) -> InterpResult < ' tcx > {
423
+ this. reacquire_cond_lock ( self . thread , self . lock_id , self . shared ) ?;
424
+
425
+ this. condvar_remove_waiter ( self . condvar_id , self . thread ) ;
426
+
427
+ let error_timeout = this. eval_windows ( "c" , "ERROR_TIMEOUT" ) ?;
428
+ this. set_last_error ( error_timeout) ?;
429
+ this. write_scalar ( this. eval_windows ( "c" , "FALSE" ) ?, & self . dest ) ?;
430
+ Ok ( ( ) )
431
+ }
432
+ }
433
+
434
+ this. register_timeout_callback (
435
+ active_thread,
436
+ Time :: Monotonic ( timeout_time) ,
437
+ Box :: new ( Callback {
438
+ thread : active_thread,
439
+ condvar_id,
440
+ lock_id,
441
+ shared,
442
+ dest : dest. clone ( ) ,
443
+ } ) ,
444
+ ) ;
445
+ }
446
+
447
+ this. eval_windows ( "c" , "TRUE" )
448
+ }
449
+
450
+ fn WakeConditionVariable ( & mut self , condvar_op : & OpTy < ' tcx , Provenance > ) -> InterpResult < ' tcx > {
451
+ let this = self . eval_context_mut ( ) ;
452
+ let condvar_id = this. condvar_get_or_create_id ( condvar_op, CONDVAR_ID_OFFSET ) ?;
453
+
454
+ if let Some ( ( thread, lock, shared) ) = this. condvar_signal ( condvar_id) {
455
+ this. reacquire_cond_lock ( thread, RwLockId :: from_u32 ( lock) , shared) ?;
456
+ this. unregister_timeout_callback_if_exists ( thread) ;
457
+ }
458
+
459
+ Ok ( ( ) )
460
+ }
461
+
462
+ fn WakeAllConditionVariable (
463
+ & mut self ,
464
+ condvar_op : & OpTy < ' tcx , Provenance > ,
465
+ ) -> InterpResult < ' tcx > {
466
+ let this = self . eval_context_mut ( ) ;
467
+ let condvar_id = this. condvar_get_or_create_id ( condvar_op, CONDVAR_ID_OFFSET ) ?;
468
+
469
+ while let Some ( ( thread, lock, shared) ) = this. condvar_signal ( condvar_id) {
470
+ this. reacquire_cond_lock ( thread, RwLockId :: from_u32 ( lock) , shared) ?;
471
+ this. unregister_timeout_callback_if_exists ( thread) ;
472
+ }
473
+
474
+ Ok ( ( ) )
475
+ }
330
476
}
0 commit comments