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_ci 16cac7dca0Sopenharmony_ciuse crate::{Selector, Token}; 17cac7dca0Sopenharmony_ci 18cac7dca0Sopenharmony_cimacro_rules! cfg_linux { 19cac7dca0Sopenharmony_ci ($($item:item)*) => { 20cac7dca0Sopenharmony_ci $( 21cac7dca0Sopenharmony_ci #[cfg(target_os = "linux")] 22cac7dca0Sopenharmony_ci $item 23cac7dca0Sopenharmony_ci )* 24cac7dca0Sopenharmony_ci } 25cac7dca0Sopenharmony_ci} 26cac7dca0Sopenharmony_ci 27cac7dca0Sopenharmony_cimacro_rules! cfg_macos { 28cac7dca0Sopenharmony_ci ($($item:item)*) => { 29cac7dca0Sopenharmony_ci $( 30cac7dca0Sopenharmony_ci #[cfg(target_os = "macos")] 31cac7dca0Sopenharmony_ci $item 32cac7dca0Sopenharmony_ci )* 33cac7dca0Sopenharmony_ci } 34cac7dca0Sopenharmony_ci} 35cac7dca0Sopenharmony_ci 36cac7dca0Sopenharmony_cicfg_linux!( 37cac7dca0Sopenharmony_ci use std::fs::File; 38cac7dca0Sopenharmony_ci use std::io::{Read, Write}; 39cac7dca0Sopenharmony_ci use std::os::unix::io::FromRawFd; 40cac7dca0Sopenharmony_ci use crate::Interest; 41cac7dca0Sopenharmony_ci 42cac7dca0Sopenharmony_ci /// In Linux, `eventfd` is used to implement asynchronous wake-up. It is a 43cac7dca0Sopenharmony_ci /// 64-bit counter. A fixed 8-byte (64-bit) unsigned integer is written to 44cac7dca0Sopenharmony_ci /// ensure wake-up reliability. 45cac7dca0Sopenharmony_ci #[derive(Debug)] 46cac7dca0Sopenharmony_ci pub(crate) struct WakerInner { 47cac7dca0Sopenharmony_ci fd: File, 48cac7dca0Sopenharmony_ci } 49cac7dca0Sopenharmony_ci 50cac7dca0Sopenharmony_ci impl WakerInner { 51cac7dca0Sopenharmony_ci pub(crate) fn new(selector: &Selector, token: Token) -> io::Result<WakerInner> { 52cac7dca0Sopenharmony_ci let fd = unsafe { libc::eventfd(0, libc::EFD_CLOEXEC | libc::EFD_NONBLOCK) }; 53cac7dca0Sopenharmony_ci let file = unsafe { File::from_raw_fd(fd) }; 54cac7dca0Sopenharmony_ci if fd == -1 { 55cac7dca0Sopenharmony_ci let err = io::Error::last_os_error(); 56cac7dca0Sopenharmony_ci Err(err) 57cac7dca0Sopenharmony_ci } else { 58cac7dca0Sopenharmony_ci selector 59cac7dca0Sopenharmony_ci .register(fd, token, Interest::READABLE) 60cac7dca0Sopenharmony_ci .map(|()| WakerInner { fd: file }) 61cac7dca0Sopenharmony_ci } 62cac7dca0Sopenharmony_ci } 63cac7dca0Sopenharmony_ci 64cac7dca0Sopenharmony_ci pub(crate) fn wake(&self) -> io::Result<()> { 65cac7dca0Sopenharmony_ci let buf: [u8; 8] = 1u64.to_ne_bytes(); 66cac7dca0Sopenharmony_ci match (&self.fd).write(&buf) { 67cac7dca0Sopenharmony_ci Ok(_) => Ok(()), 68cac7dca0Sopenharmony_ci Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => { 69cac7dca0Sopenharmony_ci let mut buf: [u8; 8] = 0u64.to_ne_bytes(); 70cac7dca0Sopenharmony_ci match (&self.fd).read(&mut buf) { 71cac7dca0Sopenharmony_ci Err(err) if err.kind() != io::ErrorKind::WouldBlock => Err(err), 72cac7dca0Sopenharmony_ci _ => self.wake(), 73cac7dca0Sopenharmony_ci } 74cac7dca0Sopenharmony_ci } 75cac7dca0Sopenharmony_ci Err(err) => Err(err), 76cac7dca0Sopenharmony_ci } 77cac7dca0Sopenharmony_ci } 78cac7dca0Sopenharmony_ci } 79cac7dca0Sopenharmony_ci); 80cac7dca0Sopenharmony_ci 81cac7dca0Sopenharmony_cicfg_macos!( 82cac7dca0Sopenharmony_ci /// In MacOs, kqueue with `EVFILT_USER` is used to implement asynchronous wake-up. 83cac7dca0Sopenharmony_ci #[derive(Debug)] 84cac7dca0Sopenharmony_ci pub(crate) struct WakerInner { 85cac7dca0Sopenharmony_ci selector: Selector, 86cac7dca0Sopenharmony_ci token: Token, 87cac7dca0Sopenharmony_ci } 88cac7dca0Sopenharmony_ci 89cac7dca0Sopenharmony_ci impl WakerInner { 90cac7dca0Sopenharmony_ci pub(crate) fn new(selector: &Selector, token: Token) -> io::Result<WakerInner> { 91cac7dca0Sopenharmony_ci let selector = selector.try_clone()?; 92cac7dca0Sopenharmony_ci selector.register_waker(token)?; 93cac7dca0Sopenharmony_ci Ok(WakerInner { selector, token }) 94cac7dca0Sopenharmony_ci } 95cac7dca0Sopenharmony_ci 96cac7dca0Sopenharmony_ci pub(crate) fn wake(&self) -> io::Result<()> { 97cac7dca0Sopenharmony_ci self.selector.wake(self.token) 98cac7dca0Sopenharmony_ci } 99cac7dca0Sopenharmony_ci } 100cac7dca0Sopenharmony_ci); 101