|
1 | 1 | use std::iter; |
| 2 | +use std::time::{Duration, Instant}; |
2 | 3 |
|
3 | 4 | use rustc_middle::mir; |
4 | 5 | use rustc_span::Symbol; |
5 | 6 | use rustc_target::abi::Size; |
6 | 7 | use rustc_target::spec::abi::Abi; |
7 | 8 |
|
| 9 | +use crate::thread::Time; |
8 | 10 | use crate::*; |
9 | 11 | use shims::foreign_items::EmulateByNameResult; |
| 12 | +use shims::windows::handle::Handle; |
10 | 13 | use shims::windows::sync::EvalContextExt as _; |
| 14 | +use shims::windows::thread::EvalContextExt as _; |
| 15 | + |
11 | 16 | use smallvec::SmallVec; |
12 | 17 |
|
13 | 18 | impl<'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 |
230 | 235 | let result = this.QueryPerformanceFrequency(lpFrequency)?; |
231 | 236 | this.write_scalar(Scalar::from_i32(result), dest)?; |
232 | 237 | } |
| 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 | + } |
233 | 261 |
|
234 | 262 | // Synchronization primitives |
235 | 263 | "AcquireSRWLockExclusive" => { |
@@ -340,14 +368,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx |
340 | 368 | // std-only shim. |
341 | 369 | this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; |
342 | 370 | } |
| 371 | + "CloseHandle" => { |
| 372 | + let [handle] = |
| 373 | + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; |
| 374 | + |
| 375 | + match Handle::from_scalar(this.read_scalar(handle)?.check_init()?, this)? { |
| 376 | + Some(Handle::Thread(thread)) => this.detach_thread(thread)?, |
| 377 | + _ => throw_ub_format!("invalid handle"), |
| 378 | + }; |
343 | 379 |
|
344 | | - // Better error for attempts to create a thread |
| 380 | + this.write_scalar(Scalar::from_u32(1), dest)?; |
| 381 | + } |
| 382 | + |
| 383 | + // Threading |
345 | 384 | "CreateThread" => { |
346 | | - let [_, _, _, _, _, _] = |
| 385 | + let [security, stacksize, start, arg, flags, thread] = |
347 | 386 | this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; |
348 | 387 |
|
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)?; |
351 | 405 | } |
352 | 406 |
|
353 | 407 | // Incomplete shims that we "stub out" just to get pre-main initialization code to work. |
|
0 commit comments