kernel/abi/linux/riscv64/
pipe.rs1use crate::{
5 abi::linux::riscv64::{
6 LinuxRiscv64Abi, errno,
7 fs::{FD_CLOEXEC, O_CLOEXEC, O_NONBLOCK},
8 },
9 arch::Trapframe,
10 ipc::UnidirectionalPipe,
11 object::capability::selectable::Selectable,
12 task::mytask,
13};
14
15pub fn sys_pipe2(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
17 let task = match mytask() {
18 Some(t) => t,
19 None => return errno::to_result(errno::EIO),
20 };
21
22 let pipefd_user = trapframe.get_arg(0);
23 let flags = trapframe.get_arg(1) as i32;
24
25 trapframe.increment_pc_next(task);
26
27 let allowed = O_CLOEXEC | O_NONBLOCK;
29 if flags & !allowed != 0 {
30 return errno::to_result(errno::EINVAL);
31 }
32
33 let pipefd_ptr = match task.vm_manager.translate_vaddr(pipefd_user) {
34 Some(ptr) => ptr as *mut u32,
35 None => return errno::to_result(errno::EFAULT),
36 };
37
38 let (read_end, write_end) = UnidirectionalPipe::create_pair(4096);
39
40 let read_handle = match task.handle_table.insert(read_end) {
41 Ok(h) => h,
42 Err(_) => return errno::to_result(errno::ENFILE),
43 };
44 let write_handle = match task.handle_table.insert(write_end) {
45 Ok(h) => h,
46 Err(_) => {
47 let _ = task.handle_table.remove(read_handle);
48 return errno::to_result(errno::ENFILE);
49 }
50 };
51
52 let read_fd = match abi.allocate_fd(read_handle as u32) {
53 Ok(fd) => fd,
54 Err(_) => {
55 let _ = task.handle_table.remove(read_handle);
56 let _ = task.handle_table.remove(write_handle);
57 return errno::to_result(errno::EMFILE);
58 }
59 };
60 let write_fd = match abi.allocate_fd(write_handle as u32) {
61 Ok(fd) => fd,
62 Err(_) => {
63 let _ = abi.remove_fd(read_fd);
64 let _ = task.handle_table.remove(read_handle);
65 let _ = task.handle_table.remove(write_handle);
66 return errno::to_result(errno::EMFILE);
67 }
68 };
69
70 let mut status_flags: u32 = 0;
71 if (flags & O_NONBLOCK) != 0 {
72 status_flags |= O_NONBLOCK as u32;
73 }
74
75 if abi.set_file_status_flags(read_fd, status_flags).is_err() {
76 let _ = abi.remove_fd(write_fd);
77 let _ = abi.remove_fd(read_fd);
78 let _ = task.handle_table.remove(write_handle);
79 let _ = task.handle_table.remove(read_handle);
80 return errno::to_result(errno::EMFILE);
81 }
82 if abi.set_file_status_flags(write_fd, status_flags).is_err() {
83 let _ = abi.remove_fd(write_fd);
84 let _ = abi.remove_fd(read_fd);
85 let _ = task.handle_table.remove(write_handle);
86 let _ = task.handle_table.remove(read_handle);
87 return errno::to_result(errno::EMFILE);
88 }
89
90 if (flags & O_CLOEXEC) != 0 {
91 let _ = abi.set_fd_flags(read_fd, FD_CLOEXEC);
92 let _ = abi.set_fd_flags(write_fd, FD_CLOEXEC);
93 }
94
95 if let Some(obj) = task.handle_table.get(read_handle) {
96 if let Some(sel) = obj.as_selectable() {
97 sel.set_nonblocking((flags & O_NONBLOCK) != 0);
98 }
99 }
100 if let Some(obj) = task.handle_table.get(write_handle) {
101 if let Some(sel) = obj.as_selectable() {
102 sel.set_nonblocking((flags & O_NONBLOCK) != 0);
103 }
104 }
105
106 unsafe {
107 core::ptr::write_unaligned(pipefd_ptr, read_fd as u32);
108 core::ptr::write_unaligned(pipefd_ptr.add(1), write_fd as u32);
109 }
110
111 0
112}