@@ -8,6 +8,38 @@ use crate::*;
88
99const SRWLOCK_ID_OFFSET : u64 = 0 ;
1010const 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+ }
1143
1244impl < ' mir , ' tcx > EvalContextExt < ' mir , ' tcx > for crate :: MiriInterpCx < ' mir , ' tcx > { }
1345#[ allow( non_snake_case) ]
@@ -327,4 +359,118 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
327359
328360 Ok ( ( ) )
329361 }
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+ }
330476}
0 commit comments