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