1 use std::ffi::CString;
2 use std::io;
3 use std::process::Command;
4 use std::ptr;
5 use std::sync::Arc;
6 use std::thread::{Builder, JoinHandle};
7 
8 #[derive(Debug)]
9 pub struct Client {
10     sem: Handle,
11     name: String,
12 }
13 
14 #[derive(Debug)]
15 pub struct Acquired;
16 
17 type BOOL = i32;
18 type DWORD = u32;
19 type HANDLE = *mut u8;
20 type LONG = i32;
21 
22 const ERROR_ALREADY_EXISTS: DWORD = 183;
23 const FALSE: BOOL = 0;
24 const INFINITE: DWORD = 0xffffffff;
25 const SEMAPHORE_MODIFY_STATE: DWORD = 0x2;
26 const SYNCHRONIZE: DWORD = 0x00100000;
27 const TRUE: BOOL = 1;
28 const WAIT_OBJECT_0: DWORD = 0;
29 
30 extern "system" {
CloseHandle(handle: HANDLE) -> BOOL31     fn CloseHandle(handle: HANDLE) -> BOOL;
SetEvent(hEvent: HANDLE) -> BOOL32     fn SetEvent(hEvent: HANDLE) -> BOOL;
WaitForMultipleObjects( ncount: DWORD, lpHandles: *const HANDLE, bWaitAll: BOOL, dwMilliseconds: DWORD, ) -> DWORD33     fn WaitForMultipleObjects(
34         ncount: DWORD,
35         lpHandles: *const HANDLE,
36         bWaitAll: BOOL,
37         dwMilliseconds: DWORD,
38     ) -> DWORD;
CreateEventA( lpEventAttributes: *mut u8, bManualReset: BOOL, bInitialState: BOOL, lpName: *const i8, ) -> HANDLE39     fn CreateEventA(
40         lpEventAttributes: *mut u8,
41         bManualReset: BOOL,
42         bInitialState: BOOL,
43         lpName: *const i8,
44     ) -> HANDLE;
ReleaseSemaphore( hSemaphore: HANDLE, lReleaseCount: LONG, lpPreviousCount: *mut LONG, ) -> BOOL45     fn ReleaseSemaphore(
46         hSemaphore: HANDLE,
47         lReleaseCount: LONG,
48         lpPreviousCount: *mut LONG,
49     ) -> BOOL;
CreateSemaphoreA( lpEventAttributes: *mut u8, lInitialCount: LONG, lMaximumCount: LONG, lpName: *const i8, ) -> HANDLE50     fn CreateSemaphoreA(
51         lpEventAttributes: *mut u8,
52         lInitialCount: LONG,
53         lMaximumCount: LONG,
54         lpName: *const i8,
55     ) -> HANDLE;
OpenSemaphoreA(dwDesiredAccess: DWORD, bInheritHandle: BOOL, lpName: *const i8) -> HANDLE56     fn OpenSemaphoreA(dwDesiredAccess: DWORD, bInheritHandle: BOOL, lpName: *const i8) -> HANDLE;
WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD57     fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
58     #[link_name = "SystemFunction036"]
RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: u32) -> u859     fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: u32) -> u8;
60 }
61 
62 // Note that we ideally would use the `getrandom` crate, but unfortunately
63 // that causes build issues when this crate is used in rust-lang/rust (see
64 // rust-lang/rust#65014 for more information). As a result we just inline
65 // the pretty simple Windows-specific implementation of generating
66 // randomness.
getrandom(dest: &mut [u8]) -> io::Result<()>67 fn getrandom(dest: &mut [u8]) -> io::Result<()> {
68     // Prevent overflow of u32
69     for chunk in dest.chunks_mut(u32::max_value() as usize) {
70         let ret = unsafe { RtlGenRandom(chunk.as_mut_ptr(), chunk.len() as u32) };
71         if ret == 0 {
72             return Err(io::Error::new(
73                 io::ErrorKind::Other,
74                 "failed to generate random bytes",
75             ));
76         }
77     }
78     Ok(())
79 }
80 
81 impl Client {
new(limit: usize) -> io::Result<Client>82     pub fn new(limit: usize) -> io::Result<Client> {
83         // Try a bunch of random semaphore names until we get a unique one,
84         // but don't try for too long.
85         //
86         // Note that `limit == 0` is a valid argument above but Windows
87         // won't let us create a semaphore with 0 slots available to it. Get
88         // `limit == 0` working by creating a semaphore instead with one
89         // slot and then immediately acquire it (without ever releaseing it
90         // back).
91         for _ in 0..100 {
92             let mut bytes = [0; 4];
93             getrandom(&mut bytes)?;
94             let mut name = format!("__rust_jobserver_semaphore_{}\0", u32::from_ne_bytes(bytes));
95             unsafe {
96                 let create_limit = if limit == 0 { 1 } else { limit };
97                 let r = CreateSemaphoreA(
98                     ptr::null_mut(),
99                     create_limit as LONG,
100                     create_limit as LONG,
101                     name.as_ptr() as *const _,
102                 );
103                 if r.is_null() {
104                     return Err(io::Error::last_os_error());
105                 }
106                 let handle = Handle(r);
107 
108                 let err = io::Error::last_os_error();
109                 if err.raw_os_error() == Some(ERROR_ALREADY_EXISTS as i32) {
110                     continue;
111                 }
112                 name.pop(); // chop off the trailing nul
113                 let client = Client {
114                     sem: handle,
115                     name: name,
116                 };
117                 if create_limit != limit {
118                     client.acquire()?;
119                 }
120                 return Ok(client);
121             }
122         }
123 
124         Err(io::Error::new(
125             io::ErrorKind::Other,
126             "failed to find a unique name for a semaphore",
127         ))
128     }
129 
open(s: &str) -> Option<Client>130     pub unsafe fn open(s: &str) -> Option<Client> {
131         let name = match CString::new(s) {
132             Ok(s) => s,
133             Err(_) => return None,
134         };
135 
136         let sem = OpenSemaphoreA(SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, FALSE, name.as_ptr());
137         if sem.is_null() {
138             None
139         } else {
140             Some(Client {
141                 sem: Handle(sem),
142                 name: s.to_string(),
143             })
144         }
145     }
146 
acquire(&self) -> io::Result<Acquired>147     pub fn acquire(&self) -> io::Result<Acquired> {
148         unsafe {
149             let r = WaitForSingleObject(self.sem.0, INFINITE);
150             if r == WAIT_OBJECT_0 {
151                 Ok(Acquired)
152             } else {
153                 Err(io::Error::last_os_error())
154             }
155         }
156     }
157 
release(&self, _data: Option<&Acquired>) -> io::Result<()>158     pub fn release(&self, _data: Option<&Acquired>) -> io::Result<()> {
159         unsafe {
160             let r = ReleaseSemaphore(self.sem.0, 1, ptr::null_mut());
161             if r != 0 {
162                 Ok(())
163             } else {
164                 Err(io::Error::last_os_error())
165             }
166         }
167     }
168 
string_arg(&self) -> String169     pub fn string_arg(&self) -> String {
170         self.name.clone()
171     }
172 
configure(&self, _cmd: &mut Command)173     pub fn configure(&self, _cmd: &mut Command) {
174         // nothing to do here, we gave the name of our semaphore to the
175         // child above
176     }
177 }
178 
179 #[derive(Debug)]
180 struct Handle(HANDLE);
181 // HANDLE is a raw ptr, but we're send/sync
182 unsafe impl Sync for Handle {}
183 unsafe impl Send for Handle {}
184 
185 impl Drop for Handle {
drop(&mut self)186     fn drop(&mut self) {
187         unsafe {
188             CloseHandle(self.0);
189         }
190     }
191 }
192 
193 #[derive(Debug)]
194 pub struct Helper {
195     event: Arc<Handle>,
196     thread: JoinHandle<()>,
197 }
198 
spawn_helper( client: crate::Client, state: Arc<super::HelperState>, mut f: Box<dyn FnMut(io::Result<crate::Acquired>) + Send>, ) -> io::Result<Helper>199 pub(crate) fn spawn_helper(
200     client: crate::Client,
201     state: Arc<super::HelperState>,
202     mut f: Box<dyn FnMut(io::Result<crate::Acquired>) + Send>,
203 ) -> io::Result<Helper> {
204     let event = unsafe {
205         let r = CreateEventA(ptr::null_mut(), TRUE, FALSE, ptr::null());
206         if r.is_null() {
207             return Err(io::Error::last_os_error());
208         } else {
209             Handle(r)
210         }
211     };
212     let event = Arc::new(event);
213     let event2 = event.clone();
214     let thread = Builder::new().spawn(move || {
215         let objects = [event2.0, client.inner.sem.0];
216         state.for_each_request(|_| {
217             const WAIT_OBJECT_1: u32 = WAIT_OBJECT_0 + 1;
218             match unsafe { WaitForMultipleObjects(2, objects.as_ptr(), FALSE, INFINITE) } {
219                 WAIT_OBJECT_0 => return,
220                 WAIT_OBJECT_1 => f(Ok(crate::Acquired {
221                     client: client.inner.clone(),
222                     data: Acquired,
223                     disabled: false,
224                 })),
225                 _ => f(Err(io::Error::last_os_error())),
226             }
227         });
228     })?;
229     Ok(Helper { thread, event })
230 }
231 
232 impl Helper {
join(self)233     pub fn join(self) {
234         // Unlike unix this logic is much easier. If our thread was blocked
235         // in waiting for requests it should already be woken up and
236         // exiting. Otherwise it's waiting for a token, so we wake it up
237         // with a different event that it's also waiting on here. After
238         // these two we should be guaranteed the thread is on its way out,
239         // so we can safely `join`.
240         let r = unsafe { SetEvent(self.event.0) };
241         if r == 0 {
242             panic!("failed to set event: {}", io::Error::last_os_error());
243         }
244         drop(self.thread.join());
245     }
246 }
247