1 use super::BufferHandles; 2 use crate::ioctl; 3 4 use std::sync::{ 5 atomic::{AtomicUsize, Ordering}, 6 Arc, Mutex, 7 }; 8 9 /// Represents the current state of an allocated buffer. 10 pub(super) enum BufferState<P: BufferHandles> { 11 /// The buffer can be obtained via `get_buffer()` and be queued. 12 Free, 13 /// The buffer has been requested via `get_buffer()` but is not queued yet. 14 PreQueue, 15 /// The buffer is queued and waiting to be dequeued. 16 Queued(P), 17 /// The buffer has been dequeued and the client is still using it. The buffer 18 /// will go back to the `Free` state once the reference is dropped. 19 Dequeued, 20 } 21 22 /// Structure that allows a queue and its users to keep track of how many buffers are available for 23 /// use and currently queued. 24 #[derive(Default)] 25 pub(super) struct BufferStats { 26 num_free: AtomicUsize, 27 num_queued: AtomicUsize, 28 } 29 30 impl BufferStats { 31 /// Create a new tracker for buffer stats. The stats are initially empty, so this structure 32 /// must be passed to `BufferInfo::new` for the buffer to be initially registered. new() -> Self33 pub fn new() -> Self { 34 Self { 35 num_free: AtomicUsize::new(0), 36 num_queued: AtomicUsize::new(0), 37 } 38 } 39 num_free(&self) -> usize40 pub fn num_free(&self) -> usize { 41 self.num_free.load(Ordering::Relaxed) 42 } 43 num_queued(&self) -> usize44 pub fn num_queued(&self) -> usize { 45 self.num_queued.load(Ordering::Relaxed) 46 } 47 } 48 49 pub(super) struct BufferInfo<P: BufferHandles> { 50 /// Static information about the buffer, obtains from V4L2's `QUERYBUF` ioctl. 51 pub(super) features: ioctl::QueryBuffer, 52 /// Current state of the buffer. 53 state: Mutex<BufferState<P>>, 54 /// Link to the queue's buffer stats, so we can update them as the buffer state changes. 55 stats: Arc<BufferStats>, 56 } 57 58 impl<P: BufferHandles> Drop for BufferInfo<P> { drop(&mut self)59 fn drop(&mut self) { 60 self.stats.num_free.fetch_sub(1, Ordering::Relaxed); 61 } 62 } 63 64 impl<P: BufferHandles> BufferInfo<P> { new(features: ioctl::QueryBuffer, stats: Arc<BufferStats>) -> Self65 pub(super) fn new(features: ioctl::QueryBuffer, stats: Arc<BufferStats>) -> Self { 66 stats.num_free.fetch_add(1, Ordering::Relaxed); 67 Self { 68 state: Mutex::new(BufferState::Free), 69 features, 70 stats: Arc::clone(&stats), 71 } 72 } 73 74 /// Do something with the buffer's state. The state is provided read-only and thus cannot be 75 /// modified. do_with_state<R, F: FnOnce(&BufferState<P>) -> R>(&self, f: F) -> R76 pub(super) fn do_with_state<R, F: FnOnce(&BufferState<P>) -> R>(&self, f: F) -> R { 77 f(&*self.state.lock().unwrap()) 78 } 79 80 /// Update the buffer's state. The queue's stats will be updated to reflect the new state 81 /// decided by `f`. update_state<R, F: FnOnce(&mut BufferState<P>) -> R>(&self, f: F) -> R82 pub(super) fn update_state<R, F: FnOnce(&mut BufferState<P>) -> R>(&self, f: F) -> R { 83 let mut state = self.state.lock().unwrap(); 84 match *state { 85 BufferState::Free => self.stats.num_free.fetch_sub(1, Ordering::Relaxed), 86 BufferState::Queued(_) => self.stats.num_queued.fetch_sub(1, Ordering::Relaxed), 87 _ => 0, 88 }; 89 90 // Let the provided closure decide the new state. 91 let res = f(&mut *state); 92 93 match *state { 94 BufferState::Free => self.stats.num_free.fetch_add(1, Ordering::Relaxed), 95 BufferState::Queued(_) => self.stats.num_queued.fetch_add(1, Ordering::Relaxed), 96 _ => 0, 97 }; 98 99 res 100 } 101 } 102 103 #[cfg(test)] 104 mod tests { 105 use crate::memory::MmapHandle; 106 107 use super::*; 108 109 #[test] test_buffer_state_update()110 fn test_buffer_state_update() { 111 const NUM_BUFFERS: usize = 5; 112 113 let buffer_stats = Arc::new(BufferStats::new()); 114 assert_eq!(buffer_stats.num_free(), 0); 115 assert_eq!(buffer_stats.num_queued(), 0); 116 117 let buffers = (0..NUM_BUFFERS) 118 .map(|i| { 119 let querybuf = ioctl::QueryBuffer { 120 index: i, 121 flags: ioctl::BufferFlags::empty(), 122 planes: Default::default(), 123 }; 124 let buffer: BufferInfo<Vec<MmapHandle>> = 125 BufferInfo::new(querybuf, Arc::clone(&buffer_stats)); 126 assert_eq!(buffer_stats.num_free(), i + 1); 127 assert_eq!(buffer_stats.num_queued(), 0); 128 129 buffer 130 }) 131 .collect::<Vec<BufferInfo<Vec<MmapHandle>>>>(); 132 133 buffers[0].update_state(|s| { 134 let _ = std::mem::replace(&mut *s, BufferState::PreQueue); 135 }); 136 assert_eq!(buffer_stats.num_free(), NUM_BUFFERS - 1); 137 assert_eq!(buffer_stats.num_queued(), 0); 138 139 buffers[1].update_state(|s| { 140 let _ = std::mem::replace(&mut *s, BufferState::PreQueue); 141 }); 142 assert_eq!(buffer_stats.num_free(), NUM_BUFFERS - 2); 143 assert_eq!(buffer_stats.num_queued(), 0); 144 145 buffers[0].update_state(|s| { 146 let _ = std::mem::replace(&mut *s, BufferState::Queued(Default::default())); 147 }); 148 assert_eq!(buffer_stats.num_free(), NUM_BUFFERS - 2); 149 assert_eq!(buffer_stats.num_queued(), 1); 150 151 buffers[2].update_state(|s| { 152 let _ = std::mem::replace(&mut *s, BufferState::Queued(Default::default())); 153 }); 154 assert_eq!(buffer_stats.num_free(), NUM_BUFFERS - 3); 155 assert_eq!(buffer_stats.num_queued(), 2); 156 157 buffers[2].update_state(|s| { 158 let _ = std::mem::replace(&mut *s, BufferState::Free); 159 }); 160 assert_eq!(buffer_stats.num_free(), NUM_BUFFERS - 2); 161 assert_eq!(buffer_stats.num_queued(), 1); 162 163 buffers[0].update_state(|s| { 164 let _ = std::mem::replace(&mut *s, BufferState::Dequeued); 165 }); 166 assert_eq!(buffer_stats.num_free(), NUM_BUFFERS - 2); 167 assert_eq!(buffer_stats.num_queued(), 0); 168 169 buffers[0].update_state(|s| { 170 let _ = std::mem::replace(&mut *s, BufferState::Free); 171 }); 172 assert_eq!(buffer_stats.num_free(), NUM_BUFFERS - 1); 173 assert_eq!(buffer_stats.num_queued(), 0); 174 175 buffers[1].update_state(|s| { 176 let _ = std::mem::replace(&mut *s, BufferState::Free); 177 }); 178 assert_eq!(buffer_stats.num_free(), NUM_BUFFERS); 179 assert_eq!(buffer_stats.num_queued(), 0); 180 } 181 } 182