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