11use std:: iter;
2+ use std:: time:: { Duration , Instant } ;
23
34use rustc_middle:: mir;
45use rustc_span:: Symbol ;
56use rustc_target:: abi:: Size ;
67use rustc_target:: spec:: abi:: Abi ;
78
9+ use crate :: thread:: Time ;
810use crate :: * ;
911use shims:: foreign_items:: EmulateByNameResult ;
12+ use shims:: windows:: handle:: { EvalContextExt as _, Handle } ;
1013use shims:: windows:: sync:: EvalContextExt as _;
14+ use shims:: windows:: thread:: EvalContextExt as _;
15+
1116use smallvec:: SmallVec ;
1217
1318impl < ' mir , ' tcx : ' mir > EvalContextExt < ' mir , ' tcx > for crate :: MiriEvalContext < ' mir , ' tcx > { }
@@ -230,6 +235,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
230235 let result = this. QueryPerformanceFrequency ( lpFrequency) ?;
231236 this. write_scalar ( Scalar :: from_i32 ( result) , dest) ?;
232237 }
238+ "Sleep" => {
239+ let [ timeout] =
240+ this. check_shim ( abi, Abi :: System { unwind : false } , link_name, args) ?;
241+
242+ this. check_no_isolation ( "`Sleep`" ) ?;
243+
244+ let timeout_ms = this. read_scalar ( timeout) ?. to_u32 ( ) ?;
245+
246+ let duration = Duration :: from_millis ( timeout_ms as u64 ) ;
247+ let timeout_time = Time :: Monotonic ( Instant :: now ( ) . checked_add ( duration) . unwrap ( ) ) ;
248+
249+ let active_thread = this. get_active_thread ( ) ;
250+ this. block_thread ( active_thread) ;
251+
252+ this. register_timeout_callback (
253+ active_thread,
254+ timeout_time,
255+ Box :: new ( move |ecx| {
256+ ecx. unblock_thread ( active_thread) ;
257+ Ok ( ( ) )
258+ } ) ,
259+ ) ;
260+ }
233261
234262 // Synchronization primitives
235263 "AcquireSRWLockExclusive" => {
@@ -325,10 +353,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
325353 // FIXME: we should set last_error, but to what?
326354 this. write_null ( dest) ?;
327355 }
328- "SwitchToThread" => {
356+ // this is only callable from std because we know that std ignores the return value
357+ "SwitchToThread" if this. frame_in_std ( ) => {
329358 let [ ] = this. check_shim ( abi, Abi :: System { unwind : false } , link_name, args) ?;
330- // Note that once Miri supports concurrency, this will need to return a nonzero
331- // value if this call does result in switching to another thread.
359+
360+ this. yield_active_thread ( ) ;
361+
362+ // FIXME: this should return a nonzero value if this call does result in switching to another thread.
332363 this. write_null ( dest) ?;
333364 }
334365 "GetStdHandle" => {
@@ -340,14 +371,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
340371 // std-only shim.
341372 this. write_scalar ( Scalar :: from_machine_isize ( which. into ( ) , this) , dest) ?;
342373 }
374+ "CloseHandle" => {
375+ let [ handle] =
376+ this. check_shim ( abi, Abi :: System { unwind : false } , link_name, args) ?;
343377
344- // Better error for attempts to create a thread
378+ this. CloseHandle ( handle) ?;
379+
380+ this. write_scalar ( Scalar :: from_u32 ( 1 ) , dest) ?;
381+ }
382+
383+ // Threading
345384 "CreateThread" => {
346- let [ _ , _ , _ , _ , _ , _ ] =
385+ let [ security , stacksize , start , arg , flags , thread ] =
347386 this. check_shim ( abi, Abi :: System { unwind : false } , link_name, args) ?;
348387
349- this. handle_unsupported ( "can't create threads on Windows" ) ?;
350- return Ok ( EmulateByNameResult :: AlreadyJumped ) ;
388+ let thread_id =
389+ this. CreateThread ( security, stacksize, start, arg, flags, thread) ?;
390+
391+ this. write_scalar ( Handle :: Thread ( thread_id) . to_scalar ( this) , dest) ?;
392+ }
393+ "WaitForSingleObject" => {
394+ let [ handle, timeout] =
395+ this. check_shim ( abi, Abi :: System { unwind : false } , link_name, args) ?;
396+
397+ this. WaitForSingleObject ( handle, timeout) ?;
398+
399+ this. write_scalar ( Scalar :: from_u32 ( 0 ) , dest) ?;
400+ }
401+ "GetCurrentThread" => {
402+ let [ ] = this. check_shim ( abi, Abi :: System { unwind : false } , link_name, args) ?;
403+
404+ this. write_scalar ( Handle :: CurrentThread . to_scalar ( this) , dest) ?;
351405 }
352406
353407 // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
@@ -385,40 +439,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
385439 // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
386440 this. write_scalar ( Scalar :: from_u32 ( 1 ) , dest) ?;
387441 }
388- | "InitializeCriticalSection"
389- | "EnterCriticalSection"
390- | "LeaveCriticalSection"
391- | "DeleteCriticalSection"
392- if this. frame_in_std ( ) =>
393- {
394- #[ allow( non_snake_case) ]
395- let [ _lpCriticalSection] =
396- this. check_shim ( abi, Abi :: System { unwind : false } , link_name, args) ?;
397- assert_eq ! (
398- this. get_total_thread_count( ) ,
399- 1 ,
400- "concurrency on Windows is not supported"
401- ) ;
402- // Nothing to do, not even a return value.
403- // (Windows locks are reentrant, and we have only 1 thread,
404- // so not doing any futher checks here is at least not incorrect.)
405- }
406- "TryEnterCriticalSection" if this. frame_in_std ( ) => {
407- #[ allow( non_snake_case) ]
408- let [ _lpCriticalSection] =
409- this. check_shim ( abi, Abi :: System { unwind : false } , link_name, args) ?;
410- assert_eq ! (
411- this. get_total_thread_count( ) ,
412- 1 ,
413- "concurrency on Windows is not supported"
414- ) ;
415- // There is only one thread, so this always succeeds and returns TRUE.
416- this. write_scalar ( Scalar :: from_i32 ( 1 ) , dest) ?;
417- }
418- "GetCurrentThread" if this. frame_in_std ( ) => {
419- let [ ] = this. check_shim ( abi, Abi :: System { unwind : false } , link_name, args) ?;
420- this. write_scalar ( Scalar :: from_machine_isize ( 1 , this) , dest) ?;
421- }
422442 "GetCurrentProcessId" if this. frame_in_std ( ) => {
423443 let [ ] = this. check_shim ( abi, Abi :: System { unwind : false } , link_name, args) ?;
424444 let result = this. GetCurrentProcessId ( ) ?;
0 commit comments