win-sync-sys
Memory-safe Rust over the Win32 synchronization API: the objects Windows provides for one thread
to signal another, and for a thread to wait. Thin over Win32 and adding no policy -- the -sys
suffix is that promise, as the workspace's naming decision defines it.
What is here
Event-- an owned event object, created withCreateEventW, that can be set and reset withoutunsafe. A clone (try_clone) is a second handle to the same object, so one part of a program can keep an event to signal while another hands it to something that waits on it.
use OwnedHandle;
use ;
let ready = new?;
// A second handle to the same event, for another thread to signal through.
let signaller = ready.try_clone?;
spawn
.join
.expect?;
// `ready` is now signalled. Anything that waits on a handle can take it from
// here; an `Event` converts into an `OwnedHandle` and lends one as well.
let handle: OwnedHandle = ready.into;
# drop;
# Ok::
wait_for_single_object--WaitForSingleObjectover any handle, anEventincluded, with a timeout ofNonefor no limit or aDuration. It reports how the wait ended as aWaitOutcome, so a mutex abandoned by its owner is not mistaken for a signal. A satisfied wait changes the object as the Win32 call does: an auto-reset event is consumed.
use Duration;
use ;
let event = new?;
assert_eq!;
event.set?;
assert_eq!;
// The wait took the signal.
assert_eq!;
# Ok::
windows-threadpool-sys accepts an Event as a thread-pool wait target without unsafe, because
an Event is never a mutex -- the one kind of object the pool cannot wait on.
wait_for_any,wait_for_all,signal_object_and_wait,wait_for_single_object_exandqueue_user_apc-- the rest of the wait functions:WaitForMultipleObjectsExfor up toMAXIMUM_OBJECTS(64) objects, either until any one is signalled, reporting which, or until all are at once, which takes from them atomically;SignalObjectAndWait, which can signal only aSignalableobject, so aWaitOnlyEventis refused by the compiler; and the alertable form of each, anAlertable::Yeswait that an APC ends withAlerted.queue_user_apctakes a Rust closure and runs it on the target thread in its next alertable wait.
use Duration;
use ;
let events = ;
let poll = Some;
events.set?;
assert_eq!;
// All, atomically: one signalled is not enough, and nothing is taken until both are.
events.set?;
assert_eq!;
events.set?;
assert_eq!;
// An APC ends an alertable wait, and runs first.
queue_user_apc_to_current_thread?;
let outcome = wait_for_any?;
assert_eq!;
// Signal one object and wait on another in one call.
let = ;
signal_object_and_wait?;
# Ok::
WaitOnlyEventandduplicate_handle_with_access-- a handle to the same object that can do less.Event::try_clone_wait_onlygives a handle to the event that can be waited on and can neither set nor reset it: the kernel refuses aSetEventorResetEventon it.duplicate_handle_with_accessisDuplicateHandlewith the access mask chosen, over any handle and returning anOwnedHandle. Windows does not confine a duplicate to the source's access, so a holder that sets out to can duplicate a wait-only handle into a wider one; the narrowing guards against a handle used for what it was not handed out for, and is not a boundary within the process.
use Duration;
use ;
let event = new?;
// Hand this to something that should wait for the event and never signal it.
let waiter = event.try_clone_wait_only?;
assert_eq!;
event.set?;
assert_eq!;
// The same for a handle that is not an `Event`, such as one received from elsewhere.
let adopted = duplicate_handle_with_access?;
assert_eq!;
# Ok::
What is not here
PulseEvent, deliberately. Its own documentation calls it unreliable and says it should not be used: a thread waiting on the event can be briefly taken out of its wait by a kernel-mode APC, and a pulse that lands in that moment releases nothing, because a pulse releases only the threads waiting at the instant it happens. The waiter misses a signal it was waiting for, and nothing reports that it did. Microsoft's replacement is a condition variable.- Named events and
OpenEvent. Every event here is unnamed. Whether named objects belong in this crate is not yet decided. - The other kernel objects -- semaphores, mutexes and waitable timers -- are planned in this
crate's
CHECKLIST.md. - The in-process primitives -- SRW locks, condition variables, critical sections, one-time
initialization, barriers and
WaitOnAddress-- are parked rather than rejected.
The reasoning behind each is in this crate's DESIGN-NOTES.md.