• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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