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