Skip to content

Commit

Permalink
basic theading
Browse files Browse the repository at this point in the history
  • Loading branch information
beepster4096 committed Jul 10, 2022
1 parent 1118d94 commit 57d6ac7
Show file tree
Hide file tree
Showing 59 changed files with 476 additions and 165 deletions.
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#![feature(try_blocks)]
#![feature(let_else)]
#![feature(io_error_more)]
#![feature(int_log)]
#![feature(variant_count)]
#![feature(yeet_expr)]
#![feature(is_some_with)]
#![feature(nonzero_ops)]
Expand Down
4 changes: 2 additions & 2 deletions src/shims/tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
fn schedule_windows_tls_dtors(&mut self) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let active_thread = this.get_active_thread();
assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported");

// Windows has a special magic linker section that is run on certain events.
// Instead of searching for that section and supporting arbitrary hooks in there
// (that would be basically https://github.com/rust-lang/miri/issues/450),
Expand All @@ -252,7 +252,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.get_ptr_fn(this.scalar_to_ptr(thread_callback)?)?.as_instance()?;

// The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`.
let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_THREAD_DETACH"])?;
let reason = this.eval_windows("c", "DLL_THREAD_DETACH")?;
this.call_function(
thread_callback,
Abi::System { unwind: false },
Expand Down
43 changes: 5 additions & 38 deletions src/shims/unix/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,47 +13,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
) -> InterpResult<'tcx, i32> {
let this = self.eval_context_mut();

// Create the new thread
let new_thread_id = this.create_thread();

// Write the current thread-id, switch to the next thread later
// to treat this write operation as occuring on the current thread.
let thread_info_place = this.deref_operand(thread)?;
this.write_scalar(
Scalar::from_uint(new_thread_id.to_u32(), thread_info_place.layout.size),
&thread_info_place.into(),
)?;

// Read the function argument that will be sent to the new thread
// before the thread starts executing since reading after the
// context switch will incorrectly report a data-race.
let fn_ptr = this.read_pointer(start_routine)?;
let func_arg = this.read_immediate(arg)?;

// Finally switch to new thread so that we can push the first stackframe.
// After this all accesses will be treated as occuring in the new thread.
let old_thread_id = this.set_active_thread(new_thread_id);

// Perform the function pointer load in the new thread frame.
let instance = this.get_ptr_fn(fn_ptr)?.as_instance()?;

// Note: the returned value is currently ignored (see the FIXME in
// pthread_join below) because the Rust standard library does not use
// it.
let ret_place =
this.allocate(this.layout_of(this.tcx.types.usize)?, MiriMemoryKind::Machine.into())?;

this.call_function(
instance,
this.start_thread(
Some(thread),
start_routine,
Abi::C { unwind: false },
&[*func_arg],
Some(&ret_place.into()),
StackPopCleanup::Root { cleanup: true },
arg,
this.layout_of(this.tcx.types.usize)?,
)?;

// Restore the old active thread frame.
this.set_active_thread(old_thread_id);

Ok(0)
}

Expand Down
19 changes: 19 additions & 0 deletions src/shims/windows/dlsym.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ use rustc_target::spec::abi::Abi;
use log::trace;

use crate::helpers::check_arg_count;
use crate::shims::windows::handle::Handle;
use crate::*;

#[derive(Debug, Copy, Clone)]
pub enum Dlsym {
NtWriteFile,
SetThreadDescription,
}

impl Dlsym {
Expand All @@ -20,6 +22,7 @@ impl Dlsym {
"GetSystemTimePreciseAsFileTime" => None,
"SetThreadDescription" => None,
"NtWriteFile" => Some(Dlsym::NtWriteFile),
"SetThreadDescription" => Some(Dlsym::SetThreadDescription),
_ => throw_unsup_format!("unsupported Windows dlsym: {}", name),
})
}
Expand Down Expand Up @@ -106,6 +109,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
dest,
)?;
}
Dlsym::SetThreadDescription => {
let [handle, name] = check_arg_count(args)?;

let name = this.read_wide_str(this.read_pointer(name)?)?;

let thread =
match Handle::from_scalar(this.read_scalar(handle)?.check_init()?, this)? {
Some(Handle::Thread(thread)) => thread,
Some(Handle::CurrentThread) => this.get_active_thread(),
_ => throw_ub_format!("invalid handle"),
};

this.set_thread_name_wide(thread, name);

this.write_null(dest)?;
}
}

