1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 use std::io;
15 use std::os::raw::{c_int, c_uint};
16 use std::sync::atomic::{AtomicUsize, Ordering};
17 use std::time::Duration;
18
19 use crate::{Events, Interest, Token};
20
21 static NEXT_ID: AtomicUsize = AtomicUsize::new(1);
22
23 /// An wrapper to block different OS polling system.
24 /// Linux: epoll
25 /// Windows: iocp
26 pub struct Selector {
27 // selector id
28 id: usize,
29 // epoll fd
30 ep: i32,
31 }
32
33 impl Selector {
34 /// Creates a new Selector.
35 ///
36 /// # Error
37 /// If the underlying syscall fails, returns the corresponding error.
new() -> io::Result<Selector>38 pub fn new() -> io::Result<Selector> {
39 let ep = match syscall!(epoll_create1(libc::EPOLL_CLOEXEC)) {
40 Ok(ep_sys) => ep_sys,
41 Err(err) => {
42 return Err(err);
43 }
44 };
45
46 Ok(Selector {
47 id: NEXT_ID.fetch_add(1, Ordering::Relaxed),
48 ep,
49 })
50 }
51
52 /// Waits for io events to come within a time limit.
select(&self, events: &mut Events, timeout: Option<Duration>) -> io::Result<()>53 pub fn select(&self, events: &mut Events, timeout: Option<Duration>) -> io::Result<()> {
54 // Convert to milliseconds, if input time is none, it means the timeout is -1
55 // and wait permanently.
56 let timeout = timeout.map(|time| time.as_millis() as c_int).unwrap_or(-1);
57
58 events.clear();
59
60 match syscall!(epoll_wait(
61 self.ep,
62 events.as_mut_ptr(),
63 events.capacity() as i32,
64 timeout
65 )) {
66 Ok(n_events) => unsafe { events.set_len(n_events as usize) },
67 Err(err) => {
68 return Err(err);
69 }
70 }
71 Ok(())
72 }
73
74 /// Registers the fd with specific interested events
register(&self, fd: i32, token: Token, interests: Interest) -> io::Result<()>75 pub fn register(&self, fd: i32, token: Token, interests: Interest) -> io::Result<()> {
76 let mut sys_event = libc::epoll_event {
77 events: interests_to_io_event(interests),
78 u64: usize::from(token) as u64,
79 };
80
81 match syscall!(epoll_ctl(self.ep, libc::EPOLL_CTL_ADD, fd, &mut sys_event)) {
82 Ok(_) => Ok(()),
83 Err(err) => Err(err),
84 }
85 }
86
87 /// Re-registers the fd with specific interested events
reregister(&self, fd: i32, token: Token, interests: Interest) -> io::Result<()>88 pub fn reregister(&self, fd: i32, token: Token, interests: Interest) -> io::Result<()> {
89 let mut sys_event = libc::epoll_event {
90 events: interests_to_io_event(interests),
91 u64: usize::from(token) as u64,
92 };
93
94 match syscall!(epoll_ctl(self.ep, libc::EPOLL_CTL_MOD, fd, &mut sys_event)) {
95 Ok(_) => Ok(()),
96 Err(err) => Err(err),
97 }
98 }
99
100 /// De-registers the fd.
deregister(&self, fd: i32) -> io::Result<()>101 pub fn deregister(&self, fd: i32) -> io::Result<()> {
102 match syscall!(epoll_ctl(
103 self.ep,
104 libc::EPOLL_CTL_DEL,
105 fd,
106 std::ptr::null_mut() as *mut libc::epoll_event
107 )) {
108 Ok(_) => Ok(()),
109 Err(err) => Err(err),
110 }
111 }
112 }
113
interests_to_io_event(interests: Interest) -> c_uint114 fn interests_to_io_event(interests: Interest) -> c_uint {
115 let mut io_event = libc::EPOLLET as u32;
116
117 if interests.is_readable() {
118 io_event |= libc::EPOLLIN as u32;
119 io_event |= libc::EPOLLRDHUP as u32;
120 }
121
122 if interests.is_writable() {
123 io_event |= libc::EPOLLOUT as u32;
124 }
125
126 io_event as c_uint
127 }
128
129 impl Drop for Selector {
drop(&mut self)130 fn drop(&mut self) {
131 if let Err(_err) = syscall!(close(self.ep)) {
132 // todo: log the error
133 }
134 }
135 }
136
137 impl std::fmt::Debug for Selector {
fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result138 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139 write!(fmt, "epoll fd: {}, Select id: {}", self.ep, self.id)
140 }
141 }
142