xref: /DragonOS/kernel/src/ipc/pipe.rs (revision 6b4e7a2972cc06663754c0e35a0e541987006fa4)
1 use crate::{
2     arch::{sched::sched, CurrentIrqArch},
3     exception::InterruptArch,
4     filesystem::vfs::{
5         core::generate_inode_id, file::FileMode, syscall::ModeType, FilePrivateData, FileSystem,
6         FileType, IndexNode, Metadata, PollStatus,
7     },
8     libs::{spinlock::SpinLock, wait_queue::WaitQueue},
9     process::ProcessState,
10     syscall::SystemError,
11     time::TimeSpec,
12 };
13 
14 use alloc::sync::{Arc, Weak};
15 
16 /// 我们设定pipe_buff的总大小为1024字节
17 const PIPE_BUFF_SIZE: usize = 1024;
18 
19 /// @brief 管道文件i节点(锁)
20 #[derive(Debug)]
21 pub struct LockedPipeInode(SpinLock<InnerPipeInode>);
22 
23 /// @brief 管道文件i节点(无锁)
24 #[derive(Debug)]
25 pub struct InnerPipeInode {
26     self_ref: Weak<LockedPipeInode>,
27     valid_cnt: i32,
28     read_pos: i32,
29     write_pos: i32,
30     read_wait_queue: WaitQueue,
31     write_wait_queue: WaitQueue,
32     data: [u8; PIPE_BUFF_SIZE],
33     /// INode 元数据
34     metadata: Metadata,
35     flags: FileMode,
36 }
37 
38 impl LockedPipeInode {
39     pub fn new(flags: FileMode) -> Arc<Self> {
40         let inner = InnerPipeInode {
41             self_ref: Weak::default(),
42             valid_cnt: 0,
43             read_pos: 0,
44             write_pos: 0,
45             read_wait_queue: WaitQueue::INIT,
46             write_wait_queue: WaitQueue::INIT,
47             data: [0; PIPE_BUFF_SIZE],
48 
49             metadata: Metadata {
50                 dev_id: 0,
51                 inode_id: generate_inode_id(),
52                 size: PIPE_BUFF_SIZE as i64,
53                 blk_size: 0,
54                 blocks: 0,
55                 atime: TimeSpec::default(),
56                 mtime: TimeSpec::default(),
57                 ctime: TimeSpec::default(),
58                 file_type: FileType::Pipe,
59                 mode: ModeType::from_bits_truncate(0o666),
60                 nlinks: 1,
61                 uid: 0,
62                 gid: 0,
63                 raw_dev: 0,
64             },
65             flags,
66         };
67         let result = Arc::new(Self(SpinLock::new(inner)));
68         let mut guard = result.0.lock();
69         guard.self_ref = Arc::downgrade(&result);
70         // 释放锁
71         drop(guard); //这一步其实不需要,只要离开作用域,guard生命周期结束,自会解锁
72         return result;
73     }
74 }
75 
76 impl IndexNode for LockedPipeInode {
77     fn read_at(
78         &self,
79         _offset: usize,
80         len: usize,
81         buf: &mut [u8],
82         _data: &mut FilePrivateData,
83     ) -> Result<usize, crate::syscall::SystemError> {
84         if buf.len() < len {
85             return Err(SystemError::EINVAL);
86         }
87         // 加锁
88         let mut inode = self.0.lock();
89 
90         // 如果管道里面没有数据,则唤醒写端,
91         while inode.valid_cnt == 0 {
92             inode
93                 .write_wait_queue
94                 .wakeup(Some(ProcessState::Blocked(true)));
95 
96             // 如果为非阻塞管道,直接返回错误
97             if inode.flags.contains(FileMode::O_NONBLOCK) {
98                 drop(inode);
99                 return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
100             }
101 
102             // 否则在读等待队列中睡眠,并释放锁
103             unsafe {
104                 let irq_guard = CurrentIrqArch::save_and_disable_irq();
105                 inode.read_wait_queue.sleep_without_schedule();
106                 drop(inode);
107 
108                 drop(irq_guard);
109             }
110             sched();
111             inode = self.0.lock();
112         }
113 
114         let mut num = inode.valid_cnt as usize;
115         //决定要输出的字节
116         let start = inode.read_pos as usize;
117         //如果读端希望读取的字节数大于有效字节数,则输出有效字节
118         let mut end = (inode.valid_cnt as usize + inode.read_pos as usize) % PIPE_BUFF_SIZE;
119         //如果读端希望读取的字节数少于有效字节数,则输出希望读取的字节
120         if len < inode.valid_cnt as usize {
121             end = (len + inode.read_pos as usize) % PIPE_BUFF_SIZE;
122             num = len;
123         }
124 
125         // 从管道拷贝数据到用户的缓冲区
126 
127         if end < start {
128             buf[0..(PIPE_BUFF_SIZE - start)].copy_from_slice(&inode.data[start..PIPE_BUFF_SIZE]);
129             buf[(PIPE_BUFF_SIZE - start)..num].copy_from_slice(&inode.data[0..end]);
130         } else {
131             buf[0..num].copy_from_slice(&inode.data[start..end]);
132         }
133 
134         //更新读位置以及valid_cnt
135         inode.read_pos = (inode.read_pos + num as i32) % PIPE_BUFF_SIZE as i32;
136         inode.valid_cnt -= num as i32;
137 
138         //读完后解锁并唤醒等待在写等待队列中的进程
139         inode
140             .write_wait_queue
141             .wakeup(Some(ProcessState::Blocked(true)));
142         //返回读取的字节数
143         return Ok(num);
144     }
145 
146     fn open(
147         &self,
148         _data: &mut FilePrivateData,
149         _mode: &crate::filesystem::vfs::file::FileMode,
150     ) -> Result<(), SystemError> {
151         return Ok(());
152     }
153 
154     fn metadata(&self) -> Result<crate::filesystem::vfs::Metadata, SystemError> {
155         let inode = self.0.lock();
156         let mut metadata = inode.metadata.clone();
157         metadata.size = inode.data.len() as i64;
158 
159         return Ok(metadata);
160     }
161 
162     fn close(&self, _data: &mut FilePrivateData) -> Result<(), SystemError> {
163         return Ok(());
164     }
165 
166     fn write_at(
167         &self,
168         _offset: usize,
169         len: usize,
170         buf: &[u8],
171         _data: &mut FilePrivateData,
172     ) -> Result<usize, crate::syscall::SystemError> {
173         if buf.len() < len || len > PIPE_BUFF_SIZE {
174             return Err(SystemError::EINVAL);
175         }
176         // 加锁
177 
178         let mut inode = self.0.lock();
179 
180         // 如果管道空间不够
181 
182         while len + inode.valid_cnt as usize > PIPE_BUFF_SIZE {
183             // 唤醒读端
184             inode
185                 .read_wait_queue
186                 .wakeup(Some(ProcessState::Blocked(true)));
187 
188             // 如果为非阻塞管道,直接返回错误
189             if inode.flags.contains(FileMode::O_NONBLOCK) {
190                 drop(inode);
191                 return Err(SystemError::ENOMEM);
192             }
193 
194             // 解锁并睡眠
195             unsafe {
196                 let irq_guard = CurrentIrqArch::save_and_disable_irq();
197                 inode.write_wait_queue.sleep_without_schedule();
198                 drop(inode);
199                 drop(irq_guard);
200             }
201             sched();
202             inode = self.0.lock();
203         }
204 
205         // 决定要输入的字节
206         let start = inode.write_pos as usize;
207         let end = (inode.write_pos as usize + len) % PIPE_BUFF_SIZE;
208         // 从用户的缓冲区拷贝数据到管道
209 
210         if end < start {
211             inode.data[start..PIPE_BUFF_SIZE].copy_from_slice(&buf[0..(PIPE_BUFF_SIZE - start)]);
212             inode.data[0..end].copy_from_slice(&buf[(PIPE_BUFF_SIZE - start)..len]);
213         } else {
214             inode.data[start..end].copy_from_slice(&buf[0..len]);
215         }
216         // 更新写位置以及valid_cnt
217         inode.write_pos = (inode.write_pos + len as i32) % PIPE_BUFF_SIZE as i32;
218         inode.valid_cnt += len as i32;
219 
220         // 读完后解锁并唤醒等待在读等待队列中的进程
221         inode
222             .read_wait_queue
223             .wakeup(Some(ProcessState::Blocked(true)));
224         // 返回写入的字节数
225         return Ok(len);
226     }
227 
228     fn poll(&self) -> Result<PollStatus, crate::syscall::SystemError> {
229         return Ok(PollStatus::READ | PollStatus::WRITE);
230     }
231 
232     fn as_any_ref(&self) -> &dyn core::any::Any {
233         self
234     }
235 
236     fn get_entry_name_and_metadata(
237         &self,
238         ino: crate::filesystem::vfs::InodeId,
239     ) -> Result<(alloc::string::String, crate::filesystem::vfs::Metadata), SystemError> {
240         // 如果有条件,请在文件系统中使用高效的方式实现本接口,而不是依赖这个低效率的默认实现。
241         let name = self.get_entry_name(ino)?;
242         let entry = self.find(&name)?;
243         return Ok((name, entry.metadata()?));
244     }
245 
246     fn fs(&self) -> Arc<(dyn FileSystem)> {
247         todo!()
248     }
249 
250     fn list(&self) -> Result<alloc::vec::Vec<alloc::string::String>, SystemError> {
251         return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
252     }
253 }
254