trace!("{:?}", this.dump_place(**dest));
Expand Down
102 changes: 61 additions & 41 deletions src/shims/windows/foreign_items.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
use std::iter;
use std::time::{Duration, Instant};

use rustc_middle::mir;
use rustc_span::Symbol;
use rustc_target::abi::Size;
use rustc_target::spec::abi::Abi;

use crate::thread::Time;
use crate::*;
use shims::foreign_items::EmulateByNameResult;
use shims::windows::handle::{EvalContextExt as _, Handle};
use shims::windows::sync::EvalContextExt as _;
use shims::windows::thread::EvalContextExt as _;

use smallvec::SmallVec;

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
Expand Down Expand Up @@ -230,6 +235,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let result = this.QueryPerformanceFrequency(lpFrequency)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"Sleep" => {
let [timeout] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;

this.check_no_isolation("`Sleep`")?;

let timeout_ms = this.read_scalar(timeout)?.to_u32()?;

let duration = Duration::from_millis(timeout_ms as u64);
let timeout_time = Time::Monotonic(Instant::now().checked_add(duration).unwrap());

let active_thread = this.get_active_thread();
this.block_thread(active_thread);

this.register_timeout_callback(
active_thread,
timeout_time,
Box::new(move |ecx| {
ecx.unblock_thread(active_thread);
Ok(())
}),
);
}

// Synchronization primitives
"AcquireSRWLockExclusive" => {
Expand Down Expand Up @@ -325,10 +353,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
// FIXME: we should set last_error, but to what?
this.write_null(dest)?;
}
"SwitchToThread" => {
// this is only callable from std because we know that std ignores the return value
"SwitchToThread" if this.frame_in_std() => {
let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
// Note that once Miri supports concurrency, this will need to return a nonzero
// value if this call does result in switching to another thread.

this.yield_active_thread();

// FIXME: this should return a nonzero value if this call does result in switching to another thread.
this.write_null(dest)?;
}
"GetStdHandle" => {
Expand All @@ -340,14 +371,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
// std-only shim.
this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?;
}
"CloseHandle" => {
let [handle] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;

// Better error for attempts to create a thread
this.CloseHandle(handle)?;

this.write_scalar(Scalar::from_u32(1), dest)?;
}

// Threading
"CreateThread" => {
let [_, _, _, _, _, _] =
let [security, stacksize, start, arg, flags, thread] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;

this.handle_unsupported("can't create threads on Windows")?;
return Ok(EmulateByNameResult::AlreadyJumped);
let thread_id =
this.CreateThread(security, stacksize, start, arg, flags, thread)?;

this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?;
}
"WaitForSingleObject" => {
let [handle, timeout] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;

this.WaitForSingleObject(handle, timeout)?;

this.write_scalar(Scalar::from_u32(0), dest)?;
}
"GetCurrentThread" => {
let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;

this.write_scalar(Handle::CurrentThread.to_scalar(this), dest)?;
}

// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
Expand Down Expand Up @@ -385,40 +439,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
// Any non zero value works for the stdlib. This is just used for stack overflows anyway.
this.write_scalar(Scalar::from_u32(1), dest)?;
}
| "InitializeCriticalSection"
| "EnterCriticalSection"
| "LeaveCriticalSection"
| "DeleteCriticalSection"
if this.frame_in_std() =>
{
#[allow(non_snake_case)]
let [_lpCriticalSection] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
assert_eq!(
this.get_total_thread_count(),
1,
"concurrency on Windows is not supported"
);
// Nothing to do, not even a return value.
// (Windows locks are reentrant, and we have only 1 thread,
// so not doing any futher checks here is at least not incorrect.)
}
"TryEnterCriticalSection" if this.frame_in_std() => {
#[allow(non_snake_case)]
let [_lpCriticalSection] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
assert_eq!(
this.get_total_thread_count(),
1,
"concurrency on Windows is not supported"
);
// There is only one thread, so this always succeeds and returns TRUE.
this.write_scalar(Scalar::from_i32(1), dest)?;
}
"GetCurrentThread" if this.frame_in_std() => {
let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
this.write_scalar(Scalar::from_machine_isize(1, this), dest)?;
}
"GetCurrentProcessId" if this.frame_in_std() => {
let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
let result = this.GetCurrentProcessId()?;
Expand Down
Loading

0 comments on commit 57d6ac7

Please sign in to comment.