pub struct TransactionGuard<'captured> { /* private fields */ }Expand description
Holds an installed thread transaction until released.
Not Send: it restores the thread it was created on. Moving one to
another thread would restore that thread’s transaction to a value
captured on a different one, corrupting both.
That property is currently a consequence of a field type rather than of an
explicit bound – previous: Option<HANDLE> is a raw pointer, and raw
pointers are not Send. Nothing would notice if HANDLE were later
replaced by an integer newtype, at which point the guard would silently
become Send and this paragraph would become false. So the claim is
pinned by a test rather than left as prose:
fn assert_send<T: Send>() {}
assert_send::<windows_thread_ambient_sys::transaction::TransactionGuard<'static>>();§Why it borrows the captured context
The installed value is a raw HANDLE owned by the
TransactionContext the guard was built from. Windows recycles handle
values aggressively, so if that context were dropped while the guard were
still alive, the thread would be left enlisting work in whatever kernel
object had since inherited the value – silently, and reachable from safe
code.
The lifetime is what forbids it. Owning a duplicate fixes the capture side of that problem (see this module’s documentation); this fixes the installed side, which is the same hazard one step later.
§Examples
Keeping the context alive alongside the guard is the correct shape:
use windows_thread_ambient_sys::transaction;
let captured = transaction::capture()?;
let guard = transaction::install(&captured)?;
// ... transacted work happens here ...
guard.release()?;Dropping the context while its handle is still installed would leave the thread enlisting work in whatever kernel object Windows had since recycled that handle value onto. The borrow is what forbids it, so this does not compile:
use windows_thread_ambient_sys::transaction;
let guard = {
let captured = transaction::capture().expect("capture");
transaction::install(&captured).expect("install")
// `captured` is dropped here, closing the handle the guard installed.
};
let _ = guard.release();Implementations§
Source§impl TransactionGuard<'_>
impl TransactionGuard<'_>
Sourcepub fn release(self) -> Result<(), TransactionError>
pub fn release(self) -> Result<(), TransactionError>
Restore the thread’s entry transaction, including “none”.
§Errors
Returns a TransactionError if the entry transaction could not be
restored, leaving the thread contaminated.