@@ -3,11 +3,45 @@ use std::time::Duration;
33use rustc_target:: abi:: Size ;
44
55use crate :: concurrency:: init_once:: InitOnceStatus ;
6+ use crate :: concurrency:: sync:: { CondvarLock , RwLockMode } ;
67use crate :: concurrency:: thread:: MachineCallback ;
78use crate :: * ;
89
910const SRWLOCK_ID_OFFSET : u64 = 0 ;
1011const 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+ }
1145
1246impl < ' mir , ' tcx > EvalContextExt < ' mir , ' tcx > for crate :: MiriInterpCx < ' mir , ' tcx > { }
1347#[ allow( non_snake_case) ]
@@ -327,4 +361,131 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
327361
328362 Ok ( ( ) )
329363 }
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+ }
330491}
0 commit comments