os/kernel/syscall/
ipc.rs

1//! IPC 相关的系统调用实现
2
3use alloc::sync::Arc;
4
5use crate::{
6    arch::trap::SumGuard,
7    kernel::{current_cpu, current_task},
8    vfs::{FdFlags, File, FsError, OpenFlags, PipeFile},
9};
10
11pub fn dup(oldfd: usize) -> isize {
12    let task = current_cpu().lock().current_task.as_ref().unwrap().clone();
13    match task.lock().fd_table.dup(oldfd) {
14        Ok(newfd) => newfd as isize,
15        Err(e) => e.to_errno(),
16    }
17}
18
19pub fn dup3(oldfd: usize, newfd: usize, flags: u32) -> isize {
20    let task = current_cpu().lock().current_task.as_ref().unwrap().clone();
21
22    let open_flags = match OpenFlags::from_bits(flags) {
23        Some(f) => f,
24        None => return FsError::InvalidArgument.to_errno(),
25    };
26
27    if open_flags.bits() & !OpenFlags::O_CLOEXEC.bits() != 0 {
28        return FsError::InvalidArgument.to_errno();
29    }
30
31    match task.lock().fd_table.dup3(oldfd, newfd, open_flags) {
32        Ok(newfd) => newfd as isize,
33        Err(e) => e.to_errno(),
34    }
35}
36
37pub fn pipe2(pipefd: *mut i32, flags: u32) -> isize {
38    if pipefd.is_null() {
39        return FsError::InvalidArgument.to_errno();
40    }
41
42    let valid_flags = OpenFlags::O_CLOEXEC | OpenFlags::O_NONBLOCK;
43    if flags & !valid_flags.bits() != 0 {
44        return FsError::InvalidArgument.to_errno();
45    }
46
47    let fd_flags =
48        FdFlags::from_open_flags(OpenFlags::from_bits(flags).unwrap_or(OpenFlags::empty()));
49
50    let (pipe_read, pipe_write) = PipeFile::create_pair();
51
52    // 获取当前任务的 FD 表
53    let fd_table = current_task().lock().fd_table.clone();
54
55    // 分配文件描述符
56    let read_fd =
57        match fd_table.alloc_with_flags(Arc::new(pipe_read) as Arc<dyn File>, fd_flags.clone()) {
58            Ok(fd) => fd,
59            Err(e) => return e.to_errno(),
60        };
61
62    let write_fd = match fd_table.alloc_with_flags(Arc::new(pipe_write) as Arc<dyn File>, fd_flags)
63    {
64        Ok(fd) => fd,
65        Err(e) => {
66            // 分配失败,需要回滚读端 FD
67            let _ = fd_table.close(read_fd);
68            return e.to_errno();
69        }
70    };
71
72    // 将 FD 写回用户空间
73    {
74        let _guard = SumGuard::new();
75        unsafe {
76            core::ptr::write(pipefd.offset(0), read_fd as i32);
77            core::ptr::write(pipefd.offset(1), write_fd as i32);
78        }
79    }
80
81    0
82}