pub struct Devres<T>(/* private fields */);
Expand description
This abstraction is meant to be used by subsystems to containerize Device
bound resources to
manage their lifetime.
Device
bound resources should be freed when either the resource goes out of scope or the
Device
is unbound respectively, depending on what happens first.
To achieve that Devres
registers a devres callback on creation, which is called once the
Device
is unbound, revoking access to the encapsulated resource (see also Revocable
).
After the Devres
has been unbound it is not possible to access the encapsulated resource
anymore.
Devres
users should make sure to simply free the corresponding backing resource in T
’s
Drop
implementation.
§Example
// See also [`pci::Bar`] for a real example.
struct IoMem<const SIZE: usize>(IoRaw<SIZE>);
impl<const SIZE: usize> IoMem<SIZE> {
/// # Safety
///
/// [`paddr`, `paddr` + `SIZE`) must be a valid MMIO region that is mappable into the CPUs
/// virtual address space.
unsafe fn new(paddr: usize) -> Result<Self>{
// SAFETY: By the safety requirements of this function [`paddr`, `paddr` + `SIZE`) is
// valid for `ioremap`.
let addr = unsafe { bindings::ioremap(paddr as _, SIZE as _) };
if addr.is_null() {
return Err(ENOMEM);
}
Ok(IoMem(IoRaw::new(addr as _, SIZE)?))
}
}
impl<const SIZE: usize> Drop for IoMem<SIZE> {
fn drop(&mut self) {
// SAFETY: `self.0.addr()` is guaranteed to be properly mapped by `Self::new`.
unsafe { bindings::iounmap(self.0.addr() as _); };
}
}
impl<const SIZE: usize> Deref for IoMem<SIZE> {
type Target = Io<SIZE>;
fn deref(&self) -> &Self::Target {
// SAFETY: The memory range stored in `self` has been properly mapped in `Self::new`.
unsafe { Io::from_raw(&self.0) }
}
}
// SAFETY: Invalid usage for example purposes.
let iomem = unsafe { IoMem::<{ core::mem::size_of::<u32>() }>::new(0xBAAAAAAD)? };
let devres = Devres::new(dev, iomem, GFP_KERNEL)?;
let res = devres.try_access().ok_or(ENXIO)?;
res.write8(0x42, 0x0);
Implementations§
Source§impl<T> Devres<T>
impl<T> Devres<T>
Sourcepub fn new(dev: &Device<Bound>, data: T, flags: Flags) -> Result<Self>
pub fn new(dev: &Device<Bound>, data: T, flags: Flags) -> Result<Self>
Creates a new Devres
instance of the given data
. The data
encapsulated within the
returned Devres
instance’ data
will be revoked once the device is detached.
Sourcepub fn new_foreign_owned(dev: &Device<Bound>, data: T, flags: Flags) -> Result
pub fn new_foreign_owned(dev: &Device<Bound>, data: T, flags: Flags) -> Result
Same as Devres::new
, but does not return a Devres
instance. Instead the given data
is owned by devres and will be revoked / dropped, once the device is detached.
Methods from Deref<Target = Revocable<T>>§
Sourcepub fn try_access(&self) -> Option<RevocableGuard<'_, T>>
pub fn try_access(&self) -> Option<RevocableGuard<'_, T>>
Tries to access the revocable wrapped object.
Returns None
if the object has been revoked and is therefore no longer accessible.
Returns a guard that gives access to the object otherwise; the object is guaranteed to remain accessible while the guard is alive. In such cases, callers are not allowed to sleep because another CPU may be waiting to complete the revocation of this object.
Sourcepub fn try_access_with_guard<'a>(&'a self, _guard: &'a Guard) -> Option<&'a T>
pub fn try_access_with_guard<'a>(&'a self, _guard: &'a Guard) -> Option<&'a T>
Tries to access the revocable wrapped object.
Returns None
if the object has been revoked and is therefore no longer accessible.
Returns a shared reference to the object otherwise; the object is guaranteed to remain accessible while the rcu read side guard is alive. In such cases, callers are not allowed to sleep because another CPU may be waiting to complete the revocation of this object.
Sourcepub fn try_access_with<R, F: FnOnce(&T) -> R>(&self, f: F) -> Option<R>
pub fn try_access_with<R, F: FnOnce(&T) -> R>(&self, f: F) -> Option<R>
Tries to access the wrapped object and run a closure on it while the guard is held.
This is a convenience method to run short non-sleepable code blocks while ensuring the
guard is dropped afterwards. Self::try_access
carries the risk that the caller will
forget to explicitly drop that returned guard before calling sleepable code; this method
adds an extra safety to make sure it doesn’t happen.
Returns None
if the object has been revoked and is therefore no longer accessible, or
the result of the closure wrapped in Some
. If the closure returns a Result
then the
return type becomes Option<Result<>>
, which can be inconvenient. Users are encouraged to
define their own macro that turns the Option
into a proper error code and flattens the
inner result into it if it makes sense within their subsystem.
Sourcepub unsafe fn revoke_nosync(&self)
pub unsafe fn revoke_nosync(&self)
Revokes access to and drops the wrapped object.
Access to the object is revoked immediately to new callers of Revocable::try_access
,
expecting that there are no concurrent users of the object.
§Safety
Callers must ensure that there are no more concurrent users of the revocable object.
Sourcepub fn revoke(&self)
pub fn revoke(&self)
Revokes access to and drops the wrapped object.
Access to the object is revoked immediately to new callers of Revocable::try_access
.
If there are concurrent users of the object (i.e., ones that called
Revocable::try_access
beforehand and still haven’t dropped the returned guard), this
function waits for the concurrent access to complete before dropping the wrapped object.