arceos_posix_api/imp/
pipe.rs1use alloc::sync::Arc;
2use core::ffi::c_int;
3
4use axerrno::{LinuxError, LinuxResult};
5use axio::PollState;
6use axsync::Mutex;
7
8use super::fd_ops::{FileLike, add_file_like, close_file_like};
9use crate::ctypes;
10
11#[derive(Copy, Clone, PartialEq)]
12enum RingBufferStatus {
13 Full,
14 Empty,
15 Normal,
16}
17
18const RING_BUFFER_SIZE: usize = 256;
19
20pub struct PipeRingBuffer {
21 arr: [u8; RING_BUFFER_SIZE],
22 head: usize,
23 tail: usize,
24 status: RingBufferStatus,
25}
26
27impl PipeRingBuffer {
28 pub const fn new() -> Self {
29 Self {
30 arr: [0; RING_BUFFER_SIZE],
31 head: 0,
32 tail: 0,
33 status: RingBufferStatus::Empty,
34 }
35 }
36
37 pub fn write_byte(&mut self, byte: u8) {
38 self.status = RingBufferStatus::Normal;
39 self.arr[self.tail] = byte;
40 self.tail = (self.tail + 1) % RING_BUFFER_SIZE;
41 if self.tail == self.head {
42 self.status = RingBufferStatus::Full;
43 }
44 }
45
46 pub fn read_byte(&mut self) -> u8 {
47 self.status = RingBufferStatus::Normal;
48 let c = self.arr[self.head];
49 self.head = (self.head + 1) % RING_BUFFER_SIZE;
50 if self.head == self.tail {
51 self.status = RingBufferStatus::Empty;
52 }
53 c
54 }
55
56 pub const fn available_read(&self) -> usize {
58 if matches!(self.status, RingBufferStatus::Empty) {
59 0
60 } else if self.tail > self.head {
61 self.tail - self.head
62 } else {
63 self.tail + RING_BUFFER_SIZE - self.head
64 }
65 }
66
67 pub const fn available_write(&self) -> usize {
69 if matches!(self.status, RingBufferStatus::Full) {
70 0
71 } else {
72 RING_BUFFER_SIZE - self.available_read()
73 }
74 }
75}
76
77pub struct Pipe {
78 readable: bool,
79 buffer: Arc<Mutex<PipeRingBuffer>>,
80}
81
82impl Pipe {
83 pub fn new() -> (Pipe, Pipe) {
84 let buffer = Arc::new(Mutex::new(PipeRingBuffer::new()));
85 let read_end = Pipe {
86 readable: true,
87 buffer: buffer.clone(),
88 };
89 let write_end = Pipe {
90 readable: false,
91 buffer,
92 };
93 (read_end, write_end)
94 }
95
96 pub const fn readable(&self) -> bool {
97 self.readable
98 }
99
100 pub const fn writable(&self) -> bool {
101 !self.readable
102 }
103
104 pub fn write_end_close(&self) -> bool {
105 Arc::strong_count(&self.buffer) == 1
106 }
107}
108
109impl FileLike for Pipe {
110 fn read(&self, buf: &mut [u8]) -> LinuxResult<usize> {
111 if !self.readable() {
112 return Err(LinuxError::EPERM);
113 }
114 let mut read_size = 0usize;
115 let max_len = buf.len();
116 loop {
117 let mut ring_buffer = self.buffer.lock();
118 let loop_read = ring_buffer.available_read();
119 if loop_read == 0 {
120 if self.write_end_close() {
121 return Ok(read_size);
122 }
123 drop(ring_buffer);
124 crate::sys_sched_yield(); continue;
127 }
128 for _ in 0..loop_read {
129 if read_size == max_len {
130 return Ok(read_size);
131 }
132 buf[read_size] = ring_buffer.read_byte();
133 read_size += 1;
134 }
135 }
136 }
137
138 fn write(&self, buf: &[u8]) -> LinuxResult<usize> {
139 if !self.writable() {
140 return Err(LinuxError::EPERM);
141 }
142 let mut write_size = 0usize;
143 let max_len = buf.len();
144 loop {
145 let mut ring_buffer = self.buffer.lock();
146 let loop_write = ring_buffer.available_write();
147 if loop_write == 0 {
148 drop(ring_buffer);
149 crate::sys_sched_yield(); continue;
152 }
153 for _ in 0..loop_write {
154 if write_size == max_len {
155 return Ok(write_size);
156 }
157 ring_buffer.write_byte(buf[write_size]);
158 write_size += 1;
159 }
160 }
161 }
162
163 fn stat(&self) -> LinuxResult<ctypes::stat> {
164 let st_mode = 0o10000 | 0o600u32; Ok(ctypes::stat {
166 st_ino: 1,
167 st_nlink: 1,
168 st_mode,
169 st_uid: 1000,
170 st_gid: 1000,
171 st_blksize: 4096,
172 ..Default::default()
173 })
174 }
175
176 fn into_any(self: Arc<Self>) -> Arc<dyn core::any::Any + Send + Sync> {
177 self
178 }
179
180 fn poll(&self) -> LinuxResult<PollState> {
181 let buf = self.buffer.lock();
182 Ok(PollState {
183 readable: self.readable() && buf.available_read() > 0,
184 writable: self.writable() && buf.available_write() > 0,
185 })
186 }
187
188 fn set_nonblocking(&self, _nonblocking: bool) -> LinuxResult {
189 Ok(())
190 }
191}
192
193pub fn sys_pipe(fds: &mut [c_int]) -> c_int {
197 debug!("sys_pipe <= {:#x}", fds.as_ptr() as usize);
198 syscall_body!(sys_pipe, {
199 if fds.len() != 2 {
200 return Err(LinuxError::EFAULT);
201 }
202
203 let (read_end, write_end) = Pipe::new();
204 let read_fd = add_file_like(Arc::new(read_end))?;
205 let write_fd = add_file_like(Arc::new(write_end)).inspect_err(|_| {
206 close_file_like(read_fd).ok();
207 })?;
208
209 fds[0] = read_fd as c_int;
210 fds[1] = write_fd as c_int;
211
212 Ok(0)
213 })
214}