1use core::ops::{Deref, DerefMut};
2
3use alloc::{
4 collections::VecDeque,
5 sync::{Arc, Weak},
6};
7use spin::Mutex;
8
9use crate::{DArray, DeviceDma, DmaDirection, DmaError};
10
11#[derive(Clone, Debug)]
12pub(crate) struct DArrayConfig {
13 pub size: usize,
14 pub align: usize,
15 pub direction: DmaDirection,
16}
17
18#[derive(Clone)]
19pub struct DArrayPool {
20 inner: Arc<Mutex<Inner>>,
21}
22
23pub struct DBuff {
24 data: Option<DArray<u8>>,
25 pool: Weak<Mutex<Inner>>,
26}
27
28unsafe impl Send for DBuff {}
29
30impl Deref for DBuff {
31 type Target = DArray<u8>;
32
33 fn deref(&self) -> &Self::Target {
34 self.data.as_ref().unwrap()
35 }
36}
37
38impl DerefMut for DBuff {
39 fn deref_mut(&mut self) -> &mut Self::Target {
40 self.data.as_mut().unwrap()
41 }
42}
43
44impl Drop for DBuff {
45 fn drop(&mut self) {
46 if let Some(data) = self.data.take()
47 && let Some(pool) = self.pool.upgrade()
48 {
49 let mut inner = pool.lock();
50 inner.dealloc(data);
51 }
52 }
53}
54
55struct Inner {
56 dev: DeviceDma,
57 config: DArrayConfig,
58 pool: VecDeque<DArray<u8>>,
59}
60
61impl Inner {
62 fn alloc(&mut self) -> Option<DArray<u8>> {
63 self.pool.pop_front()
64 }
65
66 fn dealloc(&mut self, dvec: DArray<u8>) {
67 self.pool.push_back(dvec);
68 }
69}
70
71impl DArrayPool {
72 pub(crate) fn new_pool(dev: DeviceDma, config: DArrayConfig, cap: usize) -> DArrayPool {
73 let mut pool = VecDeque::with_capacity(cap);
74 for _ in 0..cap {
75 if let Ok(dvec) =
76 DArray::new_zero_with_align(
78 &dev,
79 config.size,
80 config.align,
81 config.direction,
82 )
83 {
84 pool.push_back(dvec);
85 }
86 }
87
88 DArrayPool {
89 inner: Arc::new(Mutex::new(Inner { dev, pool, config })),
90 }
91 }
92
93 pub fn alloc(&self) -> Result<DBuff, DmaError> {
94 let config;
95 let dev;
96 {
97 let mut inner = self.inner.lock();
98 if let Some(dvec) = inner.alloc() {
99 return Ok(DBuff {
100 data: Some(dvec),
101 pool: Arc::downgrade(&self.inner),
102 });
103 } else {
104 config = inner.config.clone();
105 dev = inner.dev.clone();
106 }
107 };
108
109 let dvec = DArray::new_zero_with_align(&dev, config.size, config.align, config.direction)?;
110 Ok(DBuff {
111 data: Some(dvec),
112 pool: Arc::downgrade(&self.inner),
113 })
114 }
115}