strat9_kernel/vfs/
pipe.rs1use crate::{
8 sync::{waitqueue::WaitQueue, SpinLock},
9 syscall::error::SyscallError,
10};
11use alloc::sync::Arc;
12
13const PIPE_BUF_SIZE: usize = 4096;
14
15struct PipeInner {
17 buf: [u8; PIPE_BUF_SIZE],
18 read_pos: usize,
19 write_pos: usize,
20 len: usize,
22 read_closed: bool,
23 write_closed: bool,
24 read_refs: usize,
27 write_refs: usize,
29}
30
31impl PipeInner {
32 fn new() -> Self {
34 PipeInner {
35 buf: [0u8; PIPE_BUF_SIZE],
36 read_pos: 0,
37 write_pos: 0,
38 len: 0,
39 read_closed: false,
40 write_closed: false,
41 read_refs: 1,
42 write_refs: 1,
43 }
44 }
45
46 #[allow(dead_code)]
48 fn is_empty(&self) -> bool {
49 self.len == 0
50 }
51
52 #[allow(dead_code)]
54 fn is_full(&self) -> bool {
55 self.len >= PIPE_BUF_SIZE
56 }
57
58 fn available_read(&self) -> usize {
60 self.len
61 }
62
63 fn available_write(&self) -> usize {
65 PIPE_BUF_SIZE - self.len
66 }
67}
68
69pub struct Pipe {
71 inner: SpinLock<PipeInner>,
72 readers: WaitQueue,
74 writers: WaitQueue,
76}
77
78impl Pipe {
79 pub fn new() -> Arc<Self> {
81 Arc::new(Pipe {
82 inner: SpinLock::new(PipeInner::new()),
83 readers: WaitQueue::new(),
84 writers: WaitQueue::new(),
85 })
86 }
87
88 pub fn read(&self, buf: &mut [u8]) -> Result<usize, SyscallError> {
90 loop {
91 {
93 let mut inner = self.inner.lock();
94 if inner.available_read() > 0 {
95 let to_read = core::cmp::min(buf.len(), inner.available_read());
96 for i in 0..to_read {
97 buf[i] = inner.buf[inner.read_pos];
98 inner.read_pos = (inner.read_pos + 1) % PIPE_BUF_SIZE;
99 }
100 inner.len -= to_read;
101 self.writers.wake_one();
102 return Ok(to_read);
103 }
104 if inner.write_closed {
105 return Ok(0); }
107 }
108
109 let result = self.readers.wait_until(|| {
114 let inner = self.inner.lock();
115 if inner.available_read() > 0 {
116 return Some(true);
117 }
118 if inner.write_closed {
119 return Some(false);
120 }
121 None
122 });
123
124 match result {
125 true => {
126 continue;
128 }
129 false => {
130 return Ok(0);
132 } }
135 }
136 }
137
138 pub fn write(&self, buf: &[u8]) -> Result<usize, SyscallError> {
140 if buf.is_empty() {
141 return Ok(0);
142 }
143
144 let mut total = 0;
145 while total < buf.len() {
146 let wrote_some = self.writers.wait_until(|| {
147 let mut inner = self.inner.lock();
148
149 if inner.read_closed {
150 if total > 0 {
151 return Some(Ok(0)); }
153 return Some(Err(SyscallError::Pipe));
154 }
155
156 if inner.available_write() > 0 {
157 let to_write = core::cmp::min(buf.len() - total, inner.available_write());
158 for i in 0..to_write {
159 let wp = inner.write_pos;
160 inner.buf[wp] = buf[total + i];
161 inner.write_pos = (wp + 1) % PIPE_BUF_SIZE;
162 }
163 inner.len += to_write;
164 return Some(Ok(to_write));
165 }
166
167 None });
169 self.readers.wake_one();
170 let n = wrote_some?;
171 if n == 0 {
172 break; }
174 total += n;
175 }
176
177 Ok(total)
178 }
179
180 pub fn dup_read(&self) {
182 self.inner.lock().read_refs += 1;
183 }
184
185 pub fn dup_write(&self) {
187 self.inner.lock().write_refs += 1;
188 }
189
190 pub fn close_read(&self) -> bool {
193 let mut inner = self.inner.lock();
194 if inner.read_refs == 0 {
195 return false;
196 }
197 inner.read_refs -= 1;
198 if inner.read_refs == 0 {
199 inner.read_closed = true;
200 drop(inner);
201 self.writers.wake_all();
202 true
203 } else {
204 false
205 }
206 }
207
208 pub fn close_write(&self) -> bool {
211 let mut inner = self.inner.lock();
212 if inner.write_refs == 0 {
213 return false;
214 }
215 inner.write_refs -= 1;
216 if inner.write_refs == 0 {
217 inner.write_closed = true;
218 drop(inner);
219 self.readers.wake_all();
220 true
221 } else {
222 false
223 }
224 }
225}
226
227use super::scheme::{
232 finalize_pseudo_stat, DirEntry, FileStat, OpenFlags, OpenResult, Scheme, DEV_PIPEFS,
233};
234use alloc::{collections::BTreeMap, vec::Vec};
235use core::sync::atomic::{AtomicU64, Ordering};
236
237pub struct PipeScheme {
241 pipes: SpinLock<BTreeMap<u64, Arc<Pipe>>>,
242}
243
244static NEXT_PIPE_ID: AtomicU64 = AtomicU64::new(2); impl PipeScheme {
247 pub fn new() -> Self {
249 PipeScheme {
250 pipes: SpinLock::new(BTreeMap::new()),
251 }
252 }
253
254 pub fn create_pipe(&self) -> (u64, Arc<Pipe>) {
256 let base_id = NEXT_PIPE_ID.fetch_add(2, Ordering::SeqCst);
257 let pipe = Pipe::new();
258 self.pipes.lock().insert(base_id, pipe.clone());
259 (base_id, pipe)
260 }
261
262 fn get_pipe(&self, file_id: u64) -> Result<Arc<Pipe>, SyscallError> {
264 let base = file_id & !1; self.pipes
266 .lock()
267 .get(&base)
268 .cloned()
269 .ok_or(SyscallError::BadHandle)
270 }
271
272 fn is_read_end(file_id: u64) -> bool {
274 file_id & 1 == 0
275 }
276}
277
278impl Scheme for PipeScheme {
279 fn open(&self, _path: &str, _flags: OpenFlags) -> Result<OpenResult, SyscallError> {
281 Err(SyscallError::NotSupported) }
283
284 fn read(&self, file_id: u64, _offset: u64, buf: &mut [u8]) -> Result<usize, SyscallError> {
286 if !Self::is_read_end(file_id) {
287 return Err(SyscallError::PermissionDenied);
288 }
289 let pipe = self.get_pipe(file_id)?;
290 pipe.read(buf)
291 }
292
293 fn write(&self, file_id: u64, _offset: u64, buf: &[u8]) -> Result<usize, SyscallError> {
295 if Self::is_read_end(file_id) {
296 return Err(SyscallError::PermissionDenied);
297 }
298 let pipe = self.get_pipe(file_id)?;
299 pipe.write(buf)
300 }
301
302 fn close(&self, file_id: u64) -> Result<(), SyscallError> {
304 let pipe = self.get_pipe(file_id)?;
305 if Self::is_read_end(file_id) {
306 pipe.close_read();
307 } else {
308 pipe.close_write();
309 }
310
311 let base = file_id & !1;
314 let inner = pipe.inner.lock();
315 if inner.read_closed && inner.write_closed {
316 drop(inner);
317 self.pipes.lock().remove(&base);
318 }
319 Ok(())
320 }
321
322 fn stat(&self, file_id: u64) -> Result<FileStat, SyscallError> {
324 let pipe = self.get_pipe(file_id)?;
325 let inner = pipe.inner.lock();
326 Ok(finalize_pseudo_stat(
327 FileStat {
328 st_ino: file_id,
329 st_mode: 0o010600, st_nlink: 1,
331 st_size: inner.len as u64,
332 st_blksize: PIPE_BUF_SIZE as u64,
333 st_blocks: 0,
334 ..FileStat::zeroed()
335 },
336 DEV_PIPEFS,
337 0,
338 ))
339 }
340
341 fn readdir(&self, _file_id: u64) -> Result<Vec<DirEntry>, SyscallError> {
343 Err(SyscallError::InvalidArgument)
344 }
345
346 fn size(&self, file_id: u64) -> Result<u64, SyscallError> {
348 let pipe = self.get_pipe(file_id)?;
349 let len = pipe.inner.lock().len;
350 Ok(len as u64)
351 }
352}