usecrate::FromEnvErrorInner; use std::ffi::CString; use std::io; use std::process::Command; use std::ptr; use std::sync::Arc; use std::thread::{Builder, JoinHandle};
#[allow(clippy::upper_case_acronyms)] type BOOL = i32; #[allow(clippy::upper_case_acronyms)] type DWORD = u32; #[allow(clippy::upper_case_acronyms)] type HANDLE = *mut u8; #[allow(clippy::upper_case_acronyms)] type LONG = i32;
// Note that we ideally would use the `getrandom` crate, but unfortunately // that causes build issues when this crate is used in rust-lang/rust (see // rust-lang/rust#65014 for more information). As a result we just inline // the pretty simple Windows-specific implementation of generating // randomness. fn getrandom(dest: &mut [u8]) -> io::Result<()> { // Prevent overflow of u32 for chunk in dest.chunks_mut(u32::MAX as usize) { let ret = unsafe { RtlGenRandom(chunk.as_mut_ptr(), chunk.len() as u32) }; if ret == 0 { return Err(io::Error::new(
io::ErrorKind::Other, "failed to generate random bytes",
));
}
}
Ok(())
}
impl Client { pubfn new(limit: usize) -> io::Result<Client> { // Try a bunch of random semaphore names until we get a unique one, // but don't try for too long. // // Note that `limit == 0` is a valid argument above but Windows // won't let us create a semaphore with 0 slots available to it. Get // `limit == 0` working by creating a semaphore instead with one // slot and then immediately acquire it (without ever releaseing it // back). for _ in0..100 { letmut bytes = [0; 4];
getrandom(&mut bytes)?; letmut name = format!("__rust_jobserver_semaphore_{}\0", u32::from_ne_bytes(bytes)); unsafe { let create_limit = if limit == 0 { 1 } else { limit }; let r = CreateSemaphoreA(
ptr::null_mut(),
create_limit as LONG,
create_limit as LONG,
name.as_ptr() as *const _,
); if r.is_null() { return Err(io::Error::last_os_error());
} let handle = Handle(r);
let err = io::Error::last_os_error(); if err.raw_os_error() == Some(ERROR_ALREADY_EXISTS as i32) { continue;
}
name.pop(); // chop off the trailing nul let client = Client { sem: handle, name }; if create_limit != limit {
client.acquire()?;
} return Ok(client);
}
}
Err(io::Error::new(
io::ErrorKind::Other, "failed to find a unique name for a semaphore",
))
}
pub(crate) unsafefn open(s: &str, _check_pipe: bool) -> Result<Client, FromEnvErrorInner> { let name = match CString::new(s) {
Ok(s) => s,
Err(e) => return Err(FromEnvErrorInner::CannotParse(e.to_string())),
};
let sem = OpenSemaphoreA(SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, FALSE, name.as_ptr()); if sem.is_null() {
Err(FromEnvErrorInner::CannotOpenPath(
s.to_string(),
io::Error::last_os_error(),
))
} else {
Ok(Client {
sem: Handle(sem),
name: s.to_string(),
})
}
}
pubfn acquire(&self) -> io::Result<Acquired> { unsafe { let r = WaitForSingleObject(self.sem.0, INFINITE); if r == WAIT_OBJECT_0 {
Ok(Acquired)
} else {
Err(io::Error::last_os_error())
}
}
}
pubfn try_acquire(&self) -> io::Result<Option<Acquired>> { matchunsafe { WaitForSingleObject(self.sem.0, 0) } {
WAIT_OBJECT_0 => Ok(Some(Acquired)),
WAIT_TIMEOUT => Ok(None),
WAIT_FAILED => Err(io::Error::last_os_error()), // We believe this should be impossible for a semaphore, but still // check the error code just in case it happens.
WAIT_ABANDONED => Err(io::Error::new(
io::ErrorKind::Other, "Wait on jobserver semaphore returned WAIT_ABANDONED",
)),
_ => unreachable!("Unexpected return value from WaitForSingleObject"),
}
}
pubfn release(&self, _data: Option<&Acquired>) -> io::Result<()> { unsafe { let r = ReleaseSemaphore(self.sem.0, 1, ptr::null_mut()); if r != 0 {
Ok(())
} else {
Err(io::Error::last_os_error())
}
}
}
pubfn available(&self) -> io::Result<usize> { // Can't read value of a semaphore on Windows, so // try to acquire without sleeping, since we can find out the // old value on release. If acquisiton fails, then available is 0. unsafe { let r = WaitForSingleObject(self.sem.0, 0); if r != WAIT_OBJECT_0 {
Ok(0)
} else { letmut prev: LONG = 0; let r = ReleaseSemaphore(self.sem.0, 1, &mut prev); if r != 0 {
Ok(prev as usize + 1)
} else {
Err(io::Error::last_os_error())
}
}
}
}
pubfn configure(&self, _cmd: &mut Command) { // nothing to do here, we gave the name of our semaphore to the // child above
}
}
#[derive(Debug)] struct Handle(HANDLE); // HANDLE is a raw ptr, but we're send/sync unsafeimpl Sync for Handle {} unsafeimpl Send for Handle {}
impl Drop for Handle { fn drop(&mutself) { unsafe {
CloseHandle(self.0);
}
}
}
impl Helper { pubfn join(self) { // Unlike unix this logic is much easier. If our thread was blocked // in waiting for requests it should already be woken up and // exiting. Otherwise it's waiting for a token, so we wake it up // with a different event that it's also waiting on here. After // these two we should be guaranteed the thread is on its way out, // so we can safely `join`. let r = unsafe { SetEvent(self.event.0) }; if r == 0 {
panic!("failed to set event: {}", io::Error::last_os_error());
}
drop(self.thread.join());
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-06-19)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.