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