1cac7dca0Sopenharmony_ci// Copyright (c) 2023 Huawei Device Co., Ltd. 2cac7dca0Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License"); 3cac7dca0Sopenharmony_ci// you may not use this file except in compliance with the License. 4cac7dca0Sopenharmony_ci// You may obtain a copy of the License at 5cac7dca0Sopenharmony_ci// 6cac7dca0Sopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0 7cac7dca0Sopenharmony_ci// 8cac7dca0Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software 9cac7dca0Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS, 10cac7dca0Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11cac7dca0Sopenharmony_ci// See the License for the specific language governing permissions and 12cac7dca0Sopenharmony_ci// limitations under the License. 13cac7dca0Sopenharmony_ci 14cac7dca0Sopenharmony_ciuse std::io; 15cac7dca0Sopenharmony_ciuse std::os::raw::c_int; 16cac7dca0Sopenharmony_ciuse std::sync::atomic::{AtomicUsize, Ordering}; 17cac7dca0Sopenharmony_ciuse std::time::Duration; 18cac7dca0Sopenharmony_ci 19cac7dca0Sopenharmony_ciuse crate::{EventTrait, Interest, Token}; 20cac7dca0Sopenharmony_ci 21cac7dca0Sopenharmony_cistatic NEXT_ID: AtomicUsize = AtomicUsize::new(1); 22cac7dca0Sopenharmony_ci 23cac7dca0Sopenharmony_ci/// An wrapper for different OS polling system. 24cac7dca0Sopenharmony_ci/// Linux: epoll 25cac7dca0Sopenharmony_ci/// Windows: iocp 26cac7dca0Sopenharmony_ci/// macos: kqueue 27cac7dca0Sopenharmony_cipub struct Selector { 28cac7dca0Sopenharmony_ci // selector id 29cac7dca0Sopenharmony_ci id: usize, 30cac7dca0Sopenharmony_ci // epoll fd 31cac7dca0Sopenharmony_ci ep: i32, 32cac7dca0Sopenharmony_ci} 33cac7dca0Sopenharmony_ci 34cac7dca0Sopenharmony_ciimpl Selector { 35cac7dca0Sopenharmony_ci /// Creates a new Selector. 36cac7dca0Sopenharmony_ci /// 37cac7dca0Sopenharmony_ci /// # Error 38cac7dca0Sopenharmony_ci /// If the underlying syscall fails, returns the corresponding error. 39cac7dca0Sopenharmony_ci pub fn new() -> io::Result<Selector> { 40cac7dca0Sopenharmony_ci let ep = match syscall!(epoll_create1(libc::EPOLL_CLOEXEC)) { 41cac7dca0Sopenharmony_ci Ok(ep_sys) => ep_sys, 42cac7dca0Sopenharmony_ci Err(err) => { 43cac7dca0Sopenharmony_ci return Err(err); 44cac7dca0Sopenharmony_ci } 45cac7dca0Sopenharmony_ci }; 46cac7dca0Sopenharmony_ci 47cac7dca0Sopenharmony_ci Ok(Selector { 48cac7dca0Sopenharmony_ci id: NEXT_ID.fetch_add(1, Ordering::Relaxed), 49cac7dca0Sopenharmony_ci ep, 50cac7dca0Sopenharmony_ci }) 51cac7dca0Sopenharmony_ci } 52cac7dca0Sopenharmony_ci 53cac7dca0Sopenharmony_ci /// Waits for io events to come within a time limit. 54cac7dca0Sopenharmony_ci pub fn select(&self, events: &mut Events, timeout: Option<Duration>) -> io::Result<()> { 55cac7dca0Sopenharmony_ci // Convert to milliseconds, if input time is none, it means the timeout is -1 56cac7dca0Sopenharmony_ci // and wait permanently. 57cac7dca0Sopenharmony_ci let timeout = timeout.map(|time| time.as_millis() as c_int).unwrap_or(-1); 58cac7dca0Sopenharmony_ci 59cac7dca0Sopenharmony_ci events.clear(); 60cac7dca0Sopenharmony_ci 61cac7dca0Sopenharmony_ci match syscall!(epoll_wait( 62cac7dca0Sopenharmony_ci self.ep, 63cac7dca0Sopenharmony_ci events.as_mut_ptr(), 64cac7dca0Sopenharmony_ci events.capacity() as i32, 65cac7dca0Sopenharmony_ci timeout 66cac7dca0Sopenharmony_ci )) { 67cac7dca0Sopenharmony_ci Ok(n_events) => unsafe { events.set_len(n_events as usize) }, 68cac7dca0Sopenharmony_ci Err(err) => { 69cac7dca0Sopenharmony_ci return Err(err); 70cac7dca0Sopenharmony_ci } 71cac7dca0Sopenharmony_ci } 72cac7dca0Sopenharmony_ci Ok(()) 73cac7dca0Sopenharmony_ci } 74cac7dca0Sopenharmony_ci 75cac7dca0Sopenharmony_ci /// Registers the fd with specific interested events 76cac7dca0Sopenharmony_ci pub fn register(&self, fd: i32, token: Token, interests: Interest) -> io::Result<()> { 77cac7dca0Sopenharmony_ci let mut sys_event = libc::epoll_event { 78cac7dca0Sopenharmony_ci events: interests.into_io_event(), 79cac7dca0Sopenharmony_ci u64: usize::from(token) as u64, 80cac7dca0Sopenharmony_ci }; 81cac7dca0Sopenharmony_ci 82cac7dca0Sopenharmony_ci match syscall!(epoll_ctl(self.ep, libc::EPOLL_CTL_ADD, fd, &mut sys_event)) { 83cac7dca0Sopenharmony_ci Ok(_) => Ok(()), 84cac7dca0Sopenharmony_ci Err(err) => Err(err), 85cac7dca0Sopenharmony_ci } 86cac7dca0Sopenharmony_ci } 87cac7dca0Sopenharmony_ci 88cac7dca0Sopenharmony_ci /// Re-registers the fd with specific interested events 89cac7dca0Sopenharmony_ci pub fn reregister(&self, fd: i32, token: Token, interests: Interest) -> io::Result<()> { 90cac7dca0Sopenharmony_ci let mut sys_event = libc::epoll_event { 91cac7dca0Sopenharmony_ci events: interests.into_io_event(), 92cac7dca0Sopenharmony_ci u64: usize::from(token) as u64, 93cac7dca0Sopenharmony_ci }; 94cac7dca0Sopenharmony_ci 95cac7dca0Sopenharmony_ci match syscall!(epoll_ctl(self.ep, libc::EPOLL_CTL_MOD, fd, &mut sys_event)) { 96cac7dca0Sopenharmony_ci Ok(_) => Ok(()), 97cac7dca0Sopenharmony_ci Err(err) => Err(err), 98cac7dca0Sopenharmony_ci } 99cac7dca0Sopenharmony_ci } 100cac7dca0Sopenharmony_ci 101cac7dca0Sopenharmony_ci /// De-registers the fd. 102cac7dca0Sopenharmony_ci pub fn deregister(&self, fd: i32) -> io::Result<()> { 103cac7dca0Sopenharmony_ci match syscall!(epoll_ctl( 104cac7dca0Sopenharmony_ci self.ep, 105cac7dca0Sopenharmony_ci libc::EPOLL_CTL_DEL, 106cac7dca0Sopenharmony_ci fd, 107cac7dca0Sopenharmony_ci std::ptr::null_mut() 108cac7dca0Sopenharmony_ci )) { 109cac7dca0Sopenharmony_ci Ok(_) => Ok(()), 110cac7dca0Sopenharmony_ci Err(err) => Err(err), 111cac7dca0Sopenharmony_ci } 112cac7dca0Sopenharmony_ci } 113cac7dca0Sopenharmony_ci} 114cac7dca0Sopenharmony_ci 115cac7dca0Sopenharmony_ciimpl Drop for Selector { 116cac7dca0Sopenharmony_ci fn drop(&mut self) { 117cac7dca0Sopenharmony_ci if let Err(_err) = syscall!(close(self.ep)) { 118cac7dca0Sopenharmony_ci // todo: log the error 119cac7dca0Sopenharmony_ci } 120cac7dca0Sopenharmony_ci } 121cac7dca0Sopenharmony_ci} 122cac7dca0Sopenharmony_ci 123cac7dca0Sopenharmony_ciimpl std::fmt::Debug for Selector { 124cac7dca0Sopenharmony_ci fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 125cac7dca0Sopenharmony_ci write!(fmt, "epoll fd: {}, Select id: {}", self.ep, self.id) 126cac7dca0Sopenharmony_ci } 127cac7dca0Sopenharmony_ci} 128cac7dca0Sopenharmony_ci 129cac7dca0Sopenharmony_ci/// A vector of events 130cac7dca0Sopenharmony_cipub type Events = Vec<Event>; 131cac7dca0Sopenharmony_ci 132cac7dca0Sopenharmony_ci/// An io event 133cac7dca0Sopenharmony_cipub type Event = libc::epoll_event; 134cac7dca0Sopenharmony_ci 135cac7dca0Sopenharmony_ciimpl EventTrait for Event { 136cac7dca0Sopenharmony_ci fn token(&self) -> Token { 137cac7dca0Sopenharmony_ci Token(self.u64 as usize) 138cac7dca0Sopenharmony_ci } 139cac7dca0Sopenharmony_ci 140cac7dca0Sopenharmony_ci fn is_readable(&self) -> bool { 141cac7dca0Sopenharmony_ci (self.events as libc::c_int & libc::EPOLLIN) != 0 142cac7dca0Sopenharmony_ci || (self.events as libc::c_int & libc::EPOLLPRI) != 0 143cac7dca0Sopenharmony_ci } 144cac7dca0Sopenharmony_ci 145cac7dca0Sopenharmony_ci fn is_writable(&self) -> bool { 146cac7dca0Sopenharmony_ci (self.events as libc::c_int & libc::EPOLLOUT) != 0 147cac7dca0Sopenharmony_ci } 148cac7dca0Sopenharmony_ci 149cac7dca0Sopenharmony_ci fn is_read_closed(&self) -> bool { 150cac7dca0Sopenharmony_ci self.events as libc::c_int & libc::EPOLLHUP != 0 151cac7dca0Sopenharmony_ci || (self.events as libc::c_int & libc::EPOLLIN != 0 152cac7dca0Sopenharmony_ci && self.events as libc::c_int & libc::EPOLLRDHUP != 0) 153cac7dca0Sopenharmony_ci } 154cac7dca0Sopenharmony_ci 155cac7dca0Sopenharmony_ci fn is_write_closed(&self) -> bool { 156cac7dca0Sopenharmony_ci self.events as libc::c_int & libc::EPOLLHUP != 0 157cac7dca0Sopenharmony_ci || (self.events as libc::c_int & libc::EPOLLOUT != 0 158cac7dca0Sopenharmony_ci && self.events as libc::c_int & libc::EPOLLERR != 0) 159cac7dca0Sopenharmony_ci || self.events as libc::c_int == libc::EPOLLERR 160cac7dca0Sopenharmony_ci } 161cac7dca0Sopenharmony_ci 162cac7dca0Sopenharmony_ci fn is_error(&self) -> bool { 163cac7dca0Sopenharmony_ci (self.events as libc::c_int & libc::EPOLLERR) != 0 164cac7dca0Sopenharmony_ci } 165cac7dca0Sopenharmony_ci} 166cac7dca0Sopenharmony_ci 167cac7dca0Sopenharmony_ci#[cfg(test)] 168cac7dca0Sopenharmony_cimod test { 169cac7dca0Sopenharmony_ci use crate::sys::socket; 170cac7dca0Sopenharmony_ci use crate::{Event, EventTrait, Interest, Selector, Token}; 171cac7dca0Sopenharmony_ci 172cac7dca0Sopenharmony_ci /// UT cases for `Selector::reregister`. 173cac7dca0Sopenharmony_ci /// 174cac7dca0Sopenharmony_ci /// # Brief 175cac7dca0Sopenharmony_ci /// 1. Create a Selector 176cac7dca0Sopenharmony_ci /// 2. Reregister the selector 177cac7dca0Sopenharmony_ci #[test] 178cac7dca0Sopenharmony_ci fn ut_epoll_reregister() { 179cac7dca0Sopenharmony_ci let selector = Selector::new().unwrap(); 180cac7dca0Sopenharmony_ci let sock = socket::socket_new(libc::AF_UNIX, libc::SOCK_STREAM).unwrap(); 181cac7dca0Sopenharmony_ci let ret = selector.register(sock, Token::from_usize(0), Interest::READABLE); 182cac7dca0Sopenharmony_ci assert!(ret.is_ok()); 183cac7dca0Sopenharmony_ci let ret = selector.reregister(sock, Token::from_usize(0), Interest::WRITABLE); 184cac7dca0Sopenharmony_ci assert!(ret.is_ok()); 185cac7dca0Sopenharmony_ci } 186cac7dca0Sopenharmony_ci 187cac7dca0Sopenharmony_ci /// UT case for `Event::is_error` 188cac7dca0Sopenharmony_ci /// 189cac7dca0Sopenharmony_ci /// # Brief 190cac7dca0Sopenharmony_ci /// 1. Create an event from libc::EPOLLERR 191cac7dca0Sopenharmony_ci /// 2. Check if it's an error 192cac7dca0Sopenharmony_ci #[test] 193cac7dca0Sopenharmony_ci fn ut_event_is_err() { 194cac7dca0Sopenharmony_ci let event = Event { 195cac7dca0Sopenharmony_ci events: libc::EPOLLERR as u32, 196cac7dca0Sopenharmony_ci u64: 0, 197cac7dca0Sopenharmony_ci }; 198cac7dca0Sopenharmony_ci assert!(event.is_error()); 199cac7dca0Sopenharmony_ci } 200cac7dca0Sopenharmony_ci} 201