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