pub struct DriverFence<'a, T: Send + Sync + FenceContextOps> { /* private fields */ }Expand description
A synchronization primitive mainly for GPU drivers.
The Rust DMA fence implementation has a dualistic design: DriverFences
are the producer-side, intended to be always owned by only one party. That
party has the monopoly on signaling the fence.
A Fence is the counterpart for consumers. Thus, Fences are always
refcounted and can be shared with an arbitrary number of parties, including
userspace. A Fence can only be used for actions such as checking the
fence’s status or for registering callbacks on it.
Once the associated DriverFence signals, all
FenceCallbackRegistrations registered on a Fence will be executed.
A Fence can arbitrarily outlive its DriverFence and the
FenceContext. Signaling a DriverFence decouples it from its
Fences.
It is crucial that a DriverFence always correctly represents the state
of the associated job on the hardware. Especially, it is strictly necessary
that the owner ensures that all DriverFences eventually get signaled.
As a last resort, a DriverFence will signal itself if it drops
unsignaled and print a warning.
This design intends to implement the [bindings::dma_fence_ops] in such a
way that the driver-data necessary to implement the callback’s functionality
resides in the FenceContext. Thus, a DriverFence contains a
reference to the context, which can be accessed in the callbacks. The
implementation, therefore, ensures that a DriverFence cannot outlive its
FenceContext. Unfortunately, this can be circumvented under certain
circumstances in Rust (e.g., usage of core::mem::forget).
In the unlikely case of such violations, a panic is thrown.
§Examples
use kernel::{
dma_buf::{
DriverFence,
FenceContext,
FenceContextOps,
FenceCallback,
FenceCallbackRegistration,
},
str::CString,
sync::aref::ARef, //
};
use core::fmt::Display;
struct CallbackData { }
impl FenceCallback for CallbackData {
fn on_signal(&mut self) {
pr_info!("DmaFence callback executed.\n");
}
}
#[pin_data]
struct FenceContextData {}
impl FenceContextData {
fn new() -> impl PinInit<Self> {
pin_init!(Self {})
}
}
impl FenceContextOps for FenceContextData {
type FenceDataType = FenceData;
}
let fctx_data = FenceContextData::new();
let mut fctx = KBox::pin_init(
FenceContext::new(0, c"dummy_driver", c"dummy_timeline", fctx_data),
GFP_KERNEL
)?;
struct FenceData {
data: CString,
}
let fence_data = FenceData { data: c"dummy_data".try_into()? };
let fence_alloc = fctx.new_fence_allocation(fence_data)?;
let mut fence = fence_alloc.new_fence();
let cb_data = CallbackData { };
let waiting_fence = ARef::from(fence.as_fence());
let cb_reg = FenceCallbackRegistration::new(&waiting_fence, cb_data);
let cb_reg = KBox::pin_init(cb_reg, GFP_KERNEL)?;
// TODO signalling guards
assert_eq!(waiting_fence.is_signaled(), false);
fence.signal(Ok(()));
assert_eq!(waiting_fence.is_signaled(), true);
Ok::<(), Error>(())Implementations§
Trait Implementations§
Source§impl<'a, T: Send + Sync + FenceContextOps> Deref for DriverFence<'a, T>
impl<'a, T: Send + Sync + FenceContextOps> Deref for DriverFence<'a, T>
Source§type Target = <T as FenceContextOps>::FenceDataType
type Target = <T as FenceContextOps>::FenceDataType
Source§impl<'a, T: Send + Sync + FenceContextOps> Drop for DriverFence<'a, T>
impl<'a, T: Send + Sync + FenceContextOps> Drop for DriverFence<'a, T>
Source§impl<T: Send + Sync + FenceContextOps> ForeignOwnable for DriverFence<'_, T>
impl<T: Send + Sync + FenceContextOps> ForeignOwnable for DriverFence<'_, T>
Source§const FOREIGN_ALIGN: usize
const FOREIGN_ALIGN: usize
into_foreign.Source§type Borrowed<'a> = DriverFenceBorrow<'a, T>
where
Self: 'a
type Borrowed<'a> = DriverFenceBorrow<'a, T> where Self: 'a
Source§type BorrowedMut<'a> = DriverFenceBorrow<'a, T>
where
Self: 'a
type BorrowedMut<'a> = DriverFenceBorrow<'a, T> where Self: 'a
Source§fn into_foreign(self) -> *mut c_void
fn into_foreign(self) -> *mut c_void
Source§unsafe fn from_foreign(ptr: *mut c_void) -> Self
unsafe fn from_foreign(ptr: *mut c_void) -> Self
Source§unsafe fn borrow<'a>(ptr: *mut c_void) -> Self::Borrowed<'a>where
Self: 'a,
unsafe fn borrow<'a>(ptr: *mut c_void) -> Self::Borrowed<'a>where
Self: 'a,
Source§unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> Self::BorrowedMut<'a>where
Self: 'a,
unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> Self::BorrowedMut<'a>where
Self: 'a,
impl<'a, T: Send + Sync + FenceContextOps> Send for DriverFence<'a, T>
impl<'a, T: Send + Sync + FenceContextOps> Sync for DriverFence<'a, T>
Auto Trait Implementations§
impl<'a, T> !RefUnwindSafe for DriverFence<'a, T>
impl<'a, T> !UnwindSafe for DriverFence<'a, T>
impl<'a, T> Freeze for DriverFence<'a, T>
impl<'a, T> Unpin for DriverFence<'a, T>
impl<'a, T> UnsafeUnpin for DriverFence<'a, T>where
NonNull<DriverFenceData<'a, T>>: UnsafeUnpin,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<S, T> IntoSafeCast<T> for Swhere
T: FromSafeCast<S>,
impl<S, T> IntoSafeCast<T> for Swhere
T: FromSafeCast<S>,
Source§fn into_safe_cast(self) -> T
fn into_safe_cast(self) -> T
self into a T. This operation is guaranteed to be lossless.Source§impl<S, T> IntoSafeCastArch<T> for Swhere
T: FromSafeCastArch<S>,
impl<S, T> IntoSafeCastArch<T> for Swhere
T: FromSafeCastArch<S>,
Source§fn into_safe_cast_arch(self) -> T
fn into_safe_cast_arch(self) -> T
self into a T. This operation is guaranteed to be lossless.