xref: /drstd/src/std/sys/windows/thread.rs (revision 9670759b785600bf6315e4173e46a602f16add7a)
1 use crate::std::ffi::CStr;
2 use crate::std::io;
3 use crate::std::num::NonZeroUsize;
4 use crate::std::os::windows::io::AsRawHandle;
5 use crate::std::os::windows::io::HandleOrNull;
6 use crate::std::ptr;
7 use crate::std::sys::c;
8 use crate::std::sys::handle::Handle;
9 use crate::std::sys::stack_overflow;
10 use crate::std::sys_common::FromInner;
11 use crate::std::time::Duration;
12 use dlibc;
13 use dlibc::c_void;
14 
15 use super::to_u16s;
16 
17 pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
18 
19 pub struct Thread {
20     handle: Handle,
21 }
22 
23 impl Thread {
24     // unsafe: see thread::Builder::spawn_unchecked for safety requirements
new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread>25     pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
26         let p = Box::into_raw(Box::new(p));
27 
28         // FIXME On UNIX, we guard against stack sizes that are too small but
29         // that's because pthreads enforces that stacks are at least
30         // PTHREAD_STACK_MIN bytes big. Windows has no such lower limit, it's
31         // just that below a certain threshold you can't do anything useful.
32         // That threshold is application and architecture-specific, however.
33         let ret = c::CreateThread(
34             ptr::null_mut(),
35             stack,
36             Some(thread_start),
37             p as *mut _,
38             c::STACK_SIZE_PARAM_IS_A_RESERVATION,
39             ptr::null_mut(),
40         );
41         let ret = HandleOrNull::from_raw_handle(ret);
42         return if let Ok(handle) = ret.try_into() {
43             Ok(Thread {
44                 handle: Handle::from_inner(handle),
45             })
46         } else {
47             // The thread failed to start and as a result p was not consumed. Therefore, it is
48             // safe to reconstruct the box so that it gets deallocated.
49             drop(Box::from_raw(p));
50             Err(io::Error::last_os_error())
51         };
52 
53         extern "system" fn thread_start(main: *mut c_void) -> c::DWORD {
54             unsafe {
55                 // Next, set up our stack overflow handler which may get triggered if we run
56                 // out of stack.
57                 let _handler = stack_overflow::Handler::new();
58                 // Finally, let's run some code.
59                 Box::from_raw(main as *mut Box<dyn FnOnce()>)();
60             }
61             0
62         }
63     }
64 
set_name(name: &CStr)65     pub fn set_name(name: &CStr) {
66         if let Ok(utf8) = name.to_str() {
67             if let Ok(utf16) = to_u16s(utf8) {
68                 unsafe {
69                     c::SetThreadDescription(c::GetCurrentThread(), utf16.as_ptr());
70                 };
71             };
72         };
73     }
74 
join(self)75     pub fn join(self) {
76         let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) };
77         if rc == c::WAIT_FAILED {
78             panic!("failed to join on thread: {}", io::Error::last_os_error());
79         }
80     }
81 
yield_now()82     pub fn yield_now() {
83         // This function will return 0 if there are no other threads to execute,
84         // but this also means that the yield was useless so this isn't really a
85         // case that needs to be worried about.
86         unsafe {
87             c::SwitchToThread();
88         }
89     }
90 
sleep(dur: Duration)91     pub fn sleep(dur: Duration) {
92         unsafe { c::Sleep(super::dur2timeout(dur)) }
93     }
94 
handle(&self) -> &Handle95     pub fn handle(&self) -> &Handle {
96         &self.handle
97     }
98 
into_handle(self) -> Handle99     pub fn into_handle(self) -> Handle {
100         self.handle
101     }
102 }
103 
available_parallelism() -> io::Result<NonZeroUsize>104 pub fn available_parallelism() -> io::Result<NonZeroUsize> {
105     let res = unsafe {
106         let mut sysinfo: c::SYSTEM_INFO = crate::std::mem::zeroed();
107         c::GetSystemInfo(&mut sysinfo);
108         sysinfo.dwNumberOfProcessors as usize
109     };
110     match res {
111         0 => Err(io::const_io_error!(
112             io::ErrorKind::NotFound,
113             "The number of hardware threads is not known for the target platform",
114         )),
115         cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus) }),
116     }
117 }
118 
119 #[cfg_attr(test, allow(dead_code))]
120 pub mod guard {
121     pub type Guard = !;
current() -> Option<Guard>122     pub unsafe fn current() -> Option<Guard> {
123         None
124     }
init() -> Option<Guard>125     pub unsafe fn init() -> Option<Guard> {
126         None
127     }
128 }
129