From d4af16ddd7d27f603ef08f78cb4288b36f48042a Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Sun, 6 Oct 2024 22:14:30 +0900 Subject: [PATCH] queue/qbuf: remove lifetime requirement on QBuffer Similarly to what the previous commit did for some traits, remove the lifetime generic parameter from QBuffer, and make the reference type generic. This will allow us to use either direct references to the providing queue (which guarantees at compile-time that the queue cannot be mutated while a buffer is being prepared), or reference-counter ones like Rc or Arc (which gives us more freedom as for how long we can keep a QBuffer alive, but require runtime-checks on the provided queue before it can be mutated). --- lib/src/device/queue.rs | 4 +-- lib/src/device/queue/generic.rs | 50 ++++++++++++++++++++++----------- lib/src/device/queue/qbuf.rs | 33 ++++++++++++++-------- 3 files changed, 57 insertions(+), 30 deletions(-) diff --git a/lib/src/device/queue.rs b/lib/src/device/queue.rs index 43a2e99..ff7c21a 100644 --- a/lib/src/device/queue.rs +++ b/lib/src/device/queue.rs @@ -539,7 +539,7 @@ mod private { impl<'a, D: Direction, P: PrimitiveBufferHandles> GetBufferByIndex<'a> for Queue> { - type Queueable = QBuffer<'a, D, P, P>; + type Queueable = QBuffer>>; // Take buffer `id` in order to prepare it for queueing, provided it is available. fn try_get_buffer(&'a self, index: usize) -> Result { @@ -548,7 +548,7 @@ mod private { } impl<'a, D: Direction> GetBufferByIndex<'a> for Queue> { - type Queueable = GenericQBuffer<'a, D>; + type Queueable = GenericQBuffer; fn try_get_buffer(&'a self, index: usize) -> Result { let buffer_info = self.try_obtain_buffer(index)?; diff --git a/lib/src/device/queue/generic.rs b/lib/src/device/queue/generic.rs index 1a222c6..7bfb326 100644 --- a/lib/src/device/queue/generic.rs +++ b/lib/src/device/queue/generic.rs @@ -2,6 +2,7 @@ use crate::{ device::queue::{ direction::{Capture, Direction, Output}, qbuf::{CaptureQueueable, OutputQueueable, QBuffer, QueueResult}, + BuffersAllocated, Queue, }, memory::DmaBufHandle, }; @@ -9,7 +10,7 @@ use crate::{ memory::MmapHandle, memory::{BufferHandles, MemoryType, UserPtrHandle}, }; -use std::{fmt::Debug, fs::File}; +use std::{fmt::Debug, fs::File, ops::Deref}; /// Supported memory types for `GenericBufferHandles`. /// TODO: This should be renamed to "DynamicBufferHandles", and be constructed @@ -80,38 +81,52 @@ impl BufferHandles for GenericBufferHandles { /// A QBuffer that holds either MMAP or UserPtr handles, depending on which /// memory type has been selected for the queue at runtime. -pub enum GenericQBuffer<'a, D: Direction> { - Mmap(QBuffer<'a, D, Vec, GenericBufferHandles>), - User(QBuffer<'a, D, Vec>>, GenericBufferHandles>), - DmaBuf(QBuffer<'a, D, Vec>, GenericBufferHandles>), +pub enum GenericQBuffer< + D: Direction, + Q: Deref>>, +> { + Mmap(QBuffer, GenericBufferHandles, Q>), + User(QBuffer>>, GenericBufferHandles, Q>), + DmaBuf(QBuffer>, GenericBufferHandles, Q>), } -impl<'a, D: Direction> From, GenericBufferHandles>> - for GenericQBuffer<'a, D> +impl From, GenericBufferHandles, Q>> for GenericQBuffer +where + D: Direction, + Q: Deref>>, { - fn from(qb: QBuffer<'a, D, Vec, GenericBufferHandles>) -> Self { + fn from(qb: QBuffer, GenericBufferHandles, Q>) -> Self { GenericQBuffer::Mmap(qb) } } -impl<'a, D: Direction> From>>, GenericBufferHandles>> - for GenericQBuffer<'a, D> +impl From>>, GenericBufferHandles, Q>> + for GenericQBuffer +where + D: Direction, + Q: Deref>>, { - fn from(qb: QBuffer<'a, D, Vec>>, GenericBufferHandles>) -> Self { + fn from(qb: QBuffer>>, GenericBufferHandles, Q>) -> Self { GenericQBuffer::User(qb) } } -impl<'a, D: Direction> From>, GenericBufferHandles>> - for GenericQBuffer<'a, D> +impl From>, GenericBufferHandles, Q>> + for GenericQBuffer +where + D: Direction, + Q: Deref>>, { - fn from(qb: QBuffer<'a, D, Vec>, GenericBufferHandles>) -> Self { + fn from(qb: QBuffer>, GenericBufferHandles, Q>) -> Self { GenericQBuffer::DmaBuf(qb) } } /// Any CAPTURE GenericQBuffer implements CaptureQueueable. -impl CaptureQueueable for GenericQBuffer<'_, Capture> { +impl CaptureQueueable for GenericQBuffer +where + Q: Deref>>, +{ fn queue_with_handles( self, handles: GenericBufferHandles, @@ -125,7 +140,10 @@ impl CaptureQueueable for GenericQBuffer<'_, Capture> { } /// Any OUTPUT GenericQBuffer implements OutputQueueable. -impl OutputQueueable for GenericQBuffer<'_, Output> { +impl OutputQueueable for GenericQBuffer +where + Q: Deref>>, +{ fn queue_with_handles( self, handles: GenericBufferHandles, diff --git a/lib/src/device/queue/qbuf.rs b/lib/src/device/queue/qbuf.rs index f313158..6a1ff3d 100644 --- a/lib/src/device/queue/qbuf.rs +++ b/lib/src/device/queue/qbuf.rs @@ -4,6 +4,7 @@ use super::{BufferState, BufferStateFuse, BuffersAllocated, Queue}; use crate::ioctl::{self, QBufIoctlError, QBufResult}; use crate::memory::*; use std::convert::Infallible; +use std::ops::Deref; use std::{ fmt::{self, Debug}, os::fd::RawFd, @@ -61,8 +62,13 @@ pub type QueueResult = std::result::Result /// queue or device cannot be changed while it is being used. Contrary to /// DQBuffer which can be freely duplicated and passed around, instances of this /// struct are supposed to be short-lived. -pub struct QBuffer<'a, D: Direction, P: PrimitiveBufferHandles, B: BufferHandles + From

> { - queue: &'a Queue>, +pub struct QBuffer< + D: Direction, + P: PrimitiveBufferHandles, + B: BufferHandles + From

, + Q: Deref>>, +> { + queue: Q, index: usize, num_planes: usize, timestamp: TimeVal, @@ -71,16 +77,14 @@ pub struct QBuffer<'a, D: Direction, P: PrimitiveBufferHandles, B: BufferHandles _p: std::marker::PhantomData

, } -impl<'a, D, P, B> QBuffer<'a, D, P, B> +impl QBuffer where D: Direction, P: PrimitiveBufferHandles, B: BufferHandles + From

, + Q: Deref>>, { - pub(super) fn new( - queue: &'a Queue>, - buffer_info: &Arc>, - ) -> Self { + pub(super) fn new(queue: Q, buffer_info: &Arc>) -> Self { let buffer = &buffer_info.features; let fuse = BufferStateFuse::new(Arc::downgrade(buffer_info)); @@ -159,11 +163,12 @@ where } } -impl<'a, P, B> QBuffer<'a, Output, P, B> +impl QBuffer where P: PrimitiveBufferHandles, P::HandleType: Mappable, B: BufferHandles + From

, + Q: Deref>>, { pub fn get_plane_mapping(&self, plane: usize) -> Option { let buffer_info = self.queue.state.buffer_info.get(self.index)?; @@ -203,10 +208,11 @@ pub trait OutputQueueableProvider<'a, B: BufferHandles> { } /// Any CAPTURE QBuffer implements CaptureQueueable. -impl CaptureQueueable for QBuffer<'_, Capture, P, B> +impl CaptureQueueable for QBuffer where P: PrimitiveBufferHandles, B: BufferHandles + From

, + Q: Deref>>, { fn queue_with_handles(self, handles: B) -> QueueResult<(), B> { if handles.len() != self.num_expected_planes() { @@ -233,10 +239,11 @@ where } /// Any OUTPUT QBuffer implements OutputQueueable. -impl OutputQueueable for QBuffer<'_, Output, P, B> +impl OutputQueueable for QBuffer where P: PrimitiveBufferHandles, B: BufferHandles + From

, + Q: Deref>>, { fn queue_with_handles(self, handles: B, bytes_used: &[usize]) -> QueueResult<(), B> { if handles.len() != self.num_expected_planes() { @@ -280,11 +287,12 @@ where /// empty handles. /// Since we don't receive plane handles, we also don't need to return any, so /// the returned error can be simplified. -impl QBuffer<'_, Capture, P, B> +impl QBuffer where P: PrimitiveBufferHandles + Default, ::Memory: SelfBacked, B: BufferHandles + From

, + Q: Deref>>, { pub fn queue(self) -> QBufResult<(), Infallible> { let planes: Vec<_> = (0..self.num_expected_planes()) @@ -300,11 +308,12 @@ where /// empty handles. /// Since we don't receive plane handles, we also don't need to return any, so /// the returned error can be simplified. -impl QBuffer<'_, Output, P, B> +impl QBuffer where ::Memory: SelfBacked, P: PrimitiveBufferHandles + Default, B: BufferHandles + From

, + Q: Deref>>, { pub fn queue(self, bytes_used: &[usize]) -> QBufResult<(), Infallible> { // TODO make specific error for bytes_used?