Skip to main content

queue_user_apc

Function queue_user_apc 

Source
pub fn queue_user_apc(
    thread: impl AsHandle,
    routine: impl FnOnce() + Send + 'static,
) -> Result<()>
Expand description

Queue routine to run on thread the next time it waits alertably: QueueUserAPC.

What ends an alertable wait (Alertable::Yes) is an APC, and this is how one is made. The routine runs on thread, inside whichever alertable wait or sleep it next makes, before that wait returns WaitOutcome::Alerted; a thread that never waits alertably never runs it. APCs queued to a thread run in the order they were queued.

thread is any handle that lends itself, and must carry THREAD_SET_CONTEXT access, to queue, and THREAD_QUERY_LIMITED_INFORMATION, to ask which process it belongs to: a std::thread::JoinHandle carries both.

It must be a thread of this process. The routine is an address and a closure in this process, which mean nothing in another, where delivering it would run whatever is at that address. A thread of another process is refused, as io::ErrorKind::InvalidInput, before anything is queued.

A thread that has not finished starting runs it as it starts. Windows delivers an APC queued to a new thread when the thread begins, before it reaches the Rust runtime that std::thread::spawn sets up around the closure it was given, so the routine runs outside that runtime: std::thread::current there aborts the process (“current thread handle already set”). Queue to a thread known to be running – one that has announced itself – unless the routine touches nothing of the runtime.

The routine may never run. If the thread ends first, or never waits alertably, it stays queued and is not dropped, so what it captured is leaked; no error says so, because the call succeeded. A routine that must not be lost needs a thread known to wait alertably.

It runs in whatever context the thread is in when it makes the wait – possibly while the thread holds locks or is inside a callback of the caller’s – so it must not assume the thread is idle. A panic in it aborts the process, as a panic out of any extern "system" function does.

§Errors

Invalid handle for one that is not a thread, access denied for a thread handle without THREAD_QUERY_LIMITED_INFORMATION or THREAD_SET_CONTEXT, io::ErrorKind::InvalidInput for a thread of another process, and otherwise the error from QueueUserAPC. The routine is dropped, unrun, when the call fails.