From 80f4f984e8aa30444ae6817aefdcc05fd40dc37e Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Wed, 10 Jul 2024 20:27:22 +0800 Subject: [PATCH] refactor poll/select/recvfrom syscall --- open-coroutine-core/src/syscall/facade.rs | 45 +------ open-coroutine-core/src/syscall/io_uring.rs | 50 +------ open-coroutine-core/src/syscall/mod.rs | 46 +------ open-coroutine-core/src/syscall/nio.rs | 123 +----------------- open-coroutine-core/src/syscall/raw.rs | 64 +-------- open-coroutine-core/src/syscall/state.rs | 50 +------ open-coroutine-core/src/syscall/unix/mod.rs | 9 +- open-coroutine-core/src/syscall/unix/poll.rs | 69 ++++++++++ .../src/syscall/unix/recvfrom.rs | 57 ++++++++ .../src/syscall/unix/select.rs | 115 ++++++++++++++++ 10 files changed, 256 insertions(+), 372 deletions(-) create mode 100644 open-coroutine-core/src/syscall/unix/poll.rs create mode 100644 open-coroutine-core/src/syscall/unix/recvfrom.rs create mode 100644 open-coroutine-core/src/syscall/unix/select.rs diff --git a/open-coroutine-core/src/syscall/facade.rs b/open-coroutine-core/src/syscall/facade.rs index 3f558077..daef06d5 100644 --- a/open-coroutine-core/src/syscall/facade.rs +++ b/open-coroutine-core/src/syscall/facade.rs @@ -6,9 +6,7 @@ use crate::syscall::LinuxSyscall; use crate::syscall::UnixSyscall; #[cfg(target_os = "linux")] use libc::epoll_event; -use libc::{ - fd_set, iovec, msghdr, nfds_t, off_t, pollfd, size_t, sockaddr, socklen_t, ssize_t, timeval, -}; +use libc::{iovec, msghdr, off_t, size_t, sockaddr, socklen_t, ssize_t}; use once_cell::sync::Lazy; use std::ffi::{c_int, c_void}; @@ -23,49 +21,8 @@ cfg_if::cfg_if! { } } -/// poll - -#[must_use] -pub extern "C" fn poll( - fn_ptr: Option<&extern "C" fn(*mut pollfd, nfds_t, c_int) -> c_int>, - fds: *mut pollfd, - nfds: nfds_t, - timeout: c_int, -) -> c_int { - CHAIN.poll(fn_ptr, fds, nfds, timeout) -} - -#[must_use] -pub extern "C" fn select( - fn_ptr: Option< - &extern "C" fn(c_int, *mut fd_set, *mut fd_set, *mut fd_set, *mut timeval) -> c_int, - >, - nfds: c_int, - readfds: *mut fd_set, - writefds: *mut fd_set, - errorfds: *mut fd_set, - timeout: *mut timeval, -) -> c_int { - CHAIN.select(fn_ptr, nfds, readfds, writefds, errorfds, timeout) -} - /// read -#[must_use] -pub extern "C" fn recvfrom( - fn_ptr: Option< - &extern "C" fn(c_int, *mut c_void, size_t, c_int, *mut sockaddr, *mut socklen_t) -> ssize_t, - >, - socket: c_int, - buf: *mut c_void, - len: size_t, - flags: c_int, - addr: *mut sockaddr, - addrlen: *mut socklen_t, -) -> ssize_t { - CHAIN.recvfrom(fn_ptr, socket, buf, len, flags, addr, addrlen) -} - #[must_use] pub extern "C" fn read( fn_ptr: Option<&extern "C" fn(c_int, *mut c_void, size_t) -> ssize_t>, diff --git a/open-coroutine-core/src/syscall/io_uring.rs b/open-coroutine-core/src/syscall/io_uring.rs index 250ebcc8..d787fd55 100644 --- a/open-coroutine-core/src/syscall/io_uring.rs +++ b/open-coroutine-core/src/syscall/io_uring.rs @@ -1,9 +1,7 @@ use crate::syscall::LinuxSyscall; use crate::syscall::UnixSyscall; use libc::epoll_event; -use libc::{ - fd_set, iovec, msghdr, nfds_t, off_t, pollfd, size_t, sockaddr, socklen_t, ssize_t, timeval, -}; +use libc::{iovec, msghdr, off_t, size_t, sockaddr, socklen_t, ssize_t}; use std::ffi::{c_int, c_void}; #[derive(Debug, Default)] @@ -27,52 +25,6 @@ macro_rules! impl_io_uring { } impl UnixSyscall for IoUringLinuxSyscall { - extern "C" fn poll( - &self, - fn_ptr: Option<&extern "C" fn(*mut pollfd, nfds_t, c_int) -> c_int>, - fds: *mut pollfd, - nfds: nfds_t, - timeout: c_int, - ) -> c_int { - unsupported!(self, poll, fn_ptr, fds, nfds, timeout) - } - - extern "C" fn select( - &self, - fn_ptr: Option< - &extern "C" fn(c_int, *mut fd_set, *mut fd_set, *mut fd_set, *mut timeval) -> c_int, - >, - nfds: c_int, - readfds: *mut fd_set, - writefds: *mut fd_set, - errorfds: *mut fd_set, - timeout: *mut timeval, - ) -> c_int { - unsupported!(self, select, fn_ptr, nfds, readfds, writefds, errorfds, timeout) - } - - extern "C" fn recvfrom( - &self, - fn_ptr: Option< - &extern "C" fn( - c_int, - *mut c_void, - size_t, - c_int, - *mut sockaddr, - *mut socklen_t, - ) -> ssize_t, - >, - socket: c_int, - buf: *mut c_void, - len: size_t, - flags: c_int, - addr: *mut sockaddr, - addrlen: *mut socklen_t, - ) -> ssize_t { - unsupported!(self, recvfrom, fn_ptr, socket, buf, len, flags, addr, addrlen) - } - extern "C" fn read( &self, fn_ptr: Option<&extern "C" fn(c_int, *mut c_void, size_t) -> ssize_t>, diff --git a/open-coroutine-core/src/syscall/mod.rs b/open-coroutine-core/src/syscall/mod.rs index b0062cbc..80c2f590 100644 --- a/open-coroutine-core/src/syscall/mod.rs +++ b/open-coroutine-core/src/syscall/mod.rs @@ -1,9 +1,7 @@ #[cfg(target_os = "linux")] use libc::epoll_event; #[cfg(unix)] -use libc::{ - fd_set, iovec, msghdr, nfds_t, off_t, pollfd, size_t, sockaddr, socklen_t, ssize_t, timeval, -}; +use libc::{iovec, msghdr, off_t, size_t, sockaddr, socklen_t, ssize_t}; #[cfg(unix)] use std::ffi::{c_int, c_void}; @@ -30,50 +28,8 @@ pub use facade::*; #[cfg(unix)] pub trait UnixSyscall { - /// poll - - extern "C" fn poll( - &self, - fn_ptr: Option<&extern "C" fn(*mut pollfd, nfds_t, c_int) -> c_int>, - fds: *mut pollfd, - nfds: nfds_t, - timeout: c_int, - ) -> c_int; - - extern "C" fn select( - &self, - fn_ptr: Option< - &extern "C" fn(c_int, *mut fd_set, *mut fd_set, *mut fd_set, *mut timeval) -> c_int, - >, - nfds: c_int, - readfds: *mut fd_set, - writefds: *mut fd_set, - errorfds: *mut fd_set, - timeout: *mut timeval, - ) -> c_int; - /// read - extern "C" fn recvfrom( - &self, - fn_ptr: Option< - &extern "C" fn( - c_int, - *mut c_void, - size_t, - c_int, - *mut sockaddr, - *mut socklen_t, - ) -> ssize_t, - >, - fd: c_int, - buf: *mut c_void, - len: size_t, - flags: c_int, - addr: *mut sockaddr, - addrlen: *mut socklen_t, - ) -> ssize_t; - extern "C" fn read( &self, fn_ptr: Option<&extern "C" fn(c_int, *mut c_void, size_t) -> ssize_t>, diff --git a/open-coroutine-core/src/syscall/nio.rs b/open-coroutine-core/src/syscall/nio.rs index 1c11674e..88ce03d4 100644 --- a/open-coroutine-core/src/syscall/nio.rs +++ b/open-coroutine-core/src/syscall/nio.rs @@ -5,10 +5,8 @@ use crate::syscall::LinuxSyscall; use crate::syscall::UnixSyscall; #[cfg(target_os = "linux")] use libc::epoll_event; -use libc::{ - fd_set, iovec, msghdr, nfds_t, off_t, pollfd, size_t, sockaddr, socklen_t, ssize_t, timeval, -}; -use std::ffi::{c_int, c_uint, c_void}; +use libc::{iovec, msghdr, off_t, size_t, sockaddr, socklen_t, ssize_t}; +use std::ffi::{c_int, c_void}; use std::time::Duration; #[derive(Debug, Default)] @@ -259,123 +257,6 @@ macro_rules! impl_expected_batch_write_hook { } impl UnixSyscall for NioLinuxSyscall { - extern "C" fn poll( - &self, - fn_ptr: Option<&extern "C" fn(*mut pollfd, nfds_t, c_int) -> c_int>, - fds: *mut pollfd, - nfds: nfds_t, - timeout: c_int, - ) -> c_int { - let mut t = if timeout < 0 { c_int::MAX } else { timeout }; - let mut x = 1; - let mut r; - // just check select every x ms - loop { - r = self.inner.poll(fn_ptr, fds, nfds, 0); - if r != 0 || t == 0 { - break; - } - _ = EventLoops::wait_just(Some(Duration::from_millis(t.min(x) as u64))); - if t != c_int::MAX { - t = if t > x { t - x } else { 0 }; - } - if x < 16 { - x <<= 1; - } - } - r - } - - extern "C" fn select( - &self, - fn_ptr: Option< - &extern "C" fn(c_int, *mut fd_set, *mut fd_set, *mut fd_set, *mut timeval) -> c_int, - >, - nfds: c_int, - readfds: *mut fd_set, - writefds: *mut fd_set, - errorfds: *mut fd_set, - timeout: *mut timeval, - ) -> c_int { - let mut t = if timeout.is_null() { - c_uint::MAX - } else { - unsafe { ((*timeout).tv_sec as c_uint) * 1_000_000 + (*timeout).tv_usec as c_uint } - }; - let mut o = timeval { - tv_sec: 0, - tv_usec: 0, - }; - let mut s: [fd_set; 3] = unsafe { std::mem::zeroed() }; - unsafe { - if !readfds.is_null() { - s[0] = *readfds; - } - if !writefds.is_null() { - s[1] = *writefds; - } - if !errorfds.is_null() { - s[2] = *errorfds; - } - } - let mut x = 1; - let mut r; - // just check poll every x ms - loop { - r = self - .inner - .select(fn_ptr, nfds, readfds, writefds, errorfds, &mut o); - if r != 0 || t == 0 { - break; - } - _ = EventLoops::wait_just(Some(Duration::from_millis(u64::from(t.min(x))))); - if t != c_uint::MAX { - t = if t > x { t - x } else { 0 }; - } - if x < 16 { - x <<= 1; - } - unsafe { - if !readfds.is_null() { - *readfds = s[0]; - } - if !writefds.is_null() { - *writefds = s[1]; - } - if !errorfds.is_null() { - *errorfds = s[2]; - } - } - o.tv_sec = 0; - o.tv_usec = 0; - } - r - } - - extern "C" fn recvfrom( - &self, - fn_ptr: Option< - &extern "C" fn( - c_int, - *mut c_void, - size_t, - c_int, - *mut sockaddr, - *mut socklen_t, - ) -> ssize_t, - >, - socket: c_int, - buf: *mut c_void, - len: size_t, - flags: c_int, - addr: *mut sockaddr, - addrlen: *mut socklen_t, - ) -> ssize_t { - impl_expected_read_hook!( - self.inner, recvfrom, fn_ptr, socket, buf, len, flags, addr, addrlen - ) - } - extern "C" fn read( &self, fn_ptr: Option<&extern "C" fn(c_int, *mut c_void, size_t) -> ssize_t>, diff --git a/open-coroutine-core/src/syscall/raw.rs b/open-coroutine-core/src/syscall/raw.rs index 9f85b638..341a25b6 100644 --- a/open-coroutine-core/src/syscall/raw.rs +++ b/open-coroutine-core/src/syscall/raw.rs @@ -3,77 +3,15 @@ use crate::syscall::LinuxSyscall; use crate::syscall::UnixSyscall; #[cfg(target_os = "linux")] use libc::epoll_event; -use libc::{ - fd_set, iovec, msghdr, nfds_t, off_t, pollfd, size_t, sockaddr, socklen_t, ssize_t, timeval, -}; +use libc::{iovec, msghdr, off_t, size_t, sockaddr, socklen_t, ssize_t}; use std::ffi::{c_int, c_void}; #[derive(Debug, Copy, Clone, Default)] pub struct RawLinuxSyscall {} impl UnixSyscall for RawLinuxSyscall { - /// poll - - extern "C" fn poll( - &self, - fn_ptr: Option<&extern "C" fn(*mut pollfd, nfds_t, c_int) -> c_int>, - fds: *mut pollfd, - nfds: nfds_t, - timeout: c_int, - ) -> c_int { - if let Some(f) = fn_ptr { - (f)(fds, nfds, timeout) - } else { - unsafe { libc::poll(fds, nfds, timeout) } - } - } - - extern "C" fn select( - &self, - fn_ptr: Option< - &extern "C" fn(c_int, *mut fd_set, *mut fd_set, *mut fd_set, *mut timeval) -> c_int, - >, - nfds: c_int, - readfds: *mut fd_set, - writefds: *mut fd_set, - errorfds: *mut fd_set, - timeout: *mut timeval, - ) -> c_int { - if let Some(f) = fn_ptr { - (f)(nfds, readfds, writefds, errorfds, timeout) - } else { - unsafe { libc::select(nfds, readfds, writefds, errorfds, timeout) } - } - } - /// read - extern "C" fn recvfrom( - &self, - fn_ptr: Option< - &extern "C" fn( - c_int, - *mut c_void, - size_t, - c_int, - *mut sockaddr, - *mut socklen_t, - ) -> ssize_t, - >, - socket: c_int, - buf: *mut c_void, - len: size_t, - flags: c_int, - addr: *mut sockaddr, - addrlen: *mut socklen_t, - ) -> ssize_t { - if let Some(f) = fn_ptr { - (f)(socket, buf, len, flags, addr, addrlen) - } else { - unsafe { libc::recvfrom(socket, buf, len, flags, addr, addrlen) } - } - } - extern "C" fn read( &self, fn_ptr: Option<&extern "C" fn(c_int, *mut c_void, size_t) -> ssize_t>, diff --git a/open-coroutine-core/src/syscall/state.rs b/open-coroutine-core/src/syscall/state.rs index 47487bab..9712c87e 100644 --- a/open-coroutine-core/src/syscall/state.rs +++ b/open-coroutine-core/src/syscall/state.rs @@ -4,9 +4,7 @@ use crate::syscall::LinuxSyscall; use crate::syscall::UnixSyscall; #[cfg(target_os = "linux")] use libc::epoll_event; -use libc::{ - fd_set, iovec, msghdr, nfds_t, off_t, pollfd, size_t, sockaddr, socklen_t, ssize_t, timeval, -}; +use libc::{iovec, msghdr, off_t, size_t, sockaddr, socklen_t, ssize_t}; use std::ffi::{c_int, c_void}; #[derive(Debug, Default)] @@ -37,52 +35,6 @@ macro_rules! syscall_state { } impl UnixSyscall for StateLinuxSyscall { - extern "C" fn poll( - &self, - fn_ptr: Option<&extern "C" fn(*mut pollfd, nfds_t, c_int) -> c_int>, - fds: *mut pollfd, - nfds: nfds_t, - timeout: c_int, - ) -> c_int { - syscall_state!(self, poll, fn_ptr, fds, nfds, timeout) - } - - extern "C" fn select( - &self, - fn_ptr: Option< - &extern "C" fn(c_int, *mut fd_set, *mut fd_set, *mut fd_set, *mut timeval) -> c_int, - >, - nfds: c_int, - readfds: *mut fd_set, - writefds: *mut fd_set, - errorfds: *mut fd_set, - timeout: *mut timeval, - ) -> c_int { - syscall_state!(self, select, fn_ptr, nfds, readfds, writefds, errorfds, timeout) - } - - extern "C" fn recvfrom( - &self, - fn_ptr: Option< - &extern "C" fn( - c_int, - *mut c_void, - size_t, - c_int, - *mut sockaddr, - *mut socklen_t, - ) -> ssize_t, - >, - socket: c_int, - buf: *mut c_void, - len: size_t, - flags: c_int, - addr: *mut sockaddr, - addrlen: *mut socklen_t, - ) -> ssize_t { - syscall_state!(self, recvfrom, fn_ptr, socket, buf, len, flags, addr, addrlen) - } - extern "C" fn read( &self, fn_ptr: Option<&extern "C" fn(c_int, *mut c_void, size_t) -> ssize_t>, diff --git a/open-coroutine-core/src/syscall/unix/mod.rs b/open-coroutine-core/src/syscall/unix/mod.rs index 0b0d9d0f..b9b28d12 100644 --- a/open-coroutine-core/src/syscall/unix/mod.rs +++ b/open-coroutine-core/src/syscall/unix/mod.rs @@ -5,8 +5,11 @@ pub use close::close; pub use connect::connect; pub use listen::listen; pub use nanosleep::nanosleep; +pub use poll::poll; pub use readv::readv; pub use recv::recv; +pub use recvfrom::recvfrom; +pub use select::select; pub use send::send; pub use shutdown::shutdown; pub use sleep::sleep; @@ -32,7 +35,7 @@ macro_rules! impl_facade { use $crate::scheduler::SchedulableCoroutine; let syscall = Syscall::$syscall; - $crate::info!("hook syscall {}", syscall); + $crate::info!("enter syscall {}", syscall); if let Some(co) = SchedulableCoroutine::current() { let new_state = SyscallState::Executing; if co.syscall((), syscall, new_state).is_err() { @@ -46,6 +49,7 @@ macro_rules! impl_facade { $crate::error!("{} change to running state failed !", co.get_name()); } } + $crate::info!("exit syscall {}", syscall); r } } @@ -475,8 +479,11 @@ mod close; mod connect; mod listen; mod nanosleep; +mod poll; mod readv; mod recv; +mod recvfrom; +mod select; mod send; mod shutdown; mod sleep; diff --git a/open-coroutine-core/src/syscall/unix/poll.rs b/open-coroutine-core/src/syscall/unix/poll.rs new file mode 100644 index 00000000..4952407b --- /dev/null +++ b/open-coroutine-core/src/syscall/unix/poll.rs @@ -0,0 +1,69 @@ +use crate::net::event_loop::EventLoops; +use libc::{nfds_t, pollfd}; +use once_cell::sync::Lazy; +use std::ffi::c_int; +use std::time::Duration; + +#[must_use] +pub extern "C" fn poll( + fn_ptr: Option<&extern "C" fn(*mut pollfd, nfds_t, c_int) -> c_int>, + fds: *mut pollfd, + nfds: nfds_t, + timeout: c_int, +) -> c_int { + static CHAIN: Lazy>> = + Lazy::new(Default::default); + CHAIN.poll(fn_ptr, fds, nfds, timeout) +} + +trait PollSyscall { + extern "C" fn poll( + &self, + fn_ptr: Option<&extern "C" fn(*mut pollfd, nfds_t, c_int) -> c_int>, + fds: *mut pollfd, + nfds: nfds_t, + timeout: c_int, + ) -> c_int; +} + +impl_facade!(PollSyscallFacade, PollSyscall, + poll(fds: *mut pollfd, nfds: nfds_t, timeout: c_int) -> c_int +); + +#[derive(Debug, Default)] +struct NioPollSyscall { + inner: I, +} + +impl PollSyscall for NioPollSyscall { + extern "C" fn poll( + &self, + fn_ptr: Option<&extern "C" fn(*mut pollfd, nfds_t, c_int) -> c_int>, + fds: *mut pollfd, + nfds: nfds_t, + timeout: c_int, + ) -> c_int { + let mut t = if timeout < 0 { c_int::MAX } else { timeout }; + let mut x = 1; + let mut r; + // just check select every x ms + loop { + r = self.inner.poll(fn_ptr, fds, nfds, 0); + if r != 0 || t == 0 { + break; + } + _ = EventLoops::wait_just(Some(Duration::from_millis(t.min(x) as u64))); + if t != c_int::MAX { + t = if t > x { t - x } else { 0 }; + } + if x < 16 { + x <<= 1; + } + } + r + } +} + +impl_raw!(RawPollSyscall, PollSyscall, + poll(fds: *mut pollfd, nfds: nfds_t, timeout: c_int) -> c_int +); diff --git a/open-coroutine-core/src/syscall/unix/recvfrom.rs b/open-coroutine-core/src/syscall/unix/recvfrom.rs new file mode 100644 index 00000000..cfc29531 --- /dev/null +++ b/open-coroutine-core/src/syscall/unix/recvfrom.rs @@ -0,0 +1,57 @@ +use libc::{size_t, sockaddr, socklen_t, ssize_t}; +use once_cell::sync::Lazy; +use std::ffi::{c_int, c_void}; + +#[must_use] +pub extern "C" fn recvfrom( + fn_ptr: Option< + &extern "C" fn(c_int, *mut c_void, size_t, c_int, *mut sockaddr, *mut socklen_t) -> ssize_t, + >, + fd: c_int, + buf: *mut c_void, + len: size_t, + flags: c_int, + addr: *mut sockaddr, + addrlen: *mut socklen_t, +) -> ssize_t { + static CHAIN: Lazy>> = + Lazy::new(Default::default); + CHAIN.recvfrom(fn_ptr, fd, buf, len, flags, addr, addrlen) +} + +trait RecvfromSyscall { + extern "C" fn recvfrom( + &self, + fn_ptr: Option< + &extern "C" fn( + c_int, + *mut c_void, + size_t, + c_int, + *mut sockaddr, + *mut socklen_t, + ) -> ssize_t, + >, + fd: c_int, + buf: *mut c_void, + len: size_t, + flags: c_int, + addr: *mut sockaddr, + addrlen: *mut socklen_t, + ) -> ssize_t; +} + +impl_facade!(RecvfromSyscallFacade, RecvfromSyscall, + recvfrom(fd: c_int, buf: *mut c_void, len: size_t, flags: c_int, + addr: *mut sockaddr, addrlen: *mut socklen_t) -> ssize_t +); + +impl_nio_read_buf!(NioRecvfromSyscall, RecvfromSyscall, + recvfrom(fd: c_int, buf: *mut c_void, len: size_t, flags: c_int, + addr: *mut sockaddr, addrlen: *mut socklen_t) -> ssize_t +); + +impl_raw!(RawRecvfromSyscall, RecvfromSyscall, + recvfrom(fd: c_int, buf: *mut c_void, len: size_t, flags: c_int, + addr: *mut sockaddr, addrlen: *mut socklen_t) -> ssize_t +); diff --git a/open-coroutine-core/src/syscall/unix/select.rs b/open-coroutine-core/src/syscall/unix/select.rs new file mode 100644 index 00000000..6fa8d265 --- /dev/null +++ b/open-coroutine-core/src/syscall/unix/select.rs @@ -0,0 +1,115 @@ +use crate::net::event_loop::EventLoops; +use libc::{fd_set, timeval}; +use once_cell::sync::Lazy; +use std::ffi::{c_int, c_uint}; +use std::time::Duration; + +#[must_use] +pub extern "C" fn select( + fn_ptr: Option< + &extern "C" fn(c_int, *mut fd_set, *mut fd_set, *mut fd_set, *mut timeval) -> c_int, + >, + nfds: c_int, + readfds: *mut fd_set, + writefds: *mut fd_set, + errorfds: *mut fd_set, + timeout: *mut timeval, +) -> c_int { + static CHAIN: Lazy>> = + Lazy::new(Default::default); + CHAIN.select(fn_ptr, nfds, readfds, writefds, errorfds, timeout) +} + +trait SelectSyscall { + extern "C" fn select( + &self, + fn_ptr: Option< + &extern "C" fn(c_int, *mut fd_set, *mut fd_set, *mut fd_set, *mut timeval) -> c_int, + >, + nfds: c_int, + readfds: *mut fd_set, + writefds: *mut fd_set, + errorfds: *mut fd_set, + timeout: *mut timeval, + ) -> c_int; +} + +impl_facade!(SelectSyscallFacade, SelectSyscall, + select(nfds: c_int, readfds: *mut fd_set, writefds: *mut fd_set, + errorfds: *mut fd_set, timeout: *mut timeval) -> c_int +); + +#[derive(Debug, Default)] +struct NioSelectSyscall { + inner: I, +} + +impl SelectSyscall for NioSelectSyscall { + extern "C" fn select( + &self, + fn_ptr: Option< + &extern "C" fn(c_int, *mut fd_set, *mut fd_set, *mut fd_set, *mut timeval) -> c_int, + >, + nfds: c_int, + readfds: *mut fd_set, + writefds: *mut fd_set, + errorfds: *mut fd_set, + timeout: *mut timeval, + ) -> c_int { + let mut t = if timeout.is_null() { + c_uint::MAX + } else { + unsafe { ((*timeout).tv_sec as c_uint) * 1_000_000 + (*timeout).tv_usec as c_uint } + }; + let mut o = timeval { + tv_sec: 0, + tv_usec: 0, + }; + let mut s: [fd_set; 3] = unsafe { std::mem::zeroed() }; + if !readfds.is_null() { + s[0] = unsafe { *readfds }; + } + if !writefds.is_null() { + s[1] = unsafe { *writefds }; + } + if !errorfds.is_null() { + s[2] = unsafe { *errorfds }; + } + let mut x = 1; + let mut r; + // just check poll every x ms + loop { + r = self + .inner + .select(fn_ptr, nfds, readfds, writefds, errorfds, &mut o); + if r != 0 || t == 0 { + break; + } + _ = EventLoops::wait_just(Some(Duration::from_millis(u64::from(t.min(x))))); + if t != c_uint::MAX { + t = if t > x { t - x } else { 0 }; + } + if x < 16 { + x <<= 1; + } + + if !readfds.is_null() { + unsafe { *readfds = s[0] }; + } + if !writefds.is_null() { + unsafe { *writefds = s[1] }; + } + if !errorfds.is_null() { + unsafe { *errorfds = s[2] }; + } + o.tv_sec = 0; + o.tv_usec = 0; + } + r + } +} + +impl_raw!(RawSelectSyscall, SelectSyscall, + select(nfds: c_int, readfds: *mut fd_set, writefds: *mut fd_set, + errorfds: *mut fd_set, timeout: *mut timeval) -> c_int +);