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::fs::File; 15 use std::io; 16 use std::io::{Read, Write}; 17 use std::os::unix::io::FromRawFd; 18 19 use crate::{Interest, Selector, Token}; 20 21 /// In Linux, `eventfd` is used to implement asynchronous wake-up. It is a 22 /// 64-bit counter. A fixed 8-byte (64-bit) unsigned integer is written to 23 /// ensure wake-up reliability. 24 #[derive(Debug)] 25 pub(crate) struct WakerInner { 26 fd: File, 27 } 28 impl WakerInner { new(selector: &Selector, token: Token) -> io::Result<WakerInner>29 pub(crate) fn new(selector: &Selector, token: Token) -> io::Result<WakerInner> { 30 let fd = unsafe { libc::eventfd(0, libc::EFD_CLOEXEC | libc::EFD_NONBLOCK) }; 31 let file = unsafe { File::from_raw_fd(fd) }; 32 if fd == -1 { 33 let err = io::Error::last_os_error(); 34 Err(err) 35 } else { 36 selector 37 .register(fd, token, Interest::READABLE) 38 .map(|()| WakerInner { fd: file }) 39 } 40 } 41 wake(&self) -> io::Result<()>42 pub(crate) fn wake(&self) -> io::Result<()> { 43 let buf: [u8; 8] = 1u64.to_ne_bytes(); 44 match (&self.fd).write(&buf) { 45 Ok(_) => Ok(()), 46 Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => { 47 let mut buf: [u8; 8] = 0u64.to_ne_bytes(); 48 match (&self.fd).read(&mut buf) { 49 Err(err) if err.kind() != io::ErrorKind::WouldBlock => Err(err), 50 _ => self.wake(), 51 } 52 } 53 Err(err) => Err(err), 54 } 55 } 56 } 57