From fe85826db3bd960cd143f589efd822044096fc24 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Fri, 24 Jan 2025 16:50:40 +0800 Subject: [PATCH] add IOCP accept --- core/src/net/operator/windows/mod.rs | 2 +- core/src/syscall/unix/mod.rs | 18 ++-- core/src/syscall/windows/accept.rs | 96 ++++++++++++++++- core/src/syscall/windows/mod.rs | 156 +++++++++++++++++++++++++-- 4 files changed, 251 insertions(+), 21 deletions(-) diff --git a/core/src/net/operator/windows/mod.rs b/core/src/net/operator/windows/mod.rs index 89ce0e89..998cdbc1 100644 --- a/core/src/net/operator/windows/mod.rs +++ b/core/src/net/operator/windows/mod.rs @@ -238,7 +238,7 @@ impl<'o> Operator<'o> { let mut sock_info: WSAPROTOCOL_INFOW = std::mem::zeroed(); let mut sock_info_len = size_of::() .try_into() - .expect("protocol_len overflow"); + .expect("sock_info_len overflow"); if getsockopt( fd, SOL_SOCKET, diff --git a/core/src/syscall/unix/mod.rs b/core/src/syscall/unix/mod.rs index 86189a9a..324f3ed8 100644 --- a/core/src/syscall/unix/mod.rs +++ b/core/src/syscall/unix/mod.rs @@ -61,10 +61,10 @@ macro_rules! impl_io_uring { fn_ptr: Option<&extern "C" fn($($arg_type),*) -> $result>, $($arg: $arg_type),* ) -> $result { - if let Ok(arc) = $crate::net::EventLoops::$syscall($($arg, )*) { - use $crate::common::constants::{CoroutineState, SyscallState}; - use $crate::scheduler::{SchedulableCoroutine, SchedulableSuspender}; + use $crate::common::constants::{CoroutineState, SyscallState}; + use $crate::scheduler::{SchedulableCoroutine, SchedulableSuspender}; + if let Ok(arc) = $crate::net::EventLoops::$syscall($($arg, )*) { if let Some(co) = SchedulableCoroutine::current() { if let CoroutineState::Syscall((), syscall, SyscallState::Executing) = co.state() { @@ -136,10 +136,10 @@ macro_rules! impl_io_uring_read { $fd: $fd_type, $($arg: $arg_type),* ) -> $result { - if let Ok(arc) = $crate::net::EventLoops::$syscall($fd, $($arg, )*) { - use $crate::common::constants::{CoroutineState, SyscallState}; - use $crate::scheduler::{SchedulableCoroutine, SchedulableSuspender}; + use $crate::common::constants::{CoroutineState, SyscallState}; + use $crate::scheduler::{SchedulableCoroutine, SchedulableSuspender}; + if let Ok(arc) = $crate::net::EventLoops::$syscall($fd, $($arg, )*) { if let Some(co) = SchedulableCoroutine::current() { if let CoroutineState::Syscall((), syscall, SyscallState::Executing) = co.state() { @@ -222,10 +222,10 @@ macro_rules! impl_io_uring_write { $fd: $fd_type, $($arg: $arg_type),* ) -> $result { - if let Ok(arc) = $crate::net::EventLoops::$syscall($fd, $($arg, )*) { - use $crate::common::constants::{CoroutineState, SyscallState}; - use $crate::scheduler::{SchedulableCoroutine, SchedulableSuspender}; + use $crate::common::constants::{CoroutineState, SyscallState}; + use $crate::scheduler::{SchedulableCoroutine, SchedulableSuspender}; + if let Ok(arc) = $crate::net::EventLoops::$syscall($fd, $($arg, )*) { if let Some(co) = SchedulableCoroutine::current() { if let CoroutineState::Syscall((), syscall, SyscallState::Executing) = co.state() { diff --git a/core/src/syscall/windows/accept.rs b/core/src/syscall/windows/accept.rs index dbf1dd60..304927cd 100644 --- a/core/src/syscall/windows/accept.rs +++ b/core/src/syscall/windows/accept.rs @@ -1,3 +1,4 @@ +use std::convert::TryInto; use once_cell::sync::Lazy; use std::ffi::c_int; use windows_sys::Win32::Networking::WinSock::{SOCKADDR, SOCKET}; @@ -9,8 +10,16 @@ pub extern "system" fn accept( address: *mut SOCKADDR, address_len: *mut c_int, ) -> SOCKET { - static CHAIN: Lazy>> = - Lazy::new(Default::default); + cfg_if::cfg_if! { + if #[cfg(feature = "iocp")] { + static CHAIN: Lazy< + AcceptSyscallFacade>> + > = Lazy::new(Default::default); + } else { + static CHAIN: Lazy>> = + Lazy::new(Default::default); + } + } CHAIN.accept(fn_ptr, fd, address, address_len) } @@ -28,6 +37,89 @@ impl_facade!(AcceptSyscallFacade, AcceptSyscall, accept(fd: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET ); +#[repr(C)] +#[derive(Debug, Default)] +#[cfg(all(windows, feature = "iocp"))] +struct IocpAcceptSyscall { + inner: I, +} + +#[cfg(all(windows, feature = "iocp"))] +impl AcceptSyscall for IocpAcceptSyscall { + extern "system" fn accept( + &self, + fn_ptr: Option<&extern "system" fn(SOCKET, *mut SOCKADDR, *mut c_int) -> SOCKET>, + fd: SOCKET, + address: *mut SOCKADDR, + address_len: *mut c_int + ) -> SOCKET { + use crate::common::constants::{CoroutineState, SyscallState}; + use crate::scheduler::{SchedulableCoroutine, SchedulableSuspender}; + use windows_sys::Win32::Networking::WinSock::{INVALID_SOCKET, getsockopt, SOL_SOCKET, SO_PROTOCOL_INFO, WSAPROTOCOL_INFOW}; + + if let Ok(arc) = crate::net::EventLoops::accept(fd, address, address_len) { + if let Some(co) = SchedulableCoroutine::current() { + if let CoroutineState::Syscall((), syscall, SyscallState::Executing) = co.state() + { + let new_state = SyscallState::Suspend(crate::syscall::recv_time_limit(fd)); + if co.syscall((), syscall, new_state).is_err() { + crate::error!( + "{} change to syscall {} {} failed !", + co.name(), syscall, new_state + ); + } + } + } + if let Some(suspender) = SchedulableSuspender::current() { + suspender.suspend(); + //回来的时候,系统调用已经执行完了 + } + if let Some(co) = SchedulableCoroutine::current() { + if let CoroutineState::Syscall((), syscall, SyscallState::Callback) = co.state() + { + let new_state = SyscallState::Executing; + if co.syscall((), syscall, new_state).is_err() { + crate::error!( + "{} change to syscall {} {} failed !", + co.name(), syscall, new_state + ); + } + } + } + let (lock, cvar) = &*arc; + let syscall_result = cvar + .wait_while(lock.lock().expect("lock failed"), + |&mut result| result.is_none() + ) + .expect("lock failed") + .expect("no syscall result"); + if syscall_result < 0 { + crate::syscall::set_errno((-syscall_result).try_into().expect("errno overflow")); + return INVALID_SOCKET; + } + unsafe { + let mut sock_info: WSAPROTOCOL_INFOW = std::mem::zeroed(); + let mut sock_info_len = size_of::() + .try_into() + .expect("sock_info_len overflow"); + if getsockopt( + fd, + SOL_SOCKET, + SO_PROTOCOL_INFO, + std::ptr::from_mut(&mut sock_info).cast(), + &mut sock_info_len, + ) != 0 + { + return INVALID_SOCKET; + } + (*address).sa_family = sock_info.iAddressFamily.try_into().expect("iAddressFamily overflow"); + } + return SOCKET::try_from(syscall_result).expect("overflow"); + } + self.inner.accept(fn_ptr, fd, address, address_len) + } +} + impl_nio_read!(NioAcceptSyscall, AcceptSyscall, accept(fd: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET ); diff --git a/core/src/syscall/windows/mod.rs b/core/src/syscall/windows/mod.rs index 450ff167..b10e766b 100644 --- a/core/src/syscall/windows/mod.rs +++ b/core/src/syscall/windows/mod.rs @@ -66,7 +66,7 @@ macro_rules! impl_iocp { fn_ptr: Option<&extern "system" fn($($arg_type),*) -> $result>, $($arg: $arg_type),* ) -> $result { - use $crate::common::constants::{CoroutineState, SyscallName, SyscallState}; + use $crate::common::constants::{CoroutineState, SyscallState}; use $crate::scheduler::{SchedulableCoroutine, SchedulableSuspender}; if let Ok(arc) = $crate::net::EventLoops::$syscall($($arg, )*) { @@ -77,9 +77,7 @@ macro_rules! impl_iocp { if co.syscall((), syscall, new_state).is_err() { $crate::error!( "{} change to syscall {} {} failed !", - co.name(), - syscall, - new_state + co.name(), syscall, new_state ); } } @@ -109,11 +107,7 @@ macro_rules! impl_iocp { .expect("no syscall result"); if syscall_result < 0 { $crate::syscall::set_errno((-syscall_result).try_into().expect("errno overflow")); - if SyscallName::accept == SyscallName::$syscall { - syscall_result = 0; - } else { - syscall_result = -1; - } + syscall_result = -1; } return <$result>::try_from(syscall_result).expect("overflow"); } @@ -123,6 +117,150 @@ macro_rules! impl_iocp { } } +#[allow(unused_macros)] +macro_rules! impl_iocp_read { + ( + $struct_name:ident, $trait_name: ident, + $syscall: ident($fd: ident : $fd_type: ty, $($arg: ident : $arg_type: ty),*) -> $result: ty + ) => { + #[repr(C)] + #[derive(Debug, Default)] + #[cfg(all(windows, feature = "iocp"))] + struct $struct_name { + inner: I, + } + + #[cfg(all(windows, feature = "iocp"))] + impl $trait_name for $struct_name { + extern "system" fn $syscall( + &self, + fn_ptr: Option<&extern "system" fn($fd_type, $($arg_type),*) -> $result>, + $fd: $fd_type, + $($arg: $arg_type),* + ) -> $result { + use $crate::common::constants::{CoroutineState, SyscallState}; + use $crate::scheduler::{SchedulableCoroutine, SchedulableSuspender}; + + if let Ok(arc) = $crate::net::EventLoops::$syscall($fd, $($arg, )*) { + if let Some(co) = SchedulableCoroutine::current() { + if let CoroutineState::Syscall((), syscall, SyscallState::Executing) = co.state() + { + let new_state = SyscallState::Suspend($crate::syscall::recv_time_limit($fd)); + if co.syscall((), syscall, new_state).is_err() { + $crate::error!( + "{} change to syscall {} {} failed !", + co.name(), syscall, new_state + ); + } + } + } + if let Some(suspender) = SchedulableSuspender::current() { + suspender.suspend(); + //回来的时候,系统调用已经执行完了 + } + if let Some(co) = SchedulableCoroutine::current() { + if let CoroutineState::Syscall((), syscall, SyscallState::Callback) = co.state() + { + let new_state = SyscallState::Executing; + if co.syscall((), syscall, new_state).is_err() { + $crate::error!( + "{} change to syscall {} {} failed !", + co.name(), syscall, new_state + ); + } + } + } + let (lock, cvar) = &*arc; + let mut syscall_result = cvar + .wait_while(lock.lock().expect("lock failed"), + |&mut result| result.is_none() + ) + .expect("lock failed") + .expect("no syscall result"); + if syscall_result < 0 { + $crate::syscall::set_errno((-syscall_result).try_into().expect("errno overflow")); + syscall_result = -1; + } + return <$result>::try_from(syscall_result).expect("overflow"); + } + self.inner.$syscall(fn_ptr, $fd, $($arg, )*) + } + } + } +} + +#[allow(unused_macros)] +macro_rules! impl_iocp_write { + ( + $struct_name:ident, $trait_name: ident, + $syscall: ident($fd: ident : $fd_type: ty, $($arg: ident : $arg_type: ty),*) -> $result: ty + ) => { + #[repr(C)] + #[derive(Debug, Default)] + #[cfg(all(windows, feature = "iocp"))] + struct $struct_name { + inner: I, + } + + #[cfg(all(windows, feature = "iocp"))] + impl $trait_name for $struct_name { + extern "system" fn $syscall( + &self, + fn_ptr: Option<&extern "system" fn($fd_type, $($arg_type),*) -> $result>, + $fd: $fd_type, + $($arg: $arg_type),* + ) -> $result { + use $crate::common::constants::{CoroutineState, SyscallState}; + use $crate::scheduler::{SchedulableCoroutine, SchedulableSuspender}; + + if let Ok(arc) = $crate::net::EventLoops::$syscall($fd, $($arg, )*) { + if let Some(co) = SchedulableCoroutine::current() { + if let CoroutineState::Syscall((), syscall, SyscallState::Executing) = co.state() + { + let new_state = SyscallState::Suspend($crate::syscall::send_time_limit($fd)); + if co.syscall((), syscall, new_state).is_err() { + $crate::error!( + "{} change to syscall {} {} failed !", + co.name(), syscall, new_state + ); + } + } + } + if let Some(suspender) = SchedulableSuspender::current() { + suspender.suspend(); + //回来的时候,系统调用已经执行完了 + } + if let Some(co) = SchedulableCoroutine::current() { + if let CoroutineState::Syscall((), syscall, SyscallState::Callback) = co.state() + { + let new_state = SyscallState::Executing; + if co.syscall((), syscall, new_state).is_err() { + $crate::error!( + "{} change to syscall {} {} failed !", + co.name(), syscall, new_state + ); + } + } + } + let (lock, cvar) = &*arc; + let mut syscall_result = cvar + .wait_while(lock.lock().expect("lock failed"), + |&mut result| result.is_none() + ) + .expect("lock failed") + .expect("no syscall result"); + if syscall_result < 0 { + $crate::syscall::set_errno((-syscall_result).try_into().expect("errno overflow")); + syscall_result = -1; + } + return <$result>::try_from(syscall_result).expect("overflow"); + } + self.inner.$syscall(fn_ptr, $fd, $($arg, )*) + } + } + } +} + macro_rules! impl_nio_read { ( $struct_name:ident, $trait_name: ident,