xref: /DragonOS/kernel/src/net/event_poll/syscall.rs (revision f110d330d5493f383067b4e82ebbfb72f40457b2)
1 use crate::{
2     arch::ipc::signal::SigSet,
3     filesystem::vfs::file::FileMode,
4     ipc::signal::set_current_sig_blocked,
5     mm::VirtAddr,
6     syscall::{
7         user_access::{UserBufferReader, UserBufferWriter},
8         Syscall, SystemError,
9     },
10     time::TimeSpec,
11 };
12 
13 use super::{EPollCtlOption, EPollEvent, EventPoll};
14 
15 impl Syscall {
16     pub fn epoll_create(max_size: i32) -> Result<usize, SystemError> {
17         if max_size < 0 {
18             return Err(SystemError::EINVAL);
19         }
20 
21         return EventPoll::do_create_epoll(FileMode::empty());
22     }
23 
24     pub fn epoll_create1(flag: usize) -> Result<usize, SystemError> {
25         let flags = FileMode::from_bits_truncate(flag as u32);
26 
27         let ret = EventPoll::do_create_epoll(flags);
28         ret
29     }
30 
31     pub fn epoll_wait(
32         epfd: i32,
33         events: VirtAddr,
34         max_events: i32,
35         timeout: i32,
36     ) -> Result<usize, SystemError> {
37         if max_events <= 0 || max_events as u32 > EventPoll::EP_MAX_EVENTS {
38             return Err(SystemError::EINVAL);
39         }
40 
41         let mut timespec = None;
42         if timeout == 0 {
43             timespec = Some(TimeSpec::new(0, 0));
44         }
45 
46         if timeout > 0 {
47             let sec: i64 = timeout as i64 / 1000;
48             let nsec: i64 = 1000000 * (timeout as i64 % 1000);
49 
50             timespec = Some(TimeSpec::new(sec, nsec))
51         }
52 
53         // 从用户传入的地址中拿到epoll_events
54         let mut epds_writer = UserBufferWriter::new(
55             events.as_ptr::<EPollEvent>(),
56             max_events as usize * core::mem::size_of::<EPollEvent>(),
57             true,
58         )?;
59 
60         let epoll_events = epds_writer.buffer::<EPollEvent>(0)?;
61         return EventPoll::do_epoll_wait(epfd, epoll_events, max_events, timespec);
62     }
63 
64     pub fn epoll_ctl(epfd: i32, op: usize, fd: i32, event: VirtAddr) -> Result<usize, SystemError> {
65         let op = EPollCtlOption::from_op_num(op)?;
66         let mut epds = EPollEvent::default();
67         if op != EPollCtlOption::EpollCtlDel {
68             // 不为EpollCtlDel时不允许传入空指针
69             if event.is_null() {
70                 return Err(SystemError::EFAULT);
71             }
72 
73             // 还是一样的问题,C标准的epoll_event大小为12字节,而内核实现的epoll_event内存对齐后为16字节
74             // 这样分别拷贝其实和整体拷贝差别不大,内核使用内存对其版本甚至可能提升性能
75             let epds_reader = UserBufferReader::new(
76                 event.as_ptr::<EPollEvent>(),
77                 core::mem::size_of::<EPollEvent>(),
78                 true,
79             )?;
80 
81             // 拷贝到内核
82             epds_reader.copy_one_from_user(&mut epds, 0)?;
83         }
84 
85         return EventPoll::do_epoll_ctl(epfd, op, fd, &mut epds, false);
86     }
87 
88     /// ## 在epoll_wait时屏蔽某些信号
89     pub fn epoll_pwait(
90         epfd: i32,
91         epoll_event: VirtAddr,
92         max_events: i32,
93         timespec: i32,
94         mut sigmask: &mut SigSet,
95     ) -> Result<usize, SystemError> {
96         // 设置屏蔽的信号
97         set_current_sig_blocked(&mut sigmask);
98 
99         let wait_ret = Self::epoll_wait(epfd, epoll_event, max_events, timespec);
100 
101         if wait_ret.is_err() && *wait_ret.as_ref().unwrap_err() != SystemError::EINTR {
102             // TODO: 恢复信号?
103             // link:https://code.dragonos.org.cn/xref/linux-6.1.9/fs/eventpoll.c#2294
104         }
105         wait_ret
106     }
107 }
108