Struct kernel::grant::ProcessGrant

source ·
pub struct ProcessGrant<'a, T: 'a, Upcalls: UpcallSize, AllowROs: AllowRoSize, AllowRWs: AllowRwSize> {
    process: &'a dyn Process,
    driver_num: usize,
    grant_num: usize,
    _phantom: PhantomData<(T, Upcalls, AllowROs, AllowRWs)>,
}
Expand description

An instance of a grant allocated for a particular process.

ProcessGrant is a handle to an instance of a grant that has been allocated in a specific process’s grant region. A ProcessGrant guarantees that the memory for the grant has been allocated in the process’s memory.

This is created from a Grant when that grant is entered for a specific process.

Fields§

§process: &'a dyn Process

The process the grant is applied to.

We use a reference here because instances of ProcessGrant are very short lived. They only exist while a Grant is being entered, so we can be sure the process still exists while a ProcessGrant exists. No ProcessGrant can be stored.

§driver_num: usize

The syscall driver number this grant is associated with.

§grant_num: usize

The identifier of the Grant this is applied for.

§_phantom: PhantomData<(T, Upcalls, AllowROs, AllowRWs)>

Used to store Rust types for grant.

Implementations§

source§

impl<'a, T: Default, Upcalls: UpcallSize, AllowROs: AllowRoSize, AllowRWs: AllowRwSize> ProcessGrant<'a, T, Upcalls, AllowROs, AllowRWs>

source

fn new( grant: &Grant<T, Upcalls, AllowROs, AllowRWs>, processid: ProcessId, ) -> Result<Self, Error>

Create a ProcessGrant for the given Grant in the given Process’s grant region.

If the grant in this process has not been setup before this will attempt to allocate the memory from the process’s grant region.

§Return

If the grant is already allocated or could be allocated, and the process is valid, this returns Ok(ProcessGrant). Otherwise it returns a relevant error.

source

fn new_if_allocated( grant: &Grant<T, Upcalls, AllowROs, AllowRWs>, process: &'a dyn Process, ) -> Option<Self>

Return a ProcessGrant for a grant in a process if the process is valid and that process grant has already been allocated, or None otherwise.

source

pub fn processid(&self) -> ProcessId

Return the ProcessId of the process this ProcessGrant is associated with.

source

pub fn enter<F, R>(self, fun: F) -> R
where F: FnOnce(&mut GrantData<'_, T>, &GrantKernelData<'_>) -> R,

Run a function with access to the memory in the related process for the related Grant. This also provides access to any associated Upcalls and allowed buffers stored with the grant.

This is “entering” the grant region, and the only time when the contents of a grant region can be accessed.

Note, a grant can only be entered once at a time. Attempting to call .enter() on a grant while it is already entered will result in a panic!(). See the comment in access_grant() for more information.

source

pub fn try_enter<F, R>(self, fun: F) -> Option<R>
where F: FnOnce(&mut GrantData<'_, T>, &GrantKernelData<'_>) -> R,

Run a function with access to the data in the related process for the related Grant only if that grant region is not already entered. If the grant is already entered silently skip it. Also provide access to associated Upcalls.

You almost certainly should use .enter() rather than .try_enter().

While the .enter() version can panic, that panic likely indicates a bug in the code and not a condition that should be handled. For example, this benign looking code is wrong:

self.apps.enter(thisapp, |app_grant, _| {
    // Update state in the grant region of `thisapp`. Also, mark that
    // `thisapp` needs to run again.
    app_grant.runnable = true;

    // Now, check all apps to see if any are ready to run.
    let mut work_left_to_do = false;
    self.apps.iter().each(|other_app| {
        other_app.enter(|other_app_grant, _| { // ERROR! This leads to a
            if other_app_grant.runnable {      // grant being entered
                work_left_to_do = true;        // twice!
            }
        })
    })
})

The example is wrong because it tries to iterate across all grant regions while one of them is already entered. This will lead to a grant region being entered twice which violates Rust’s memory restrictions and is undefined behavior.

However, since the example uses .enter() on the iteration, Tock will panic when the grant is entered for the second time, notifying the developer that something is wrong. The fix is to exit out of the first .enter() before attempting to iterate over the grant for all processes.

However, if the example used .try_enter() in the iter loop, there would be no panic, but the already entered grant would be silently skipped. This can hide subtle bugs if the skipped grant is only relevant in certain cases.

Therefore, only use try_enter() if you are sure you want to skip the already entered grant. Cases for this are rare.

§Return

Returns None if the grant is already entered. Otherwise returns Some(fun()).

source

pub fn enter_with_allocator<F, R>(self, fun: F) -> R
where F: FnOnce(&mut GrantData<'_, T>, &GrantKernelData<'_>, &mut GrantRegionAllocator) -> R,

Run a function with access to the memory in the related process for the related Grant. Also provide this function with access to any associated Upcalls and an allocator for allocating additional memory in the process’s grant region.

This is “entering” the grant region, and the only time when the contents of a grant region can be accessed.

Note, a grant can only be entered once at a time. Attempting to call .enter() on a grant while it is already entered will result in a panic!(). See the comment in access_grant()` for more information.

source

fn access_grant<F, R>(self, fun: F, panic_on_reenter: bool) -> Option<R>
where F: FnOnce(&mut GrantData<'_, T>, &GrantKernelData<'_>) -> R,

Access the ProcessGrant memory and run a closure on the process’s grant memory.

If panic_on_reenter is true, this will panic if the grant region is already currently entered. If panic_on_reenter is false, this will return None if the grant region is entered and do nothing.

source

fn access_grant_with_allocator<F, R>( self, fun: F, panic_on_reenter: bool, ) -> Option<R>
where F: FnOnce(&mut GrantData<'_, T>, &GrantKernelData<'_>, &mut GrantRegionAllocator) -> R,

Access the ProcessGrant memory and run a closure on the process’s grant memory.

If panic_on_reenter is true, this will panic if the grant region is already currently entered. If panic_on_reenter is false, this will return None if the grant region is entered and do nothing.

Auto Trait Implementations§

§

impl<'a, T, Upcalls, AllowROs, AllowRWs> Freeze for ProcessGrant<'a, T, Upcalls, AllowROs, AllowRWs>

§

impl<'a, T, Upcalls, AllowROs, AllowRWs> !RefUnwindSafe for ProcessGrant<'a, T, Upcalls, AllowROs, AllowRWs>

§

impl<'a, T, Upcalls, AllowROs, AllowRWs> !Send for ProcessGrant<'a, T, Upcalls, AllowROs, AllowRWs>

§

impl<'a, T, Upcalls, AllowROs, AllowRWs> !Sync for ProcessGrant<'a, T, Upcalls, AllowROs, AllowRWs>

§

impl<'a, T, Upcalls, AllowROs, AllowRWs> Unpin for ProcessGrant<'a, T, Upcalls, AllowROs, AllowRWs>
where T: Unpin, Upcalls: Unpin, AllowROs: Unpin, AllowRWs: Unpin,

§

impl<'a, T, Upcalls, AllowROs, AllowRWs> !UnwindSafe for ProcessGrant<'a, T, Upcalls, AllowROs, AllowRWs>

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>,

§

type Error = Infallible

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>,

§

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.