open-coroutine-core 0.7.0

The open-coroutine is a simple, efficient and generic coroutine library.
Documentation
use std::ffi::{c_uint, c_void};
use std::time::Duration;
use windows_sys::Win32::Foundation::{BOOL, ERROR_TIMEOUT, FALSE, TRUE};
use crate::common::{get_timeout_time, now};
use crate::net::EventLoops;
use crate::syscall::reset_errno;
use crate::syscall::set_errno;

trait WaitOnAddressSyscall {
    extern "system" fn WaitOnAddress(
        &self,
        fn_ptr: Option<&extern "system" fn(*const c_void, *const c_void, usize, c_uint) -> BOOL>,
        address: *const c_void,
        compareaddress: *const c_void,
        addresssize: usize,
        dwmilliseconds: c_uint
    ) -> BOOL;
}

impl_syscall!(WaitOnAddressSyscallFacade, NioWaitOnAddressSyscall, RawWaitOnAddressSyscall,
    WaitOnAddress(
        address: *const c_void,
        compareaddress: *const c_void,
        addresssize: usize,
        dwmilliseconds: c_uint
    ) -> BOOL
);

impl_facade!(WaitOnAddressSyscallFacade, WaitOnAddressSyscall,
    WaitOnAddress(
        address: *const c_void,
        compareaddress: *const c_void,
        addresssize: usize,
        dwmilliseconds: c_uint
    ) -> BOOL
);

#[repr(C)]
#[derive(Debug, Default)]
struct NioWaitOnAddressSyscall<I: WaitOnAddressSyscall> {
    inner: I,
}

impl<I: WaitOnAddressSyscall> WaitOnAddressSyscall for NioWaitOnAddressSyscall<I> {
    extern "system" fn WaitOnAddress(
        &self,
        fn_ptr: Option<&extern "system" fn(*const c_void, *const c_void, usize, c_uint) -> BOOL>,
        address: *const c_void,
        compareaddress: *const c_void,
        addresssize: usize,
        dwmilliseconds: c_uint
    ) -> BOOL {
        let timeout = get_timeout_time(Duration::from_millis(dwmilliseconds.into()));
        loop {
            let mut left_time = timeout.saturating_sub(now());
            if 0 == left_time {
                set_errno(ERROR_TIMEOUT);
                return FALSE;
            }
            let r = self.inner.WaitOnAddress(
                fn_ptr,
                address,
                compareaddress,
                addresssize,
                (left_time / 1_000_000).min(1).try_into().expect("overflow"),
            );
            if TRUE == r {
                reset_errno();
                return r;
            }
            left_time = timeout.saturating_sub(now());
            if 0 == left_time {
                set_errno(ERROR_TIMEOUT);
                return FALSE;
            }
            let wait_time = if left_time > 10_000_000 {
                10_000_000
            } else {
                left_time
            };
            if EventLoops::wait_event(Some(Duration::new(
                wait_time / 1_000_000_000,
                (wait_time % 1_000_000_000) as _,
            )))
                .is_err()
            {
                return r;
            }
        }
    }
}

impl_raw!(RawWaitOnAddressSyscall, WaitOnAddressSyscall, windows_sys::Win32::System::Threading,
    WaitOnAddress(
        address: *const c_void,
        compareaddress: *const c_void,
        addresssize: usize,
        dwmilliseconds: c_uint
    ) -> BOOL
);