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