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