Skip to main content

TransactionGuard

Struct TransactionGuard 

Source
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<'_>

Source

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.

Trait Implementations§

Source§

impl<'captured> Debug for TransactionGuard<'captured>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Drop for TransactionGuard<'_>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

§

impl<'captured> !Send for TransactionGuard<'captured>

§

impl<'captured> !Sync for TransactionGuard<'captured>

§

impl<'captured> Freeze for TransactionGuard<'captured>

§

impl<'captured> RefUnwindSafe for TransactionGuard<'captured>

§

impl<'captured> Unpin for TransactionGuard<'captured>

§

impl<'captured> UnsafeUnpin for TransactionGuard<'captured>

§

impl<'captured> UnwindSafe for TransactionGuard<'captured>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.