From a51c248efaed6b2640b555e9751ab0b5e904e4f3 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Wed, 13 Nov 2024 09:26:27 +0800 Subject: [PATCH 01/42] support completion io for windows --- .github/workflows/ci-preemptive.sh | 10 + .github/workflows/ci.sh | 10 + .github/workflows/ci.yml | 13 +- core/Cargo.toml | 6 + core/src/net/event_loop.rs | 110 +++++++- core/src/net/mod.rs | 52 +++- core/src/net/operator/linux/mod.rs | 1 - core/src/net/operator/mod.rs | 7 + core/src/net/operator/windows.rs | 366 +++++++++++++++++++++++++ core/src/syscall/unix/mod.rs | 11 +- core/src/syscall/windows/WSARecv.rs | 129 ++++++++- core/src/syscall/windows/WSASend.rs | 136 ++++++++- core/src/syscall/windows/WSASocketW.rs | 45 ++- core/src/syscall/windows/accept.rs | 16 +- core/src/syscall/windows/mod.rs | 85 ++++++ core/src/syscall/windows/recv.rs | 16 +- core/src/syscall/windows/send.rs | 16 +- core/src/syscall/windows/socket.rs | 23 +- hook/Cargo.toml | 6 + open-coroutine/Cargo.toml | 6 + open-coroutine/build.rs | 6 + open-coroutine/src/lib.rs | 3 +- 22 files changed, 1030 insertions(+), 43 deletions(-) create mode 100644 core/src/net/operator/windows.rs diff --git a/.github/workflows/ci-preemptive.sh b/.github/workflows/ci-preemptive.sh index 1a244eaf..d8172791 100644 --- a/.github/workflows/ci-preemptive.sh +++ b/.github/workflows/ci-preemptive.sh @@ -34,3 +34,13 @@ if [ "${TARGET}" = "x86_64-unknown-linux-gnu" ]; then "${CARGO}" test --target "${TARGET}" --no-default-features --features io_uring,preemptive "${CARGO}" test --target "${TARGET}" --no-default-features --features io_uring,preemptive --release fi + +# test IOCP +if [ "${OS}" = "windows-latest" ]; then + cd "${PROJECT_DIR}"/core + "${CARGO}" test --target "${TARGET}" --no-default-features --features iocp,preemptive + "${CARGO}" test --target "${TARGET}" --no-default-features --features iocp,preemptive --release + cd "${PROJECT_DIR}"/open-coroutine + "${CARGO}" test --target "${TARGET}" --no-default-features --features iocp,preemptive + "${CARGO}" test --target "${TARGET}" --no-default-features --features iocp,preemptive --release +fi diff --git a/.github/workflows/ci.sh b/.github/workflows/ci.sh index 47b5a23c..e97641eb 100644 --- a/.github/workflows/ci.sh +++ b/.github/workflows/ci.sh @@ -34,3 +34,13 @@ if [ "${TARGET}" = "x86_64-unknown-linux-gnu" ]; then "${CARGO}" test --target "${TARGET}" --no-default-features --features io_uring "${CARGO}" test --target "${TARGET}" --no-default-features --features io_uring --release fi + +# test IOCP +if [ "${OS}" = "windows-latest" ]; then + cd "${PROJECT_DIR}"/core + "${CARGO}" test --target "${TARGET}" --no-default-features --features iocp + "${CARGO}" test --target "${TARGET}" --no-default-features --features iocp --release + cd "${PROJECT_DIR}"/open-coroutine + "${CARGO}" test --target "${TARGET}" --no-default-features --features iocp + "${CARGO}" test --target "${TARGET}" --no-default-features --features iocp --release +fi diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7791551c..9e00d2ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,10 +22,21 @@ jobs: target: ${{ matrix.target }} override: true components: rustfmt - - uses: actions-rs/cargo@v1 + - name: Check code format + uses: actions-rs/cargo@v1 with: command: fmt args: --all -- --check + - name: Check clippy with default features + uses: actions-rs/cargo@v1 + with: + command: clippy + args: --all + - name: Check clippy with all features + uses: actions-rs/cargo@v1 + with: + command: clippy + args: --all --all-features - name: Run cargo deny if: ${{ contains(matrix.os, 'ubuntu') }} uses: EmbarkStudios/cargo-deny-action@v2 diff --git a/core/Cargo.toml b/core/Cargo.toml index af54b320..ff6c27a0 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -89,6 +89,12 @@ net = ["korosensei", "polling", "mio", "crossbeam-utils", "core_affinity"] # Provide io_uring adaptation, this feature only works in linux. io_uring = ["net", "io-uring"] +# Provide IOCP adaptation, this feature only works in windows. +iocp = ["net"] + +# Provide completion IOCP adaptation +completion_io = ["io_uring", "iocp"] + # Provide syscall implementation. syscall = ["net"] diff --git a/core/src/net/event_loop.rs b/core/src/net/event_loop.rs index 94c8a9b0..e37c4dfd 100644 --- a/core/src/net/event_loop.rs +++ b/core/src/net/event_loop.rs @@ -6,6 +6,8 @@ use crate::scheduler::SchedulableCoroutine; use crate::{error, impl_current_for, impl_display_by_debug, info}; use crossbeam_utils::atomic::AtomicCell; use dashmap::DashSet; +#[cfg(all(target_os = "linux", feature = "io_uring"))] +use libc::{epoll_event, iovec, msghdr, off_t, size_t, sockaddr, socklen_t, ssize_t}; use once_cell::sync::Lazy; use rand::Rng; use std::ffi::{c_char, c_int, c_void, CStr, CString}; @@ -18,8 +20,19 @@ use std::thread::JoinHandle; use std::time::Duration; cfg_if::cfg_if! { - if #[cfg(all(target_os = "linux", feature = "io_uring"))] { - use libc::{epoll_event, iovec, msghdr, off_t, size_t, sockaddr, socklen_t}; + if #[cfg(all(windows, feature = "iocp"))] { + use std::ffi::c_uint; + use windows_sys::core::{PCSTR, PSTR}; + use windows_sys::Win32::Networking::WinSock::{ + setsockopt, LPWSAOVERLAPPED_COMPLETION_ROUTINE, SEND_RECV_FLAGS, SOCKADDR, SOCKET, SOL_SOCKET, + SO_UPDATE_ACCEPT_CONTEXT, WSABUF, + }; + use windows_sys::Win32::System::IO::OVERLAPPED; + } +} + +cfg_if::cfg_if! { + if #[cfg(any(all(target_os = "linux", feature = "io_uring"), all(windows, feature = "iocp")))] { use dashmap::DashMap; use std::ffi::c_longlong; } @@ -33,10 +46,16 @@ pub(crate) struct EventLoop<'e> { stop: Arc<(Mutex, Condvar)>, shared_stop: Arc<(Mutex, Condvar)>, cpu: usize, - #[cfg(all(target_os = "linux", feature = "io_uring"))] + #[cfg(any( + all(target_os = "linux", feature = "io_uring"), + all(windows, feature = "iocp") + ))] operator: crate::net::operator::Operator<'e>, #[allow(clippy::type_complexity)] - #[cfg(all(target_os = "linux", feature = "io_uring"))] + #[cfg(any( + all(target_os = "linux", feature = "io_uring"), + all(windows, feature = "iocp") + ))] syscall_wait_table: DashMap>, Condvar)>>, selector: Poller, pool: CoroutinePool<'e>, @@ -91,9 +110,15 @@ impl<'e> EventLoop<'e> { stop: Arc::new((Mutex::new(false), Condvar::new())), shared_stop, cpu, - #[cfg(all(target_os = "linux", feature = "io_uring"))] + #[cfg(any( + all(target_os = "linux", feature = "io_uring"), + all(windows, feature = "iocp") + ))] operator: crate::net::operator::Operator::new(cpu)?, - #[cfg(all(target_os = "linux", feature = "io_uring"))] + #[cfg(any( + all(target_os = "linux", feature = "io_uring"), + all(windows, feature = "iocp") + ))] syscall_wait_table: DashMap::new(), selector: Poller::new()?, pool: CoroutinePool::new(name, stack_size, min_size, max_size, keep_alive_time), @@ -102,7 +127,7 @@ impl<'e> EventLoop<'e> { } #[allow(trivial_numeric_casts, clippy::cast_possible_truncation)] - fn token(syscall: Syscall) -> usize { + pub(crate) fn token(syscall: Syscall) -> usize { if let Some(co) = SchedulableCoroutine::current() { let boxed: &'static mut CString = Box::leak(Box::from( CString::new(co.name()).expect("build name failed!"), @@ -227,6 +252,8 @@ impl<'e> EventLoop<'e> { cfg_if::cfg_if! { if #[cfg(all(target_os = "linux", feature = "io_uring"))] { left_time = self.adapt_io_uring(left_time)?; + } else if #[cfg(all(windows, feature = "iocp"))] { + left_time = self.adapt_iocp(left_time)?; } } @@ -273,6 +300,47 @@ impl<'e> EventLoop<'e> { Ok(left_time) } + #[cfg(all(windows, feature = "iocp"))] + fn adapt_iocp(&self, mut left_time: Option) -> std::io::Result> { + // use IOCP + let (count, mut cq, left) = self.operator.select(left_time, 0)?; + if count > 0 { + for cqe in &mut cq { + let token = cqe.token; + // resolve completed read/write tasks + // todo refactor IOCP impl + let result = match cqe.syscall { + Syscall::accept => { + unsafe { + _ = setsockopt( + cqe.socket, + SOL_SOCKET, + SO_UPDATE_ACCEPT_CONTEXT, + std::ptr::from_ref::(&cqe.from_fd).cast(), + c_int::try_from(size_of::()).expect("overflow"), + ); + }; + cqe.socket.try_into().expect("result overflow") + } + Syscall::recv | Syscall::send => cqe.dw_number_of_bytes_transferred.into(), + _ => panic!("unsupported"), + }; + eprintln!("IOCP finish {token} {result}"); + if let Some((_, pair)) = self.syscall_wait_table.remove(&token) { + let (lock, cvar) = &*pair; + let mut pending = lock.lock().expect("lock failed"); + *pending = Some(result); + cvar.notify_one(); + } + unsafe { self.resume(token) }; + } + } + if left != left_time { + left_time = Some(left.unwrap_or(Duration::ZERO)); + } + Ok(left_time) + } + #[allow(clippy::unused_self)] unsafe fn resume(&self, token: usize) { if COROUTINE_TOKENS.remove(&token).is_none() { @@ -449,6 +517,34 @@ impl_io_uring!(writev(fd: c_int, iov: *const iovec, iovcnt: c_int) -> ssize_t); impl_io_uring!(pwritev(fd: c_int, iov: *const iovec, iovcnt: c_int, offset: off_t) -> ssize_t); impl_io_uring!(sendmsg(fd: c_int, msg: *const msghdr, flags: c_int) -> ssize_t); +macro_rules! impl_iocp { + ( $syscall: ident($($arg: ident : $arg_type: ty),*) -> $result: ty ) => { + #[cfg(all(windows, feature = "iocp"))] + impl EventLoop<'_> { + #[allow(non_snake_case, clippy::too_many_arguments)] + pub(super) fn $syscall( + &self, + $($arg: $arg_type),* + ) -> std::io::Result>, Condvar)>> { + let token = EventLoop::token(Syscall::$syscall); + self.operator.$syscall(token, $($arg, )*)?; + let arc = Arc::new((Mutex::new(None), Condvar::new())); + assert!( + self.syscall_wait_table.insert(token, arc.clone()).is_none(), + "The previous token was not retrieved in a timely manner" + ); + Ok(arc) + } + } + } +} + +impl_iocp!(accept(fd: SOCKET, addr: *mut SOCKADDR, len: *mut c_int) -> c_int); +impl_iocp!(recv(fd: SOCKET, buf: PSTR, len: c_int, flags: SEND_RECV_FLAGS) -> c_int); +impl_iocp!(WSARecv(fd: SOCKET, buf: *const WSABUF, dwbuffercount: c_uint, lpnumberofbytesrecvd: *mut c_uint, lpflags : *mut c_uint, lpoverlapped: *mut OVERLAPPED, lpcompletionroutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE) -> c_int); +impl_iocp!(send(fd: SOCKET, buf: PCSTR, len: c_int, flags: SEND_RECV_FLAGS) -> c_int); +impl_iocp!(WSASend(fd: SOCKET, buf: *const WSABUF, dwbuffercount: c_uint, lpnumberofbytesrecvd: *mut c_uint, dwflags : c_uint, lpoverlapped: *mut OVERLAPPED, lpcompletionroutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE) -> c_int); + #[cfg(all(test, not(all(unix, feature = "preemptive"))))] mod tests { use crate::net::event_loop::EventLoop; diff --git a/core/src/net/mod.rs b/core/src/net/mod.rs index a9283020..61d25dad 100644 --- a/core/src/net/mod.rs +++ b/core/src/net/mod.rs @@ -6,26 +6,45 @@ use crate::{error, info}; use once_cell::sync::OnceCell; use std::collections::VecDeque; use std::ffi::c_int; +#[cfg(any( + all(target_os = "linux", feature = "io_uring"), + all(windows, feature = "iocp") +))] +use std::ffi::c_longlong; use std::io::{Error, ErrorKind}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Condvar, Mutex}; use std::time::Duration; -/// 做C兼容时会用到 -pub type UserFunc = extern "C" fn(usize) -> usize; +cfg_if::cfg_if! { + if #[cfg(all(windows, feature = "iocp"))] { + use std::ffi::c_uint; + use windows_sys::core::{PCSTR, PSTR}; + use windows_sys::Win32::Networking::WinSock::{ + LPWSAOVERLAPPED_COMPLETION_ROUTINE, SEND_RECV_FLAGS, SOCKADDR, SOCKET, WSABUF, + }; + use windows_sys::Win32::System::IO::OVERLAPPED; + } +} cfg_if::cfg_if! { if #[cfg(all(target_os = "linux", feature = "io_uring"))] { use libc::{epoll_event, iovec, msghdr, off_t, size_t, sockaddr, socklen_t}; - use std::ffi::{c_longlong, c_void}; + use std::ffi::c_void; } } +/// 做C兼容时会用到 +pub type UserFunc = extern "C" fn(usize) -> usize; + mod selector; #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] -#[cfg(all(target_os = "linux", feature = "io_uring"))] -mod operator; +#[cfg(any( + all(target_os = "linux", feature = "io_uring"), + all(windows, feature = "iocp") +))] +pub(crate) mod operator; #[allow(missing_docs)] pub mod event_loop; @@ -119,7 +138,7 @@ impl EventLoops { } /// Get a `EventLoop`, prefer current. - fn event_loop() -> &'static EventLoop<'static> { + pub(crate) fn event_loop() -> &'static EventLoop<'static> { EventLoop::current().unwrap_or_else(|| Self::round_robin()) } @@ -274,3 +293,24 @@ impl_io_uring!(pwrite(fd: c_int, buf: *const c_void, count: size_t, offset: off_ impl_io_uring!(writev(fd: c_int, iov: *const iovec, iovcnt: c_int) -> ssize_t); impl_io_uring!(pwritev(fd: c_int, iov: *const iovec, iovcnt: c_int, offset: off_t) -> ssize_t); impl_io_uring!(sendmsg(fd: c_int, msg: *const msghdr, flags: c_int) -> ssize_t); + +macro_rules! impl_iocp { + ( $syscall: ident($($arg: ident : $arg_type: ty),*) -> $result: ty ) => { + #[allow(non_snake_case)] + #[cfg(all(windows, feature = "iocp"))] + impl EventLoops { + #[allow(missing_docs)] + pub fn $syscall( + $($arg: $arg_type),* + ) -> std::io::Result>, Condvar)>> { + Self::event_loop().$syscall($($arg, )*) + } + } + } +} + +impl_iocp!(accept(fd: SOCKET, addr: *mut SOCKADDR, len: *mut c_int) -> c_int); +impl_iocp!(recv(fd: SOCKET, buf: PSTR, len: c_int, flags: SEND_RECV_FLAGS) -> c_int); +impl_iocp!(WSARecv(fd: SOCKET, buf: *const WSABUF, dwbuffercount: c_uint, lpnumberofbytesrecvd: *mut c_uint, lpflags : *mut c_uint, lpoverlapped: *mut OVERLAPPED, lpcompletionroutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE) -> c_int); +impl_iocp!(send(fd: SOCKET, buf: PCSTR, len: c_int, flags: SEND_RECV_FLAGS) -> c_int); +impl_iocp!(WSASend(fd: SOCKET, buf: *const WSABUF, dwbuffercount: c_uint, lpnumberofbytesrecvd: *mut c_uint, dwflags : c_uint, lpoverlapped: *mut OVERLAPPED, lpcompletionroutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE) -> c_int); diff --git a/core/src/net/operator/linux/mod.rs b/core/src/net/operator/linux/mod.rs index 94d2bfd3..e9178d1b 100644 --- a/core/src/net/operator/linux/mod.rs +++ b/core/src/net/operator/linux/mod.rs @@ -574,7 +574,6 @@ impl Operator<'_> { ) } - #[allow(clippy::too_many_arguments)] pub(crate) fn sendto( &self, user_data: usize, diff --git a/core/src/net/operator/mod.rs b/core/src/net/operator/mod.rs index 6a821a4d..d75a5fd4 100644 --- a/core/src/net/operator/mod.rs +++ b/core/src/net/operator/mod.rs @@ -1,4 +1,11 @@ +#[allow(clippy::too_many_arguments)] #[cfg(all(target_os = "linux", feature = "io_uring"))] mod linux; #[cfg(all(target_os = "linux", feature = "io_uring"))] pub(crate) use linux::*; + +#[allow(non_snake_case, clippy::too_many_arguments)] +#[cfg(all(windows, feature = "iocp"))] +mod windows; +#[cfg(all(windows, feature = "iocp"))] +pub(crate) use windows::*; diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs new file mode 100644 index 00000000..a97262e6 --- /dev/null +++ b/core/src/net/operator/windows.rs @@ -0,0 +1,366 @@ +use crate::common::constants::Syscall; +use crate::common::{get_timeout_time, now}; +use dashmap::{DashMap, DashSet}; +use once_cell::sync::Lazy; +use std::ffi::{c_int, c_uint}; +use std::io::{Error, ErrorKind}; +use std::marker::PhantomData; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::time::{Duration, Instant}; +use windows_sys::core::{PCSTR, PSTR}; +use windows_sys::Win32::Foundation::{ + ERROR_NETNAME_DELETED, FALSE, HANDLE, INVALID_HANDLE_VALUE, WAIT_TIMEOUT, +}; +use windows_sys::Win32::Networking::WinSock::{ + closesocket, AcceptEx, WSAGetLastError, WSARecv, WSASend, WSASocketW, INVALID_SOCKET, IPPROTO, + LPWSAOVERLAPPED_COMPLETION_ROUTINE, SEND_RECV_FLAGS, SOCKADDR, SOCKADDR_IN, SOCKET, + SOCKET_ERROR, WINSOCK_SOCKET_TYPE, WSABUF, WSA_FLAG_OVERLAPPED, WSA_IO_PENDING, +}; +use windows_sys::Win32::System::IO::{ + CreateIoCompletionPort, GetQueuedCompletionStatus, OVERLAPPED, +}; + +#[repr(C)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub(crate) struct SocketContext { + pub(crate) domain: c_int, + pub(crate) ty: WINSOCK_SOCKET_TYPE, + pub(crate) protocol: IPPROTO, +} + +pub(crate) static SOCKET_CONTEXT: Lazy> = + Lazy::new(Default::default); + +/// The overlapped struct we actually used for IOCP. +#[repr(C)] +pub(crate) struct Overlapped { + /// The base [`OVERLAPPED`]. + pub base: OVERLAPPED, + pub from_fd: SOCKET, + pub socket: SOCKET, + pub token: usize, + pub syscall: Syscall, + pub dw_number_of_bytes_transferred: u32, +} + +#[repr(C)] +#[derive(Debug)] +pub(crate) struct Operator<'o> { + iocp: HANDLE, + entering: AtomicBool, + handles: DashSet, + phantom_data: PhantomData<&'o HANDLE>, +} + +impl Operator<'_> { + pub(crate) fn new(_cpu: usize) -> std::io::Result { + let iocp = + unsafe { CreateIoCompletionPort(INVALID_HANDLE_VALUE, std::ptr::null_mut(), 0, 0) }; + if iocp.is_null() { + return Err(Error::last_os_error()); + } + Ok(Self { + iocp, + entering: AtomicBool::new(false), + handles: DashSet::default(), + phantom_data: PhantomData, + }) + } + + /// Associates a new `HANDLE` to this I/O completion port. + /// + /// This function will associate the given handle to this port with the + /// given `token` to be returned in status messages whenever it receives a + /// notification. + /// + /// Any object which is convertible to a `HANDLE` via the `AsRawHandle` + /// trait can be provided to this function, such as `std::fs::File` and + /// friends. + fn add_handle(&self, token: usize, handle: HANDLE) -> std::io::Result<()> { + if self.handles.contains(&handle) { + return Ok(()); + } + let ret = unsafe { CreateIoCompletionPort(handle, self.iocp, token, 0) }; + if ret.is_null() { + return Err(Error::new( + ErrorKind::Other, + format!("bind handle:{} to IOCP failed", handle as usize), + )); + } + debug_assert_eq!(ret, self.iocp); + Ok(()) + } + + pub(crate) fn select( + &self, + timeout: Option, + want: usize, + ) -> std::io::Result<(usize, Vec, Option)> { + if self + .entering + .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) + .is_err() + { + return Ok((0, Vec::new(), timeout)); + } + let result = self.do_select(timeout, want); + self.entering.store(false, Ordering::Release); + result + } + + #[allow(clippy::unnecessary_wraps)] + fn do_select( + &self, + timeout: Option, + want: usize, + ) -> std::io::Result<(usize, Vec, Option)> { + let start_time = Instant::now(); + let timeout_time = timeout.map_or(u64::MAX, get_timeout_time); + let mut cq = Vec::new(); + loop { + let mut bytes = 0; + let mut token = 0; + let mut overlapped: Overlapped = unsafe { std::mem::zeroed() }; + let ret = unsafe { + GetQueuedCompletionStatus( + self.iocp, + &mut bytes, + &mut token, + std::ptr::from_mut::(&mut overlapped).cast(), + 1, + ) + }; + if ret == FALSE { + let err = Error::last_os_error().raw_os_error(); + if Some(ERROR_NETNAME_DELETED.try_into().expect("overflow")) == err + || Some(WAIT_TIMEOUT.try_into().expect("overflow")) == err + { + _ = unsafe { closesocket(overlapped.socket) }; + if cq.len() >= want || timeout_time.saturating_sub(now()) == 0 { + break; + } + continue; + } + } + overlapped.token = token; + overlapped.dw_number_of_bytes_transferred = bytes; + cq.push(overlapped); + if cq.len() >= want || timeout_time.saturating_sub(now()) == 0 { + break; + } + } + let cost = Instant::now().saturating_duration_since(start_time); + Ok((cq.len(), cq, timeout.map(|t| t.saturating_sub(cost)))) + } + + pub(crate) fn accept( + &self, + user_data: usize, + fd: SOCKET, + _address: *mut SOCKADDR, + _address_len: *mut c_int, + ) -> std::io::Result<()> { + self.add_handle(fd, fd as HANDLE)?; + let context = SOCKET_CONTEXT.get(&fd).expect("socket context not found"); + let ctx = context.value(); + unsafe { + let socket = WSASocketW( + ctx.domain, + ctx.ty, + ctx.protocol, + std::ptr::null(), + 0, + WSA_FLAG_OVERLAPPED, + ); + if INVALID_SOCKET == socket { + return Err(Error::new( + ErrorKind::WouldBlock, + "add accept operation failed", + )); + } + let size = size_of::() + .saturating_add(16) + .try_into() + .expect("size overflow"); + let mut overlapped: Overlapped = std::mem::zeroed(); + overlapped.from_fd = fd; + overlapped.socket = socket; + overlapped.token = user_data; + overlapped.syscall = Syscall::accept; + while AcceptEx( + fd, + socket, + std::ptr::null_mut(), + 0, + size, + size, + std::ptr::null_mut(), + std::ptr::from_mut::(&mut overlapped).cast(), + ) == FALSE + { + if WSA_IO_PENDING == WSAGetLastError() { + break; + } + } + } + Ok(()) + } + + pub(crate) fn recv( + &self, + user_data: usize, + fd: SOCKET, + buf: PSTR, + len: c_int, + flags: SEND_RECV_FLAGS, + ) -> std::io::Result<()> { + self.add_handle(fd, fd as HANDLE)?; + unsafe { + let mut overlapped: Overlapped = std::mem::zeroed(); + overlapped.from_fd = fd; + overlapped.token = user_data; + overlapped.syscall = Syscall::recv; + let buf = [WSABUF { + len: len.try_into().expect("len overflow"), + buf: buf.cast(), + }]; + if WSARecv( + fd, + buf.as_ptr(), + buf.len().try_into().expect("len overflow"), + std::ptr::null_mut(), + &mut u32::try_from(flags).expect("overflow"), + std::ptr::from_mut::(&mut overlapped).cast(), + None, + ) == SOCKET_ERROR + && WSA_IO_PENDING != WSAGetLastError() + { + return Err(Error::new( + ErrorKind::WouldBlock, + "add recv operation failed", + )); + } + } + Ok(()) + } + + pub(crate) fn WSARecv( + &self, + user_data: usize, + fd: SOCKET, + buf: *const WSABUF, + dwbuffercount: c_uint, + lpnumberofbytesrecvd: *mut c_uint, + lpflags: *mut c_uint, + lpoverlapped: *mut OVERLAPPED, + lpcompletionroutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> std::io::Result<()> { + assert!( + lpoverlapped.is_null(), + "the WSARecv in Operator should be called without lpoverlapped! Correct your code!" + ); + self.add_handle(fd, fd as HANDLE)?; + unsafe { + let mut overlapped: Overlapped = std::mem::zeroed(); + overlapped.from_fd = fd; + overlapped.token = user_data; + overlapped.syscall = Syscall::WSARecv; + if WSARecv( + fd, + buf, + dwbuffercount, + lpnumberofbytesrecvd, + lpflags, + std::ptr::from_mut::(&mut overlapped).cast(), + lpcompletionroutine, + ) == SOCKET_ERROR + && WSA_IO_PENDING != WSAGetLastError() + { + return Err(Error::new( + ErrorKind::WouldBlock, + "add WSARecv operation failed", + )); + } + } + Ok(()) + } + + pub(crate) fn send( + &self, + user_data: usize, + fd: SOCKET, + buf: PCSTR, + len: c_int, + flags: SEND_RECV_FLAGS, + ) -> std::io::Result<()> { + self.add_handle(fd, fd as HANDLE)?; + unsafe { + let mut overlapped: Overlapped = std::mem::zeroed(); + overlapped.from_fd = fd; + overlapped.token = user_data; + overlapped.syscall = Syscall::send; + let buf = [WSABUF { + len: len.try_into().expect("len overflow"), + buf: buf.cast_mut(), + }]; + if WSASend( + fd, + buf.as_ptr(), + buf.len().try_into().expect("len overflow"), + std::ptr::null_mut(), + u32::try_from(flags).expect("overflow"), + std::ptr::from_mut::(&mut overlapped).cast(), + None, + ) == SOCKET_ERROR + && WSA_IO_PENDING != WSAGetLastError() + { + return Err(Error::new( + ErrorKind::WouldBlock, + "add send operation failed", + )); + } + } + Ok(()) + } + + pub(crate) fn WSASend( + &self, + user_data: usize, + fd: SOCKET, + buf: *const WSABUF, + dwbuffercount: c_uint, + lpnumberofbytesrecvd: *mut c_uint, + dwflags: c_uint, + lpoverlapped: *mut OVERLAPPED, + lpcompletionroutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> std::io::Result<()> { + assert!( + lpoverlapped.is_null(), + "the WSASend in Operator should be called without lpoverlapped! Correct your code!" + ); + self.add_handle(fd, fd as HANDLE)?; + unsafe { + let mut overlapped: Overlapped = std::mem::zeroed(); + overlapped.from_fd = fd; + overlapped.token = user_data; + overlapped.syscall = Syscall::WSASend; + if WSASend( + fd, + buf, + dwbuffercount, + lpnumberofbytesrecvd, + dwflags, + std::ptr::from_mut::(&mut overlapped).cast(), + lpcompletionroutine, + ) == SOCKET_ERROR + && WSA_IO_PENDING != WSAGetLastError() + { + return Err(Error::new( + ErrorKind::WouldBlock, + "add WSASend operation failed", + )); + } + } + Ok(()) + } +} diff --git a/core/src/syscall/unix/mod.rs b/core/src/syscall/unix/mod.rs index 9db30ec4..94cb1da4 100644 --- a/core/src/syscall/unix/mod.rs +++ b/core/src/syscall/unix/mod.rs @@ -23,7 +23,8 @@ macro_rules! impl_facade { let new_state = $crate::common::constants::SyscallState::Executing; if co.syscall((), syscall, new_state).is_err() { $crate::error!("{} change to syscall {} {} failed !", - co.name(), syscall, new_state); + co.name(), syscall, new_state + ); } } let r = self.inner.$syscall(fn_ptr, $($arg, )*); @@ -66,9 +67,7 @@ macro_rules! impl_io_uring { if co.syscall((), syscall, new_state).is_err() { $crate::error!( "{} change to syscall {} {} failed !", - co.name(), - syscall, - new_state + co.name(), syscall, new_state ); } } @@ -84,9 +83,7 @@ macro_rules! impl_io_uring { if co.syscall((), syscall, new_state).is_err() { $crate::error!( "{} change to syscall {} {} failed !", - co.name(), - syscall, - new_state + co.name(), syscall, new_state ); } } diff --git a/core/src/syscall/windows/WSARecv.rs b/core/src/syscall/windows/WSARecv.rs index e6f1eb26..e9286d87 100644 --- a/core/src/syscall/windows/WSARecv.rs +++ b/core/src/syscall/windows/WSARecv.rs @@ -24,8 +24,16 @@ pub extern "system" fn WSARecv( lpoverlapped: *mut OVERLAPPED, lpcompletionroutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, ) -> c_int { - static CHAIN: Lazy>> = - Lazy::new(Default::default); + cfg_if::cfg_if! { + if #[cfg(all(windows, feature = "iocp"))] { + static CHAIN: Lazy< + WSARecvSyscallFacade>> + > = Lazy::new(Default::default); + } else { + static CHAIN: Lazy>> = + Lazy::new(Default::default); + } + } CHAIN.WSARecv( fn_ptr, fd, @@ -74,6 +82,123 @@ impl_facade!(WSARecvSyscallFacade, WSARecvSyscall, ) -> c_int ); +#[cfg(all(windows, feature = "iocp"))] +#[repr(C)] +#[derive(Debug, Default)] +struct IocpWSARecvSyscall { + inner: I, +} + +#[cfg(all(windows, feature = "iocp"))] +impl WSARecvSyscall for IocpWSARecvSyscall { + #[allow(clippy::too_many_lines)] + extern "system" fn WSARecv( + &self, + fn_ptr: Option< + &extern "system" fn( + SOCKET, + *const WSABUF, + c_uint, + *mut c_uint, + *mut c_uint, + *mut OVERLAPPED, + LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> c_int, + >, + fd: SOCKET, + buf: *const WSABUF, + dwbuffercount: c_uint, + lpnumberofbytesrecvd: *mut c_uint, + lpflags: *mut c_uint, + lpoverlapped: *mut OVERLAPPED, + lpcompletionroutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> c_int { + use windows_sys::Win32::Networking::WinSock::{SOCKET_ERROR, WSAEWOULDBLOCK}; + use crate::common::constants::{CoroutineState, SyscallState}; + use crate::net::EventLoops; + use crate::scheduler::{SchedulableCoroutine, SchedulableSuspender}; + + if !lpoverlapped.is_null() { + return RawWSARecvSyscall::default().WSARecv( + fn_ptr, + fd, + buf, + dwbuffercount, + lpnumberofbytesrecvd, + lpflags, + lpoverlapped, + lpcompletionroutine, + ); + } + match EventLoops::WSARecv(fd, buf, dwbuffercount, lpnumberofbytesrecvd, lpflags, lpoverlapped, lpcompletionroutine) { + Ok(arc) => { + if let Some(co) = SchedulableCoroutine::current() { + if let CoroutineState::SystemCall((), syscall, SyscallState::Executing) = co.state() + { + let new_state = SyscallState::Suspend(u64::MAX); + 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::SystemCall((), 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: c_int = cvar + .wait_while(lock.lock().expect("lock failed"), + |&mut result| result.is_none() + ) + .expect("lock failed") + .expect("no syscall result") + .try_into() + .expect("IOCP syscall result overflow"); + // fixme 错误处理 + // if syscall_result < 0 { + // let errno: std::ffi::c_int = (-syscall_result).try_into() + // .expect("IOCP errno overflow"); + // $crate::syscall::common::set_errno(errno); + // syscall_result = -1; + // } + syscall_result + } + Err(e) => { + if e.kind() == std::io::ErrorKind::Other { + self.inner.WSARecv( + fn_ptr, + fd, + buf, + dwbuffercount, + lpnumberofbytesrecvd, + lpflags, + lpoverlapped, + lpcompletionroutine, + ) + } else { + crate::syscall::common::set_errno(WSAEWOULDBLOCK.try_into().expect("overflow")); + SOCKET_ERROR + } + } + } + } +} + impl_nio_read_iovec!(NioWSARecvSyscall, WSARecvSyscall, WSARecv( fd: SOCKET, diff --git a/core/src/syscall/windows/WSASend.rs b/core/src/syscall/windows/WSASend.rs index c0675695..8195c8e9 100644 --- a/core/src/syscall/windows/WSASend.rs +++ b/core/src/syscall/windows/WSASend.rs @@ -24,8 +24,16 @@ pub extern "system" fn WSASend( lpoverlapped: *mut OVERLAPPED, lpcompletionroutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, ) -> c_int { - static CHAIN: Lazy>> = - Lazy::new(Default::default); + cfg_if::cfg_if! { + if #[cfg(all(windows, feature = "iocp"))] { + static CHAIN: Lazy< + WSASendSyscallFacade>> + > = Lazy::new(Default::default); + } else { + static CHAIN: Lazy>> = + Lazy::new(Default::default); + } + } CHAIN.WSASend( fn_ptr, fd, @@ -38,7 +46,7 @@ pub extern "system" fn WSASend( ) } -trait WSARecvSyscall { +trait WSASendSyscall { extern "system" fn WSASend( &self, fn_ptr: Option< @@ -62,7 +70,7 @@ trait WSARecvSyscall { ) -> c_int; } -impl_facade!(WSARecvSyscallFacade, WSARecvSyscall, +impl_facade!(WSASendSyscallFacade, WSASendSyscall, WSASend( fd: SOCKET, buf: *const WSABUF, @@ -74,7 +82,123 @@ impl_facade!(WSARecvSyscallFacade, WSARecvSyscall, ) -> c_int ); -impl_nio_write_iovec!(NioWSARecvSyscall, WSARecvSyscall, +#[cfg(all(windows, feature = "iocp"))] +#[repr(C)] +#[derive(Debug, Default)] +struct IocpWSASendSyscall { + inner: I, +} + +#[cfg(all(windows, feature = "iocp"))] +impl WSASendSyscall for IocpWSASendSyscall { + extern "system" fn WSASend( + &self, + fn_ptr: Option< + &extern "system" fn( + SOCKET, + *const WSABUF, + c_uint, + *mut c_uint, + c_uint, + *mut OVERLAPPED, + LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> c_int, + >, + fd: SOCKET, + buf: *const WSABUF, + dwbuffercount: c_uint, + lpnumberofbytesrecvd: *mut c_uint, + dwflags: c_uint, + lpoverlapped: *mut OVERLAPPED, + lpcompletionroutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> c_int { + use windows_sys::Win32::Networking::WinSock::{SOCKET_ERROR, WSAEWOULDBLOCK}; + use crate::common::constants::{CoroutineState, SyscallState}; + use crate::net::EventLoops; + use crate::scheduler::{SchedulableCoroutine, SchedulableSuspender}; + + if !lpoverlapped.is_null() { + return RawWSASendSyscall::default().WSASend( + fn_ptr, + fd, + buf, + dwbuffercount, + lpnumberofbytesrecvd, + dwflags, + lpoverlapped, + lpcompletionroutine, + ); + } + match EventLoops::WSASend(fd, buf, dwbuffercount, lpnumberofbytesrecvd, dwflags, lpoverlapped, lpcompletionroutine) { + Ok(arc) => { + if let Some(co) = SchedulableCoroutine::current() { + if let CoroutineState::SystemCall((), syscall, SyscallState::Executing) = co.state() + { + let new_state = SyscallState::Suspend(u64::MAX); + 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::SystemCall((), 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: c_int = cvar + .wait_while(lock.lock().expect("lock failed"), + |&mut result| result.is_none() + ) + .expect("lock failed") + .expect("no syscall result") + .try_into() + .expect("IOCP syscall result overflow"); + // fixme 错误处理 + // if syscall_result < 0 { + // let errno: std::ffi::c_int = (-syscall_result).try_into() + // .expect("IOCP errno overflow"); + // $crate::syscall::common::set_errno(errno); + // syscall_result = -1; + // } + syscall_result + } + Err(e) => { + if e.kind() == std::io::ErrorKind::Other { + self.inner.WSASend( + fn_ptr, + fd, + buf, + dwbuffercount, + lpnumberofbytesrecvd, + dwflags, + lpoverlapped, + lpcompletionroutine, + ) + } else { + crate::syscall::common::set_errno(WSAEWOULDBLOCK.try_into().expect("overflow")); + SOCKET_ERROR + } + } + } + } +} + +impl_nio_write_iovec!(NioWSASendSyscall, WSASendSyscall, WSASend( fd: SOCKET, buf: *const WSABUF, @@ -86,7 +210,7 @@ impl_nio_write_iovec!(NioWSARecvSyscall, WSARecvSyscall, ) -> c_int ); -impl_raw!(RawWSARecvSyscall, WSARecvSyscall, windows_sys::Win32::Networking::WinSock, +impl_raw!(RawWSASendSyscall, WSASendSyscall, windows_sys::Win32::Networking::WinSock, WSASend( fd: SOCKET, buf: *const WSABUF, diff --git a/core/src/syscall/windows/WSASocketW.rs b/core/src/syscall/windows/WSASocketW.rs index fe0022ef..f653a217 100644 --- a/core/src/syscall/windows/WSASocketW.rs +++ b/core/src/syscall/windows/WSASocketW.rs @@ -1,8 +1,6 @@ use once_cell::sync::Lazy; use std::ffi::{c_int, c_uint}; -use windows_sys::Win32::Networking::WinSock::{ - IPPROTO, SOCKET, WINSOCK_SOCKET_TYPE, WSAPROTOCOL_INFOW, -}; +use windows_sys::Win32::Networking::WinSock::{IPPROTO, SOCKET, WINSOCK_SOCKET_TYPE, WSAPROTOCOL_INFOW}; #[must_use] pub extern "system" fn WSASocketW( @@ -23,7 +21,7 @@ pub extern "system" fn WSASocketW( g: c_uint, dw_flags: c_uint, ) -> SOCKET { - static CHAIN: Lazy> = Lazy::new(Default::default); + static CHAIN: Lazy>> = Lazy::new(Default::default); CHAIN.WSASocketW(fn_ptr, domain, ty, protocol, lpprotocolinfo, g, dw_flags) } @@ -60,6 +58,45 @@ impl_facade!(WSASocketWSyscallFacade, WSASocketWSyscall, ) -> SOCKET ); +#[repr(C)] +#[derive(Debug, Default)] +struct NioWSASocketWSyscall { + inner: I, +} + +impl WSASocketWSyscall for NioWSASocketWSyscall { + extern "system" fn WSASocketW( + &self, + fn_ptr: Option< + &extern "system" fn( + c_int, + WINSOCK_SOCKET_TYPE, + IPPROTO, + *const WSAPROTOCOL_INFOW, + c_uint, + c_uint, + ) -> SOCKET, + >, + domain: c_int, + ty: WINSOCK_SOCKET_TYPE, + protocol: IPPROTO, + lpprotocolinfo: *const WSAPROTOCOL_INFOW, + g: c_uint, + dw_flags: c_uint + ) -> SOCKET { + let r = self.inner.WSASocketW(fn_ptr, domain, ty, protocol, lpprotocolinfo, g, dw_flags); + #[cfg(feature = "iocp")] + if windows_sys::Win32::Networking::WinSock::INVALID_SOCKET != r { + _ = crate::net::operator::SOCKET_CONTEXT.insert(r,crate::net::operator::SocketContext{ + domain, + ty, + protocol, + }); + } + r + } +} + impl_raw!(RawWSASocketWSyscall, WSASocketWSyscall, windows_sys::Win32::Networking::WinSock, WSASocketW( domain: c_int, diff --git a/core/src/syscall/windows/accept.rs b/core/src/syscall/windows/accept.rs index dbf1dd60..f70f13e2 100644 --- a/core/src/syscall/windows/accept.rs +++ b/core/src/syscall/windows/accept.rs @@ -9,8 +9,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 +36,10 @@ impl_facade!(AcceptSyscallFacade, AcceptSyscall, accept(fd: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET ); +impl_iocp!(IocpAcceptSyscall, AcceptSyscall, + accept(fd: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET +); + 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 0738f39c..cd2f25a7 100644 --- a/core/src/syscall/windows/mod.rs +++ b/core/src/syscall/windows/mod.rs @@ -43,6 +43,91 @@ macro_rules! impl_facade { } } +macro_rules! impl_iocp { + ( $struct_name:ident, $trait_name: ident, $syscall: ident($($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($($arg_type),*) -> $result>, + $($arg: $arg_type),* + ) -> $result { + use $crate::common::constants::{CoroutineState, SyscallState}; + use $crate::scheduler::{SchedulableCoroutine, SchedulableSuspender}; + + match $crate::net::EventLoops::$syscall($($arg, )*) { + Ok(arc) => { + if let Some(co) = SchedulableCoroutine::current() { + if let CoroutineState::SystemCall((), syscall, SyscallState::Executing) = co.state() + { + let new_state = SyscallState::Suspend(u64::MAX); + 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::SystemCall((), 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: $result = cvar + .wait_while(lock.lock().expect("lock failed"), + |&mut result| result.is_none() + ) + .expect("lock failed") + .expect("no syscall result") + .try_into() + .expect("IOCP syscall result overflow"); + // fixme 错误处理 + // if syscall_result < 0 { + // let errno: std::ffi::c_int = (-syscall_result).try_into() + // .expect("IOCP errno overflow"); + // $crate::syscall::common::set_errno(errno); + // syscall_result = -1; + // } + syscall_result + } + Err(e) => { + if e.kind() == std::io::ErrorKind::Other { + self.inner.$syscall(fn_ptr, $($arg, )*) + } else { + $crate::syscall::common::set_errno( + windows_sys::Win32::Networking::WinSock::WSAEWOULDBLOCK.try_into().expect("overflow") + ); + windows_sys::Win32::Networking::WinSock::SOCKET_ERROR.try_into().expect("overflow") + } + } + } + } + } + } +} + macro_rules! impl_nio_read { ( $struct_name:ident, $trait_name: ident, $syscall: ident($fd: ident : $fd_type: ty, $($arg: ident : $arg_type: ty),*) -> $result: ty ) => { #[repr(C)] diff --git a/core/src/syscall/windows/recv.rs b/core/src/syscall/windows/recv.rs index b9d822f7..a0b28fc3 100644 --- a/core/src/syscall/windows/recv.rs +++ b/core/src/syscall/windows/recv.rs @@ -11,8 +11,16 @@ pub extern "system" fn recv( len: c_int, flags: SEND_RECV_FLAGS, ) -> c_int { - static CHAIN: Lazy>> = - Lazy::new(Default::default); + cfg_if::cfg_if! { + if #[cfg(all(windows, feature = "iocp"))] { + static CHAIN: Lazy< + RecvSyscallFacade>> + > = Lazy::new(Default::default); + } else { + static CHAIN: Lazy>> = + Lazy::new(Default::default); + } + } CHAIN.recv(fn_ptr, fd, buf, len, flags) } @@ -31,6 +39,10 @@ impl_facade!(RecvSyscallFacade, RecvSyscall, recv(fd: SOCKET, buf: PSTR, len: c_int, flags: SEND_RECV_FLAGS) -> c_int ); +impl_iocp!(IocpRecvSyscall, RecvSyscall, + recv(fd: SOCKET, buf: PSTR, len: c_int, flags: SEND_RECV_FLAGS) -> c_int +); + impl_nio_read_buf!(NioRecvSyscall, RecvSyscall, recv(fd: SOCKET, buf: PSTR, len: c_int, flags: SEND_RECV_FLAGS) -> c_int ); diff --git a/core/src/syscall/windows/send.rs b/core/src/syscall/windows/send.rs index 8b87be11..16d7af4f 100644 --- a/core/src/syscall/windows/send.rs +++ b/core/src/syscall/windows/send.rs @@ -11,8 +11,16 @@ pub extern "system" fn send( len: c_int, flags: SEND_RECV_FLAGS, ) -> c_int { - static CHAIN: Lazy>> = - Lazy::new(Default::default); + cfg_if::cfg_if! { + if #[cfg(all(windows, feature = "iocp"))] { + static CHAIN: Lazy< + SendSyscallFacade>> + > = Lazy::new(Default::default); + } else { + static CHAIN: Lazy>> = + Lazy::new(Default::default); + } + } CHAIN.send(fn_ptr, fd, buf, len, flags) } @@ -31,6 +39,10 @@ impl_facade!(SendSyscallFacade, SendSyscall, send(fd: SOCKET, buf: PCSTR, len: c_int, flags: SEND_RECV_FLAGS) -> c_int ); +impl_iocp!(IocpSendSyscall, SendSyscall, + send(fd: SOCKET, buf: PCSTR, len: c_int, flags: SEND_RECV_FLAGS) -> c_int +); + impl_nio_write_buf!(NioSendSyscall, SendSyscall, send(fd: SOCKET, buf: PCSTR, len: c_int, flags: SEND_RECV_FLAGS) -> c_int ); diff --git a/core/src/syscall/windows/socket.rs b/core/src/syscall/windows/socket.rs index aff69705..b5ca20fc 100644 --- a/core/src/syscall/windows/socket.rs +++ b/core/src/syscall/windows/socket.rs @@ -9,7 +9,7 @@ pub extern "system" fn socket( ty: WINSOCK_SOCKET_TYPE, protocol: IPPROTO, ) -> SOCKET { - static CHAIN: Lazy> = Lazy::new(Default::default); + static CHAIN: Lazy>> = Lazy::new(Default::default); CHAIN.socket(fn_ptr, domain, ty, protocol) } @@ -27,6 +27,27 @@ impl_facade!(SocketSyscallFacade, SocketSyscall, socket(domain: c_int, ty: WINSOCK_SOCKET_TYPE, protocol: IPPROTO) -> SOCKET ); +#[repr(C)] +#[derive(Debug, Default)] +struct NioSocketSyscall { + inner: I, +} + +impl SocketSyscall for NioSocketSyscall { + extern "system" fn socket(&self, fn_ptr: Option<&extern "system" fn(c_int, WINSOCK_SOCKET_TYPE, IPPROTO) -> SOCKET>, domain: c_int, ty: WINSOCK_SOCKET_TYPE, protocol: IPPROTO) -> SOCKET { + let r = self.inner.socket(fn_ptr, domain, ty, protocol); + #[cfg(feature = "iocp")] + if windows_sys::Win32::Networking::WinSock::INVALID_SOCKET != r { + _ = crate::net::operator::SOCKET_CONTEXT.insert(r,crate::net::operator::SocketContext{ + domain, + ty, + protocol, + }); + } + r + } +} + impl_raw!(RawSocketSyscall, SocketSyscall, windows_sys::Win32::Networking::WinSock, socket(domain: c_int, ty: WINSOCK_SOCKET_TYPE, protocol: IPPROTO) -> SOCKET ); diff --git a/hook/Cargo.toml b/hook/Cargo.toml index 47c4f4a5..f82ab70b 100644 --- a/hook/Cargo.toml +++ b/hook/Cargo.toml @@ -44,6 +44,12 @@ net = ["open-coroutine-core/net"] # Provide io_uring adaptation, this feature only works in linux. io_uring = ["open-coroutine-core/io_uring"] +# Provide IOCP adaptation, this feature only works in windows. +iocp = ["open-coroutine-core/iocp"] + +# Provide completion IOCP adaptation +completion_io = ["open-coroutine-core/completion_io"] + # Provide syscall implementation. syscall = ["open-coroutine-core/syscall"] diff --git a/open-coroutine/Cargo.toml b/open-coroutine/Cargo.toml index 8dacd906..60d21d1f 100644 --- a/open-coroutine/Cargo.toml +++ b/open-coroutine/Cargo.toml @@ -56,5 +56,11 @@ net = ["open-coroutine-hook/net", "open-coroutine-core/net"] # This feature only works in linux. io_uring = ["open-coroutine-hook/io_uring", "open-coroutine-core/io_uring"] +# Provide IOCP adaptation, this feature only works in windows. +iocp = ["open-coroutine-hook/iocp", "open-coroutine-core/iocp"] + +# Provide completion IOCP adaptation +completion_io = ["open-coroutine-hook/completion_io", "open-coroutine-core/completion_io"] + # Provide syscall implementation. syscall = ["open-coroutine-hook/syscall", "open-coroutine-core/syscall"] diff --git a/open-coroutine/build.rs b/open-coroutine/build.rs index 38c3cfc6..0882f98d 100644 --- a/open-coroutine/build.rs +++ b/open-coroutine/build.rs @@ -146,6 +146,12 @@ fn main() { if cfg!(feature = "io_uring") { features.push("io_uring"); } + if cfg!(feature = "iocp") { + features.push("iocp"); + } + if cfg!(feature = "completion_io") { + features.push("completion_io"); + } if cfg!(feature = "syscall") { features.push("syscall"); } diff --git a/open-coroutine/src/lib.rs b/open-coroutine/src/lib.rs index 205ae160..62b0d65f 100644 --- a/open-coroutine/src/lib.rs +++ b/open-coroutine/src/lib.rs @@ -134,10 +134,9 @@ pub struct JoinHandle(open_coroutine_core::net::join::JoinHandle, PhantomData #[allow(missing_docs)] impl JoinHandle { - #[allow(clippy::cast_possible_truncation)] pub fn timeout_join(&self, dur: Duration) -> std::io::Result> { unsafe { - let ptr = task_timeout_join(self, dur.as_nanos() as u64); + let ptr = task_timeout_join(self, dur.as_nanos().try_into().expect("overflow")); match ptr.cmp(&0) { Ordering::Less => Err(Error::new(ErrorKind::Other, "timeout join failed")), Ordering::Equal => Ok(None), From 31a425fd61c4f925876fb32ccbbfc7a60435891d Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Wed, 13 Nov 2024 09:33:07 +0800 Subject: [PATCH 02/42] fix workflow --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9e00d2ac..2129a622 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: toolchain: ${{ matrix.target == 'i686-pc-windows-gnu' && format('{0}-i686-pc-windows-gnu', matrix.channel) || matrix.channel }} target: ${{ matrix.target }} override: true - components: rustfmt + components: rustfmt, clippy - name: Check code format uses: actions-rs/cargo@v1 with: @@ -31,12 +31,12 @@ jobs: uses: actions-rs/cargo@v1 with: command: clippy - args: --all + args: --all -- -D warnings - name: Check clippy with all features uses: actions-rs/cargo@v1 with: command: clippy - args: --all --all-features + args: --all --all-features -- -D warnings - name: Run cargo deny if: ${{ contains(matrix.os, 'ubuntu') }} uses: EmbarkStudios/cargo-deny-action@v2 From 11442dc4ce630419746f6f40b97b3884611173a2 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Wed, 13 Nov 2024 10:04:14 +0800 Subject: [PATCH 03/42] fix linux CI --- core/src/net/event_loop.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/net/event_loop.rs b/core/src/net/event_loop.rs index e37c4dfd..3dc883b1 100644 --- a/core/src/net/event_loop.rs +++ b/core/src/net/event_loop.rs @@ -7,7 +7,7 @@ use crate::{error, impl_current_for, impl_display_by_debug, info}; use crossbeam_utils::atomic::AtomicCell; use dashmap::DashSet; #[cfg(all(target_os = "linux", feature = "io_uring"))] -use libc::{epoll_event, iovec, msghdr, off_t, size_t, sockaddr, socklen_t, ssize_t}; +use libc::{epoll_event, iovec, msghdr, off_t, size_t, sockaddr, socklen_t}; use once_cell::sync::Lazy; use rand::Rng; use std::ffi::{c_char, c_int, c_void, CStr, CString}; @@ -282,7 +282,7 @@ impl<'e> EventLoop<'e> { continue; } // resolve completed read/write tasks - let result = cqe.result() as c_longlong; + let result = c_longlong::from(cqe.result()); eprintln!("io_uring finish {token} {result}"); if let Some((_, pair)) = self.syscall_wait_table.remove(&token) { let (lock, cvar) = &*pair; From 944541199cd163af97ef03fafa6944e1c4e54591 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Wed, 13 Nov 2024 10:21:48 +0800 Subject: [PATCH 04/42] hook connect --- core/src/syscall/unix/connect.rs | 2 +- core/src/syscall/windows/connect.rs | 106 ++++++++++++++++++++++++++++ core/src/syscall/windows/mod.rs | 1 + hook/src/syscall/windows.rs | 5 ++ 4 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 core/src/syscall/windows/connect.rs diff --git a/core/src/syscall/unix/connect.rs b/core/src/syscall/unix/connect.rs index 501fdb9e..0ad92684 100644 --- a/core/src/syscall/unix/connect.rs +++ b/core/src/syscall/unix/connect.rs @@ -81,7 +81,7 @@ impl ConnectSyscall for NioConnectSyscall { fd, libc::SOL_SOCKET, libc::SO_ERROR, - (std::ptr::addr_of_mut!(err)).cast::(), + std::ptr::addr_of_mut!(err).cast::(), &mut len, ); } diff --git a/core/src/syscall/windows/connect.rs b/core/src/syscall/windows/connect.rs new file mode 100644 index 00000000..be40d197 --- /dev/null +++ b/core/src/syscall/windows/connect.rs @@ -0,0 +1,106 @@ +use crate::net::EventLoops; +use crate::syscall::common::{is_blocking, reset_errno, set_blocking, set_errno, set_non_blocking}; +use once_cell::sync::Lazy; +use std::ffi::{c_int, c_void}; +use std::io::Error; +use windows_sys::Win32::Networking::WinSock::{getpeername, getsockopt, SO_ERROR, SOCKADDR, SOCKET, SOL_SOCKET, WSAEALREADY, WSAEINPROGRESS, WSAEINTR, WSAETIMEDOUT}; + +#[must_use] +pub extern "system" fn connect( + fn_ptr: Option<&extern "system" fn(SOCKET, *const SOCKADDR, c_int) -> c_int>, + socket: SOCKET, + address: *const SOCKADDR, + len: c_int, +) -> c_int { + static CHAIN: Lazy>> = + Lazy::new(Default::default); + CHAIN.connect(fn_ptr, socket, address, len) +} + +trait ConnectSyscall { + extern "system" fn connect( + &self, + fn_ptr: Option<&extern "system" fn(SOCKET, *const SOCKADDR, c_int) -> c_int>, + fd: SOCKET, + address: *const SOCKADDR, + len: c_int, + ) -> c_int; +} + +impl_facade!(ConnectSyscallFacade, ConnectSyscall, + connect(fd: SOCKET, address: *const SOCKADDR, len: c_int) -> c_int +); + +#[repr(C)] +#[derive(Debug, Default)] +struct NioConnectSyscall { + inner: I, +} + +impl ConnectSyscall for NioConnectSyscall { + extern "system" fn connect( + &self, + fn_ptr: Option<&extern "system" fn(SOCKET, *const SOCKADDR, c_int) -> c_int>, + fd: SOCKET, + address: *const SOCKADDR, + len: c_int, + ) -> c_int { + let blocking = is_blocking(fd); + if blocking { + set_non_blocking(fd); + } + let mut r = self.inner.connect(fn_ptr, fd, address, len); + loop { + if r == 0 { + reset_errno(); + break; + } + let errno = Error::last_os_error().raw_os_error(); + if errno == Some(WSAEINPROGRESS) || errno == Some(WSAEALREADY) { + //阻塞,直到写事件发生 + if EventLoops::wait_write_event(fd, Some(crate::common::constants::SLICE)).is_err() + { + break; + } + let mut err: c_int = 0; + unsafe { + let mut len: c_int = std::mem::zeroed(); + r = getsockopt( + fd, + SOL_SOCKET, + SO_ERROR, + std::ptr::addr_of_mut!(err).cast::(), + &mut len, + ); + } + if r != 0 { + r = -1; + break; + } + if err != 0 { + set_errno(err); + r = -1; + break; + }; + unsafe { + let mut address = std::mem::zeroed(); + let mut address_len = std::mem::zeroed(); + r = getpeername(fd, &mut address, &mut address_len); + } + } else if errno != Some(WSAEINTR) { + break; + } + } + if r == -1 && Error::last_os_error().raw_os_error() == Some(WSAETIMEDOUT) { + set_errno(WSAEINPROGRESS); + } + if blocking { + set_blocking(fd); + } + r + } +} + +impl_raw!(RawConnectSyscall, ConnectSyscall, windows_sys::Win32::Networking::WinSock, + connect(fd: SOCKET, address: *const SOCKADDR, len: c_int) -> c_int +); diff --git a/core/src/syscall/windows/mod.rs b/core/src/syscall/windows/mod.rs index cd2f25a7..747214c3 100644 --- a/core/src/syscall/windows/mod.rs +++ b/core/src/syscall/windows/mod.rs @@ -566,6 +566,7 @@ syscall_mod!( send; shutdown; socket; + connect; CreateFileW; SetFilePointerEx; WaitOnAddress diff --git a/hook/src/syscall/windows.rs b/hook/src/syscall/windows.rs index 642dbd3c..8420c961 100644 --- a/hook/src/syscall/windows.rs +++ b/hook/src/syscall/windows.rs @@ -101,6 +101,11 @@ unsafe fn attach() -> std::io::Result<()> { value: PSTR, option_len: c_int ) -> c_int); + impl_hook!("ws2_32.dll", CONNECT, connect( + fd: SOCKET, + address: *const SOCKADDR, + len: c_int + ) -> c_int); impl_hook!("ws2_32.dll", WSARECV, WSARecv( fd: SOCKET, buf: *const WSABUF, From 1d40dda8750707894fe9bfda29dab23838bb6c1f Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Wed, 13 Nov 2024 10:29:02 +0800 Subject: [PATCH 05/42] hook connect --- core/src/syscall/unix/connect.rs | 2 +- core/src/syscall/windows/connect.rs | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/core/src/syscall/unix/connect.rs b/core/src/syscall/unix/connect.rs index 0ad92684..788f250f 100644 --- a/core/src/syscall/unix/connect.rs +++ b/core/src/syscall/unix/connect.rs @@ -74,7 +74,7 @@ impl ConnectSyscall for NioConnectSyscall { { break; } - let mut err: c_int = 0; + let mut err = 0; unsafe { let mut len: socklen_t = std::mem::zeroed(); r = libc::getsockopt( diff --git a/core/src/syscall/windows/connect.rs b/core/src/syscall/windows/connect.rs index be40d197..f32af718 100644 --- a/core/src/syscall/windows/connect.rs +++ b/core/src/syscall/windows/connect.rs @@ -1,7 +1,7 @@ use crate::net::EventLoops; use crate::syscall::common::{is_blocking, reset_errno, set_blocking, set_errno, set_non_blocking}; use once_cell::sync::Lazy; -use std::ffi::{c_int, c_void}; +use std::ffi::c_int; use std::io::Error; use windows_sys::Win32::Networking::WinSock::{getpeername, getsockopt, SO_ERROR, SOCKADDR, SOCKET, SOL_SOCKET, WSAEALREADY, WSAEINPROGRESS, WSAEINTR, WSAETIMEDOUT}; @@ -58,18 +58,20 @@ impl ConnectSyscall for NioConnectSyscall { let errno = Error::last_os_error().raw_os_error(); if errno == Some(WSAEINPROGRESS) || errno == Some(WSAEALREADY) { //阻塞,直到写事件发生 - if EventLoops::wait_write_event(fd, Some(crate::common::constants::SLICE)).is_err() - { + if EventLoops::wait_write_event( + fd as _, + Some(crate::common::constants::SLICE) + ).is_err() { break; } - let mut err: c_int = 0; + let mut err = 0; unsafe { let mut len: c_int = std::mem::zeroed(); r = getsockopt( fd, SOL_SOCKET, SO_ERROR, - std::ptr::addr_of_mut!(err).cast::(), + std::ptr::addr_of_mut!(err).cast::(), &mut len, ); } @@ -92,7 +94,7 @@ impl ConnectSyscall for NioConnectSyscall { } } if r == -1 && Error::last_os_error().raw_os_error() == Some(WSAETIMEDOUT) { - set_errno(WSAEINPROGRESS); + set_errno(WSAEINPROGRESS.try_into().expect("overflow")); } if blocking { set_blocking(fd); From 1b688f0fe50094badeabedfe52d81b2a867ca5a8 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Wed, 13 Nov 2024 10:42:55 +0800 Subject: [PATCH 06/42] hook connect --- hook/src/syscall/windows.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hook/src/syscall/windows.rs b/hook/src/syscall/windows.rs index 8420c961..a7a6ada6 100644 --- a/hook/src/syscall/windows.rs +++ b/hook/src/syscall/windows.rs @@ -101,11 +101,6 @@ unsafe fn attach() -> std::io::Result<()> { value: PSTR, option_len: c_int ) -> c_int); - impl_hook!("ws2_32.dll", CONNECT, connect( - fd: SOCKET, - address: *const SOCKADDR, - len: c_int - ) -> c_int); impl_hook!("ws2_32.dll", WSARECV, WSARecv( fd: SOCKET, buf: *const WSABUF, @@ -147,13 +142,18 @@ unsafe fn attach() -> std::io::Result<()> { lpnewfilepointer : *mut c_longlong, dwmovemethod : SET_FILE_POINTER_MOVE_METHOD ) -> BOOL); - // NOTE: unhook WaitOnAddress due to stack overflow or bug + // NOTE: unhook WaitOnAddress/connect due to stack overflow or bug // impl_hook!("api-ms-win-core-synch-l1-2-0.dll", WAITONADDRESS, WaitOnAddress( // address: *const c_void, // compareaddress: *const c_void, // addresssize: usize, // dwmilliseconds: c_uint // ) -> BOOL); + // impl_hook!("ws2_32.dll", CONNECT, connect( + // fd: SOCKET, + // address: *const SOCKADDR, + // len: c_int + // ) -> c_int); // Enable the hook minhook::MinHook::enable_all_hooks() .map_err(|_| Error::new(ErrorKind::Other, "init all hooks failed !")) From ae6511372ccea854a3e4609d93d09df92471785b Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Wed, 13 Nov 2024 11:21:22 +0800 Subject: [PATCH 07/42] =?UTF-8?q?=E5=AE=9A=E4=BD=8DIOCP=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/src/net/event_loop.rs | 10 +++++++--- core/src/net/operator/windows.rs | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/core/src/net/event_loop.rs b/core/src/net/event_loop.rs index 3dc883b1..434d28ca 100644 --- a/core/src/net/event_loop.rs +++ b/core/src/net/event_loop.rs @@ -127,7 +127,7 @@ impl<'e> EventLoop<'e> { } #[allow(trivial_numeric_casts, clippy::cast_possible_truncation)] - pub(crate) fn token(syscall: Syscall) -> usize { + fn token(syscall: Syscall) -> usize { if let Some(co) = SchedulableCoroutine::current() { let boxed: &'static mut CString = Box::leak(Box::from( CString::new(co.name()).expect("build name failed!"), @@ -148,7 +148,7 @@ impl<'e> EventLoop<'e> { let syscall_mask = >::into(syscall).as_ptr() as usize; let token = thread_id as usize ^ syscall_mask; if Syscall::nio() != syscall { - eprintln!("{syscall} {token}"); + eprintln!("generate token:{token} for {syscall}"); } token } @@ -307,6 +307,8 @@ impl<'e> EventLoop<'e> { if count > 0 { for cqe in &mut cq { let token = cqe.token; + let bytes_transferred = cqe.dw_number_of_bytes_transferred; + eprintln!("IOCP finish {token} {bytes_transferred}"); // resolve completed read/write tasks // todo refactor IOCP impl let result = match cqe.syscall { @@ -322,7 +324,9 @@ impl<'e> EventLoop<'e> { }; cqe.socket.try_into().expect("result overflow") } - Syscall::recv | Syscall::send => cqe.dw_number_of_bytes_transferred.into(), + Syscall::recv | Syscall::WSARecv | Syscall::send | Syscall::WSASend => { + bytes_transferred.into() + } _ => panic!("unsupported"), }; eprintln!("IOCP finish {token} {result}"); diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index a97262e6..0d2c8ba8 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -144,12 +144,14 @@ impl Operator<'_> { } overlapped.token = token; overlapped.dw_number_of_bytes_transferred = bytes; + eprintln!("IOCP add cq {token} {bytes}"); cq.push(overlapped); if cq.len() >= want || timeout_time.saturating_sub(now()) == 0 { break; } } let cost = Instant::now().saturating_duration_since(start_time); + eprintln!("IOCP do_select {}", cq.len()); Ok((cq.len(), cq, timeout.map(|t| t.saturating_sub(cost)))) } From 1014fec0f7ed1fb2edf6d9c2b45577ed37ec4a62 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Wed, 13 Nov 2024 11:34:38 +0800 Subject: [PATCH 08/42] =?UTF-8?q?=E5=AE=9A=E4=BD=8DIOCP=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/src/net/operator/windows.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index 0d2c8ba8..ea68f9c4 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -130,8 +130,9 @@ impl Operator<'_> { 1, ) }; + let err = Error::last_os_error().raw_os_error(); + eprintln!("IOCP try add cq {ret} {:?}", err); if ret == FALSE { - let err = Error::last_os_error().raw_os_error(); if Some(ERROR_NETNAME_DELETED.try_into().expect("overflow")) == err || Some(WAIT_TIMEOUT.try_into().expect("overflow")) == err { @@ -144,9 +145,8 @@ impl Operator<'_> { } overlapped.token = token; overlapped.dw_number_of_bytes_transferred = bytes; - eprintln!("IOCP add cq {token} {bytes}"); cq.push(overlapped); - if cq.len() >= want || timeout_time.saturating_sub(now()) == 0 { + if timeout_time.saturating_sub(now()) == 0 || cq.len() >= want { break; } } From 471aaf6d27f6e316d9d702ef5ba7bd11b2d1b844 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Wed, 13 Nov 2024 13:25:05 +0800 Subject: [PATCH 09/42] =?UTF-8?q?=E5=AE=9A=E4=BD=8DIOCP=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/src/net/operator/windows.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index ea68f9c4..7ac14417 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -8,9 +8,7 @@ use std::marker::PhantomData; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, Instant}; use windows_sys::core::{PCSTR, PSTR}; -use windows_sys::Win32::Foundation::{ - ERROR_NETNAME_DELETED, FALSE, HANDLE, INVALID_HANDLE_VALUE, WAIT_TIMEOUT, -}; +use windows_sys::Win32::Foundation::{ERROR_NETNAME_DELETED, FALSE, HANDLE, INVALID_HANDLE_VALUE}; use windows_sys::Win32::Networking::WinSock::{ closesocket, AcceptEx, WSAGetLastError, WSARecv, WSASend, WSASocketW, INVALID_SOCKET, IPPROTO, LPWSAOVERLAPPED_COMPLETION_ROUTINE, SEND_RECV_FLAGS, SOCKADDR, SOCKADDR_IN, SOCKET, @@ -131,22 +129,17 @@ impl Operator<'_> { ) }; let err = Error::last_os_error().raw_os_error(); - eprintln!("IOCP try add cq {ret} {:?}", err); + eprintln!("IOCP try add cq {ret} {err:?}"); if ret == FALSE { - if Some(ERROR_NETNAME_DELETED.try_into().expect("overflow")) == err - || Some(WAIT_TIMEOUT.try_into().expect("overflow")) == err - { + if Some(ERROR_NETNAME_DELETED.try_into().expect("overflow")) == err { _ = unsafe { closesocket(overlapped.socket) }; - if cq.len() >= want || timeout_time.saturating_sub(now()) == 0 { - break; - } - continue; } + continue; } overlapped.token = token; overlapped.dw_number_of_bytes_transferred = bytes; cq.push(overlapped); - if timeout_time.saturating_sub(now()) == 0 || cq.len() >= want { + if cq.len() >= want || timeout_time.saturating_sub(now()) == 0 { break; } } From dc2045e1b2b9d0ddc26b17dc472738c323369d11 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Wed, 13 Nov 2024 14:12:35 +0800 Subject: [PATCH 10/42] =?UTF-8?q?=E5=AE=9A=E4=BD=8DIOCP=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/src/net/operator/windows.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index 7ac14417..57cbd19b 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -8,7 +8,9 @@ use std::marker::PhantomData; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, Instant}; use windows_sys::core::{PCSTR, PSTR}; -use windows_sys::Win32::Foundation::{ERROR_NETNAME_DELETED, FALSE, HANDLE, INVALID_HANDLE_VALUE}; +use windows_sys::Win32::Foundation::{ + ERROR_NETNAME_DELETED, FALSE, HANDLE, INVALID_HANDLE_VALUE, WAIT_TIMEOUT, +}; use windows_sys::Win32::Networking::WinSock::{ closesocket, AcceptEx, WSAGetLastError, WSARecv, WSASend, WSASocketW, INVALID_SOCKET, IPPROTO, LPWSAOVERLAPPED_COMPLETION_ROUTINE, SEND_RECV_FLAGS, SOCKADDR, SOCKADDR_IN, SOCKET, @@ -131,15 +133,21 @@ impl Operator<'_> { let err = Error::last_os_error().raw_os_error(); eprintln!("IOCP try add cq {ret} {err:?}"); if ret == FALSE { + if timeout_time.saturating_sub(now()) == 0 { + break; + } + if Some(WAIT_TIMEOUT.try_into().expect("overflow")) == err { + continue; + } if Some(ERROR_NETNAME_DELETED.try_into().expect("overflow")) == err { _ = unsafe { closesocket(overlapped.socket) }; + continue; } - continue; } overlapped.token = token; overlapped.dw_number_of_bytes_transferred = bytes; cq.push(overlapped); - if cq.len() >= want || timeout_time.saturating_sub(now()) == 0 { + if cq.len() >= want { break; } } From 76b02d44a5f315cdb2d28f71a20a7cf56aad0ef5 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Wed, 13 Nov 2024 15:04:37 +0800 Subject: [PATCH 11/42] =?UTF-8?q?=E5=AE=9A=E4=BD=8DIOCP=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/src/net/operator/windows.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index 57cbd19b..0ddb729f 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -47,6 +47,7 @@ pub(crate) struct Overlapped { #[derive(Debug)] pub(crate) struct Operator<'o> { iocp: HANDLE, + completion_key: usize, entering: AtomicBool, handles: DashSet, phantom_data: PhantomData<&'o HANDLE>, @@ -61,6 +62,8 @@ impl Operator<'_> { } Ok(Self { iocp, + completion_key: unsafe { windows_sys::Win32::System::Threading::GetCurrentThread() } + as usize, entering: AtomicBool::new(false), handles: DashSet::default(), phantom_data: PhantomData, @@ -76,11 +79,11 @@ impl Operator<'_> { /// Any object which is convertible to a `HANDLE` via the `AsRawHandle` /// trait can be provided to this function, such as `std::fs::File` and /// friends. - fn add_handle(&self, token: usize, handle: HANDLE) -> std::io::Result<()> { + fn add_handle(&self, handle: HANDLE) -> std::io::Result<()> { if self.handles.contains(&handle) { return Ok(()); } - let ret = unsafe { CreateIoCompletionPort(handle, self.iocp, token, 0) }; + let ret = unsafe { CreateIoCompletionPort(handle, self.iocp, self.completion_key, 0) }; if ret.is_null() { return Err(Error::new( ErrorKind::Other, @@ -119,13 +122,12 @@ impl Operator<'_> { let mut cq = Vec::new(); loop { let mut bytes = 0; - let mut token = 0; let mut overlapped: Overlapped = unsafe { std::mem::zeroed() }; let ret = unsafe { GetQueuedCompletionStatus( self.iocp, &mut bytes, - &mut token, + &mut self.completion_key.clone(), std::ptr::from_mut::(&mut overlapped).cast(), 1, ) @@ -144,7 +146,6 @@ impl Operator<'_> { continue; } } - overlapped.token = token; overlapped.dw_number_of_bytes_transferred = bytes; cq.push(overlapped); if cq.len() >= want { @@ -163,7 +164,7 @@ impl Operator<'_> { _address: *mut SOCKADDR, _address_len: *mut c_int, ) -> std::io::Result<()> { - self.add_handle(fd, fd as HANDLE)?; + self.add_handle(fd as HANDLE)?; let context = SOCKET_CONTEXT.get(&fd).expect("socket context not found"); let ctx = context.value(); unsafe { @@ -217,7 +218,7 @@ impl Operator<'_> { len: c_int, flags: SEND_RECV_FLAGS, ) -> std::io::Result<()> { - self.add_handle(fd, fd as HANDLE)?; + self.add_handle(fd as HANDLE)?; unsafe { let mut overlapped: Overlapped = std::mem::zeroed(); overlapped.from_fd = fd; @@ -262,7 +263,7 @@ impl Operator<'_> { lpoverlapped.is_null(), "the WSARecv in Operator should be called without lpoverlapped! Correct your code!" ); - self.add_handle(fd, fd as HANDLE)?; + self.add_handle(fd as HANDLE)?; unsafe { let mut overlapped: Overlapped = std::mem::zeroed(); overlapped.from_fd = fd; @@ -296,7 +297,7 @@ impl Operator<'_> { len: c_int, flags: SEND_RECV_FLAGS, ) -> std::io::Result<()> { - self.add_handle(fd, fd as HANDLE)?; + self.add_handle(fd as HANDLE)?; unsafe { let mut overlapped: Overlapped = std::mem::zeroed(); overlapped.from_fd = fd; @@ -341,7 +342,7 @@ impl Operator<'_> { lpoverlapped.is_null(), "the WSASend in Operator should be called without lpoverlapped! Correct your code!" ); - self.add_handle(fd, fd as HANDLE)?; + self.add_handle(fd as HANDLE)?; unsafe { let mut overlapped: Overlapped = std::mem::zeroed(); overlapped.from_fd = fd; From eb4118b6b3325edec30eb5e76a5934a61e973b1a Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Wed, 13 Nov 2024 15:18:05 +0800 Subject: [PATCH 12/42] =?UTF-8?q?=E5=AE=9A=E4=BD=8DIOCP=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/src/net/operator/windows.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index 0ddb729f..504f2eef 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -46,24 +46,23 @@ pub(crate) struct Overlapped { #[repr(C)] #[derive(Debug)] pub(crate) struct Operator<'o> { + cpu: usize, iocp: HANDLE, - completion_key: usize, entering: AtomicBool, handles: DashSet, phantom_data: PhantomData<&'o HANDLE>, } impl Operator<'_> { - pub(crate) fn new(_cpu: usize) -> std::io::Result { + pub(crate) fn new(cpu: usize) -> std::io::Result { let iocp = - unsafe { CreateIoCompletionPort(INVALID_HANDLE_VALUE, std::ptr::null_mut(), 0, 0) }; + unsafe { CreateIoCompletionPort(INVALID_HANDLE_VALUE, std::ptr::null_mut(), cpu, 0) }; if iocp.is_null() { return Err(Error::last_os_error()); } Ok(Self { + cpu, iocp, - completion_key: unsafe { windows_sys::Win32::System::Threading::GetCurrentThread() } - as usize, entering: AtomicBool::new(false), handles: DashSet::default(), phantom_data: PhantomData, @@ -83,7 +82,7 @@ impl Operator<'_> { if self.handles.contains(&handle) { return Ok(()); } - let ret = unsafe { CreateIoCompletionPort(handle, self.iocp, self.completion_key, 0) }; + let ret = unsafe { CreateIoCompletionPort(handle, self.iocp, self.cpu, 0) }; if ret.is_null() { return Err(Error::new( ErrorKind::Other, @@ -127,7 +126,7 @@ impl Operator<'_> { GetQueuedCompletionStatus( self.iocp, &mut bytes, - &mut self.completion_key.clone(), + &mut self.cpu.clone(), std::ptr::from_mut::(&mut overlapped).cast(), 1, ) From 382de0405bec116f6df8924e0745edccae25a074 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Wed, 13 Nov 2024 15:43:04 +0800 Subject: [PATCH 13/42] =?UTF-8?q?=E5=AE=9A=E4=BD=8DIOCP=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/src/net/operator/windows.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index 504f2eef..592bc7b2 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -56,7 +56,7 @@ pub(crate) struct Operator<'o> { impl Operator<'_> { pub(crate) fn new(cpu: usize) -> std::io::Result { let iocp = - unsafe { CreateIoCompletionPort(INVALID_HANDLE_VALUE, std::ptr::null_mut(), cpu, 0) }; + unsafe { CreateIoCompletionPort(INVALID_HANDLE_VALUE, std::ptr::null_mut(), 0, 0) }; if iocp.is_null() { return Err(Error::last_os_error()); } @@ -190,10 +190,11 @@ impl Operator<'_> { overlapped.socket = socket; overlapped.token = user_data; overlapped.syscall = Syscall::accept; + let mut buf: Vec = Vec::with_capacity(2 * size); while AcceptEx( fd, socket, - std::ptr::null_mut(), + buf.as_mut_ptr().cast(), 0, size, size, From aff15629c2bd713c9f4d83b500057e33f4e9801a Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Wed, 13 Nov 2024 15:55:54 +0800 Subject: [PATCH 14/42] =?UTF-8?q?=E5=AE=9A=E4=BD=8DIOCP=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/src/net/operator/windows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index 592bc7b2..088ca4dd 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -190,7 +190,7 @@ impl Operator<'_> { overlapped.socket = socket; overlapped.token = user_data; overlapped.syscall = Syscall::accept; - let mut buf: Vec = Vec::with_capacity(2 * size); + let mut buf: Vec = Vec::with_capacity(size as usize * 2); while AcceptEx( fd, socket, From 01fdaca23bb816e3ded613500853105bf7587f07 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Wed, 13 Nov 2024 16:18:18 +0800 Subject: [PATCH 15/42] fix IOCP accept bug --- core/src/net/operator/windows.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index 088ca4dd..a14b9303 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -1,5 +1,6 @@ use crate::common::constants::Syscall; use crate::common::{get_timeout_time, now}; +use crate::impl_display_by_debug; use dashmap::{DashMap, DashSet}; use once_cell::sync::Lazy; use std::ffi::{c_int, c_uint}; @@ -33,8 +34,11 @@ pub(crate) static SOCKET_CONTEXT: Lazy> = /// The overlapped struct we actually used for IOCP. #[repr(C)] +#[derive(educe::Educe)] +#[educe(Debug)] pub(crate) struct Overlapped { /// The base [`OVERLAPPED`]. + #[educe(Debug(ignore))] pub base: OVERLAPPED, pub from_fd: SOCKET, pub socket: SOCKET, @@ -43,6 +47,8 @@ pub(crate) struct Overlapped { pub dw_number_of_bytes_transferred: u32, } +impl_display_by_debug!(Overlapped); + #[repr(C)] #[derive(Debug)] pub(crate) struct Operator<'o> { @@ -131,8 +137,9 @@ impl Operator<'_> { 1, ) }; - let err = Error::last_os_error().raw_os_error(); - eprintln!("IOCP try add cq {ret} {err:?}"); + let e = Error::last_os_error(); + let err = e.raw_os_error(); + eprintln!("IOCP returns:{ret} bytes:{bytes} e:{e} try add cq:{overlapped}"); if ret == FALSE { if timeout_time.saturating_sub(now()) == 0 { break; From 356097d4958db493ed69344c7d7530e0dc267065 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Wed, 13 Nov 2024 18:03:17 +0800 Subject: [PATCH 16/42] try fix IOCP --- core/src/net/operator/windows.rs | 62 +++++++++++++++++--------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index a14b9303..540a3cdb 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -9,16 +9,14 @@ use std::marker::PhantomData; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, Instant}; use windows_sys::core::{PCSTR, PSTR}; -use windows_sys::Win32::Foundation::{ - ERROR_NETNAME_DELETED, FALSE, HANDLE, INVALID_HANDLE_VALUE, WAIT_TIMEOUT, -}; +use windows_sys::Win32::Foundation::{FALSE, HANDLE, INVALID_HANDLE_VALUE}; use windows_sys::Win32::Networking::WinSock::{ - closesocket, AcceptEx, WSAGetLastError, WSARecv, WSASend, WSASocketW, INVALID_SOCKET, IPPROTO, + AcceptEx, WSAGetLastError, WSARecv, WSASend, WSASocketW, INVALID_SOCKET, IPPROTO, LPWSAOVERLAPPED_COMPLETION_ROUTINE, SEND_RECV_FLAGS, SOCKADDR, SOCKADDR_IN, SOCKET, SOCKET_ERROR, WINSOCK_SOCKET_TYPE, WSABUF, WSA_FLAG_OVERLAPPED, WSA_IO_PENDING, }; use windows_sys::Win32::System::IO::{ - CreateIoCompletionPort, GetQueuedCompletionStatus, OVERLAPPED, + CreateIoCompletionPort, GetQueuedCompletionStatusEx, OVERLAPPED, OVERLAPPED_ENTRY, }; #[repr(C)] @@ -126,40 +124,48 @@ impl Operator<'_> { let timeout_time = timeout.map_or(u64::MAX, get_timeout_time); let mut cq = Vec::new(); loop { - let mut bytes = 0; - let mut overlapped: Overlapped = unsafe { std::mem::zeroed() }; + let left_ms = (timeout_time.saturating_sub(now()) / 1_000_000) + .try_into() + .expect("overflow"); + if left_ms == 0 { + break; + } + let mut entries: Vec = Vec::with_capacity(1024); + let uninit = entries.spare_capacity_mut(); + let mut recv_count = 0; let ret = unsafe { - GetQueuedCompletionStatus( + GetQueuedCompletionStatusEx( self.iocp, - &mut bytes, - &mut self.cpu.clone(), - std::ptr::from_mut::(&mut overlapped).cast(), - 1, + uninit.as_mut_ptr().cast(), + uninit.len().try_into().expect("overflow"), + &mut recv_count, + left_ms, + 0, ) }; let e = Error::last_os_error(); - let err = e.raw_os_error(); - eprintln!("IOCP returns:{ret} bytes:{bytes} e:{e} try add cq:{overlapped}"); - if ret == FALSE { - if timeout_time.saturating_sub(now()) == 0 { - break; - } - if Some(WAIT_TIMEOUT.try_into().expect("overflow")) == err { - continue; - } - if Some(ERROR_NETNAME_DELETED.try_into().expect("overflow")) == err { - _ = unsafe { closesocket(overlapped.socket) }; - continue; - } + eprintln!("IOCP returns:{ret} recv_count:{recv_count} e:{e}"); + if FALSE == ret && ErrorKind::TimedOut == e.kind() { + continue; + } + unsafe { entries.set_len(recv_count as _) }; + for entry in entries { + let overlapped = unsafe { &*entry.lpOverlapped.cast::() }; + cq.push(Overlapped { + base: overlapped.base, + from_fd: overlapped.from_fd, + socket: overlapped.socket, + token: overlapped.token, + syscall: overlapped.syscall, + dw_number_of_bytes_transferred: entry.dwNumberOfBytesTransferred, + }); } - overlapped.dw_number_of_bytes_transferred = bytes; - cq.push(overlapped); if cq.len() >= want { break; } } let cost = Instant::now().saturating_duration_since(start_time); - eprintln!("IOCP do_select {}", cq.len()); + eprintln!("IOCP do_select {cq:?}"); Ok((cq.len(), cq, timeout.map(|t| t.saturating_sub(cost)))) } From 192bf154427243f8a15d4970468f03565c7ed3e1 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Wed, 13 Nov 2024 18:18:06 +0800 Subject: [PATCH 17/42] try fix IOCP --- core/src/net/operator/windows.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index 540a3cdb..1c24088e 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -114,7 +114,6 @@ impl Operator<'_> { result } - #[allow(clippy::unnecessary_wraps)] fn do_select( &self, timeout: Option, @@ -145,8 +144,11 @@ impl Operator<'_> { }; let e = Error::last_os_error(); eprintln!("IOCP returns:{ret} recv_count:{recv_count} e:{e}"); - if FALSE == ret && ErrorKind::TimedOut == e.kind() { - continue; + if FALSE == ret { + if ErrorKind::TimedOut == e.kind() { + continue; + } + return Err(e); } unsafe { entries.set_len(recv_count as _) }; for entry in entries { From 2354ce573c87dd15bc19640e10a52ee507d11521 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Wed, 13 Nov 2024 19:28:44 +0800 Subject: [PATCH 18/42] try fix IOCP --- core/src/net/operator/windows.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index 1c24088e..1f61f6f4 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -221,6 +221,7 @@ impl Operator<'_> { break; } } + std::mem::forget(overlapped); } Ok(()) } @@ -259,6 +260,7 @@ impl Operator<'_> { "add recv operation failed", )); } + std::mem::forget(overlapped); } Ok(()) } @@ -300,6 +302,7 @@ impl Operator<'_> { "add WSARecv operation failed", )); } + std::mem::forget(overlapped); } Ok(()) } @@ -338,6 +341,7 @@ impl Operator<'_> { "add send operation failed", )); } + std::mem::forget(overlapped); } Ok(()) } @@ -379,6 +383,7 @@ impl Operator<'_> { "add WSASend operation failed", )); } + std::mem::forget(overlapped); } Ok(()) } From a725ec1687debb2ee50005dfb1202f6fcc68efb9 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Wed, 13 Nov 2024 21:47:34 +0800 Subject: [PATCH 19/42] try fix IOCP --- core/src/net/operator/windows.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index 1f61f6f4..d7b5dd5c 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -143,7 +143,7 @@ impl Operator<'_> { ) }; let e = Error::last_os_error(); - eprintln!("IOCP returns:{ret} recv_count:{recv_count} e:{e}"); + if FALSE == ret { if ErrorKind::TimedOut == e.kind() { continue; @@ -161,13 +161,19 @@ impl Operator<'_> { syscall: overlapped.syscall, dw_number_of_bytes_transferred: entry.dwNumberOfBytesTransferred, }); + eprintln!( + "IOCP got OVERLAPPED:{} {} {} {}", + overlapped.base.Internal, + overlapped.base.InternalHigh, + unsafe { overlapped.base.Anonymous.Anonymous.Offset }, + unsafe { overlapped.base.Anonymous.Anonymous.OffsetHigh } + ); } if cq.len() >= want { break; } } let cost = Instant::now().saturating_duration_since(start_time); - eprintln!("IOCP do_select {cq:?}"); Ok((cq.len(), cq, timeout.map(|t| t.saturating_sub(cost)))) } @@ -221,7 +227,13 @@ impl Operator<'_> { break; } } - std::mem::forget(overlapped); + eprintln!( + "add accept operation OVERLAPPED:{} {} {} {}", + overlapped.base.Internal, + overlapped.base.InternalHigh, + overlapped.base.Anonymous.Anonymous.Offset, + overlapped.base.Anonymous.Anonymous.OffsetHigh + ); } Ok(()) } @@ -260,7 +272,6 @@ impl Operator<'_> { "add recv operation failed", )); } - std::mem::forget(overlapped); } Ok(()) } @@ -302,7 +313,6 @@ impl Operator<'_> { "add WSARecv operation failed", )); } - std::mem::forget(overlapped); } Ok(()) } @@ -341,7 +351,6 @@ impl Operator<'_> { "add send operation failed", )); } - std::mem::forget(overlapped); } Ok(()) } @@ -383,7 +392,6 @@ impl Operator<'_> { "add WSASend operation failed", )); } - std::mem::forget(overlapped); } Ok(()) } From e7e3ba06722fe599615e36d4ce5dcb1bc76d71de Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Thu, 14 Nov 2024 08:27:15 +0800 Subject: [PATCH 20/42] try fix IOCP --- core/src/net/event_loop.rs | 2 +- core/src/net/operator/windows.rs | 51 ++++++++++++++++++-------------- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/core/src/net/event_loop.rs b/core/src/net/event_loop.rs index 434d28ca..b09f3f57 100644 --- a/core/src/net/event_loop.rs +++ b/core/src/net/event_loop.rs @@ -307,7 +307,7 @@ impl<'e> EventLoop<'e> { if count > 0 { for cqe in &mut cq { let token = cqe.token; - let bytes_transferred = cqe.dw_number_of_bytes_transferred; + let bytes_transferred = cqe.bytes_transferred; eprintln!("IOCP finish {token} {bytes_transferred}"); // resolve completed read/write tasks // todo refactor IOCP impl diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index d7b5dd5c..a61070d1 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -42,7 +42,7 @@ pub(crate) struct Overlapped { pub socket: SOCKET, pub token: usize, pub syscall: Syscall, - pub dw_number_of_bytes_transferred: u32, + pub bytes_transferred: u32, } impl_display_by_debug!(Overlapped); @@ -54,6 +54,7 @@ pub(crate) struct Operator<'o> { iocp: HANDLE, entering: AtomicBool, handles: DashSet, + context: DashMap, phantom_data: PhantomData<&'o HANDLE>, } @@ -69,6 +70,7 @@ impl Operator<'_> { iocp, entering: AtomicBool::new(false), handles: DashSet::default(), + context: DashMap::default(), phantom_data: PhantomData, }) } @@ -143,7 +145,6 @@ impl Operator<'_> { ) }; let e = Error::last_os_error(); - if FALSE == ret { if ErrorKind::TimedOut == e.kind() { continue; @@ -153,21 +154,11 @@ impl Operator<'_> { unsafe { entries.set_len(recv_count as _) }; for entry in entries { let overlapped = unsafe { &*entry.lpOverlapped.cast::() }; - cq.push(Overlapped { - base: overlapped.base, - from_fd: overlapped.from_fd, - socket: overlapped.socket, - token: overlapped.token, - syscall: overlapped.syscall, - dw_number_of_bytes_transferred: entry.dwNumberOfBytesTransferred, - }); - eprintln!( - "IOCP got OVERLAPPED:{} {} {} {}", - overlapped.base.Internal, - overlapped.base.InternalHigh, - unsafe { overlapped.base.Anonymous.Anonymous.Offset }, - unsafe { overlapped.base.Anonymous.Anonymous.OffsetHigh } - ); + if let Some((_, mut overlapped)) = self.context.remove(&overlapped.token) { + overlapped.bytes_transferred = entry.dwNumberOfBytesTransferred; + eprintln!("IOCP got Overlapped:{overlapped}"); + cq.push(overlapped); + } } if cq.len() >= want { break; @@ -227,12 +218,10 @@ impl Operator<'_> { break; } } - eprintln!( - "add accept operation OVERLAPPED:{} {} {} {}", - overlapped.base.Internal, - overlapped.base.InternalHigh, - overlapped.base.Anonymous.Anonymous.Offset, - overlapped.base.Anonymous.Anonymous.OffsetHigh + eprintln!("add accept operation Overlapped:{overlapped}"); + assert!( + self.context.insert(user_data, overlapped).is_none(), + "The previous token was not retrieved in a timely manner" ); } Ok(()) @@ -272,6 +261,10 @@ impl Operator<'_> { "add recv operation failed", )); } + assert!( + self.context.insert(user_data, overlapped).is_none(), + "The previous token was not retrieved in a timely manner" + ); } Ok(()) } @@ -313,6 +306,10 @@ impl Operator<'_> { "add WSARecv operation failed", )); } + assert!( + self.context.insert(user_data, overlapped).is_none(), + "The previous token was not retrieved in a timely manner" + ); } Ok(()) } @@ -351,6 +348,10 @@ impl Operator<'_> { "add send operation failed", )); } + assert!( + self.context.insert(user_data, overlapped).is_none(), + "The previous token was not retrieved in a timely manner" + ); } Ok(()) } @@ -392,6 +393,10 @@ impl Operator<'_> { "add WSASend operation failed", )); } + assert!( + self.context.insert(user_data, overlapped).is_none(), + "The previous token was not retrieved in a timely manner" + ); } Ok(()) } From e0e161cf89489dadfa54ceef6f34be9670bf9745 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Thu, 14 Nov 2024 08:54:52 +0800 Subject: [PATCH 21/42] try fix IOCP --- core/src/net/operator/windows.rs | 8 +++- core/src/syscall/windows/WSARecv.rs | 67 ++++++++++++++++++++++++----- core/src/syscall/windows/WSASend.rs | 67 ++++++++++++++++++++++++----- 3 files changed, 120 insertions(+), 22 deletions(-) diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index a61070d1..cb813978 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -153,6 +153,10 @@ impl Operator<'_> { } unsafe { entries.set_len(recv_count as _) }; for entry in entries { + eprintln!( + "IOCP got lpCompletionKey:{} dwNumberOfBytesTransferred{}", + entry.lpCompletionKey, entry.dwNumberOfBytesTransferred + ); let overlapped = unsafe { &*entry.lpOverlapped.cast::() }; if let Some((_, mut overlapped)) = self.context.remove(&overlapped.token) { overlapped.bytes_transferred = entry.dwNumberOfBytesTransferred; @@ -282,7 +286,7 @@ impl Operator<'_> { ) -> std::io::Result<()> { assert!( lpoverlapped.is_null(), - "the WSARecv in Operator should be called without lpoverlapped! Correct your code!" + "the WSARecv in Operator should be called without lpoverlapped! Please report bug to open-coroutine!" ); self.add_handle(fd as HANDLE)?; unsafe { @@ -369,7 +373,7 @@ impl Operator<'_> { ) -> std::io::Result<()> { assert!( lpoverlapped.is_null(), - "the WSASend in Operator should be called without lpoverlapped! Correct your code!" + "the WSASend in Operator should be called without lpoverlapped! Please report bug to open-coroutine!" ); self.add_handle(fd as HANDLE)?; unsafe { diff --git a/core/src/syscall/windows/WSARecv.rs b/core/src/syscall/windows/WSARecv.rs index e9286d87..9df06b71 100644 --- a/core/src/syscall/windows/WSARecv.rs +++ b/core/src/syscall/windows/WSARecv.rs @@ -2,6 +2,9 @@ use once_cell::sync::Lazy; use std::ffi::{c_int, c_uint}; use windows_sys::Win32::Networking::WinSock::{LPWSAOVERLAPPED_COMPLETION_ROUTINE, SOCKET, WSABUF}; use windows_sys::Win32::System::IO::OVERLAPPED; +use crate::common::constants::{CoroutineState, Syscall, SyscallState}; +use crate::{error, info}; +use crate::scheduler::SchedulableCoroutine; #[must_use] pub extern "system" fn WSARecv( @@ -70,17 +73,62 @@ trait WSARecvSyscall { ) -> c_int; } -impl_facade!(WSARecvSyscallFacade, WSARecvSyscall, - WSARecv( +#[repr(C)] +#[derive(Debug, Default)] +struct WSARecvSyscallFacade { + inner: I, +} + +impl WSARecvSyscall for WSARecvSyscallFacade { + extern "system" fn WSARecv( + &self, + fn_ptr: Option< + &extern "system" fn( + SOCKET, + *const WSABUF, + c_uint, + *mut c_uint, + *mut c_uint, + *mut OVERLAPPED, + LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> c_int, + >, fd: SOCKET, buf: *const WSABUF, dwbuffercount: c_uint, lpnumberofbytesrecvd: *mut c_uint, - lpflags : *mut c_uint, + lpflags: *mut c_uint, lpoverlapped: *mut OVERLAPPED, - lpcompletionroutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE - ) -> c_int -); + lpcompletionroutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> c_int { + let syscall = Syscall::WSARecv; + info!("enter syscall {}", syscall); + if let Some(co) = SchedulableCoroutine::current() { + _ = co.syscall((), syscall, SyscallState::Executing); + } + let r = self.inner.WSARecv( + fn_ptr, + fd, + buf, + dwbuffercount, + lpnumberofbytesrecvd, + lpflags, + lpoverlapped, + lpcompletionroutine, + ); + if let Some(co) = SchedulableCoroutine::current() { + if let CoroutineState::SystemCall((), Syscall::WSARecv, SyscallState::Executing) = + co.state() + { + if co.running().is_err() { + error!("{} change to running state failed !", co.name()); + } + } + } + info!("exit syscall {}", syscall); + r + } +} #[cfg(all(windows, feature = "iocp"))] #[repr(C)] @@ -114,9 +162,8 @@ impl WSARecvSyscall for IocpWSARecvSyscall { lpcompletionroutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, ) -> c_int { use windows_sys::Win32::Networking::WinSock::{SOCKET_ERROR, WSAEWOULDBLOCK}; - use crate::common::constants::{CoroutineState, SyscallState}; use crate::net::EventLoops; - use crate::scheduler::{SchedulableCoroutine, SchedulableSuspender}; + use crate::scheduler::SchedulableSuspender; if !lpoverlapped.is_null() { return RawWSARecvSyscall::default().WSARecv( @@ -137,7 +184,7 @@ impl WSARecvSyscall for IocpWSARecvSyscall { { let new_state = SyscallState::Suspend(u64::MAX); if co.syscall((), syscall, new_state).is_err() { - crate::error!( + error!( "{} change to syscall {} {} failed !", co.name(), syscall, new_state ); @@ -153,7 +200,7 @@ impl WSARecvSyscall for IocpWSARecvSyscall { { let new_state = SyscallState::Executing; if co.syscall((), syscall, new_state).is_err() { - crate::error!( + error!( "{} change to syscall {} {} failed !", co.name(), syscall, new_state ); diff --git a/core/src/syscall/windows/WSASend.rs b/core/src/syscall/windows/WSASend.rs index 8195c8e9..8e1f763f 100644 --- a/core/src/syscall/windows/WSASend.rs +++ b/core/src/syscall/windows/WSASend.rs @@ -2,6 +2,9 @@ use once_cell::sync::Lazy; use std::ffi::{c_int, c_uint}; use windows_sys::Win32::Networking::WinSock::{LPWSAOVERLAPPED_COMPLETION_ROUTINE, SOCKET, WSABUF}; use windows_sys::Win32::System::IO::OVERLAPPED; +use crate::common::constants::{CoroutineState, Syscall, SyscallState}; +use crate::{error, info}; +use crate::scheduler::SchedulableCoroutine; #[must_use] pub extern "system" fn WSASend( @@ -70,17 +73,62 @@ trait WSASendSyscall { ) -> c_int; } -impl_facade!(WSASendSyscallFacade, WSASendSyscall, - WSASend( +#[repr(C)] +#[derive(Debug, Default)] +struct WSASendSyscallFacade { + inner: I, +} + +impl WSASendSyscall for WSASendSyscallFacade { + extern "system" fn WSASend( + &self, + fn_ptr: Option< + &extern "system" fn( + SOCKET, + *const WSABUF, + c_uint, + *mut c_uint, + c_uint, + *mut OVERLAPPED, + LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> c_int, + >, fd: SOCKET, buf: *const WSABUF, dwbuffercount: c_uint, lpnumberofbytesrecvd: *mut c_uint, - dwflags : c_uint, + dwflags: c_uint, lpoverlapped: *mut OVERLAPPED, - lpcompletionroutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE - ) -> c_int -); + lpcompletionroutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> c_int { + let syscall = Syscall::WSASend; + info!("enter syscall {}", syscall); + if let Some(co) = SchedulableCoroutine::current() { + _ = co.syscall((), syscall, SyscallState::Executing); + } + let r = self.inner.WSASend( + fn_ptr, + fd, + buf, + dwbuffercount, + lpnumberofbytesrecvd, + dwflags, + lpoverlapped, + lpcompletionroutine, + ); + if let Some(co) = SchedulableCoroutine::current() { + if let CoroutineState::SystemCall((), Syscall::WSASend, SyscallState::Executing) = + co.state() + { + if co.running().is_err() { + error!("{} change to running state failed !", co.name()); + } + } + } + info!("exit syscall {}", syscall); + r + } +} #[cfg(all(windows, feature = "iocp"))] #[repr(C)] @@ -113,9 +161,8 @@ impl WSASendSyscall for IocpWSASendSyscall { lpcompletionroutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, ) -> c_int { use windows_sys::Win32::Networking::WinSock::{SOCKET_ERROR, WSAEWOULDBLOCK}; - use crate::common::constants::{CoroutineState, SyscallState}; use crate::net::EventLoops; - use crate::scheduler::{SchedulableCoroutine, SchedulableSuspender}; + use crate::scheduler::SchedulableSuspender; if !lpoverlapped.is_null() { return RawWSASendSyscall::default().WSASend( @@ -136,7 +183,7 @@ impl WSASendSyscall for IocpWSASendSyscall { { let new_state = SyscallState::Suspend(u64::MAX); if co.syscall((), syscall, new_state).is_err() { - crate::error!( + error!( "{} change to syscall {} {} failed !", co.name(), syscall, new_state ); @@ -152,7 +199,7 @@ impl WSASendSyscall for IocpWSASendSyscall { { let new_state = SyscallState::Executing; if co.syscall((), syscall, new_state).is_err() { - crate::error!( + error!( "{} change to syscall {} {} failed !", co.name(), syscall, new_state ); From 56f2fb0007c16cd202ac8608de06eeaaa164319a Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Thu, 14 Nov 2024 09:06:20 +0800 Subject: [PATCH 22/42] try fix IOCP --- core/src/net/operator/windows.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index cb813978..0d6360fc 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -153,11 +153,8 @@ impl Operator<'_> { } unsafe { entries.set_len(recv_count as _) }; for entry in entries { - eprintln!( - "IOCP got lpCompletionKey:{} dwNumberOfBytesTransferred{}", - entry.lpCompletionKey, entry.dwNumberOfBytesTransferred - ); let overlapped = unsafe { &*entry.lpOverlapped.cast::() }; + eprintln!("IOCP got Overlapped:{}", overlapped); if let Some((_, mut overlapped)) = self.context.remove(&overlapped.token) { overlapped.bytes_transferred = entry.dwNumberOfBytesTransferred; eprintln!("IOCP got Overlapped:{overlapped}"); From a02b86e61d754d978f0e46a9f1c5513fed994143 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Thu, 14 Nov 2024 09:10:16 +0800 Subject: [PATCH 23/42] try fix IOCP --- core/src/net/operator/windows.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index 0d6360fc..77b82971 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -154,10 +154,10 @@ impl Operator<'_> { unsafe { entries.set_len(recv_count as _) }; for entry in entries { let overlapped = unsafe { &*entry.lpOverlapped.cast::() }; - eprintln!("IOCP got Overlapped:{}", overlapped); + eprintln!("IOCP got Overlapped:{overlapped}"); if let Some((_, mut overlapped)) = self.context.remove(&overlapped.token) { overlapped.bytes_transferred = entry.dwNumberOfBytesTransferred; - eprintln!("IOCP got Overlapped:{overlapped}"); + eprintln!("after correct Overlapped bytes_transferred:{overlapped}"); cq.push(overlapped); } } From 39759866a0ff0ca4a344bc12e1c0e590926700c9 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Thu, 14 Nov 2024 09:47:51 +0800 Subject: [PATCH 24/42] try fix IOCP --- core/src/net/operator/windows.rs | 58 +++++++++++--------------------- 1 file changed, 20 insertions(+), 38 deletions(-) diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index 77b82971..fc694f15 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -6,6 +6,7 @@ use once_cell::sync::Lazy; use std::ffi::{c_int, c_uint}; use std::io::{Error, ErrorKind}; use std::marker::PhantomData; +use std::mem::ManuallyDrop; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, Instant}; use windows_sys::core::{PCSTR, PSTR}; @@ -54,7 +55,6 @@ pub(crate) struct Operator<'o> { iocp: HANDLE, entering: AtomicBool, handles: DashSet, - context: DashMap, phantom_data: PhantomData<&'o HANDLE>, } @@ -70,7 +70,6 @@ impl Operator<'_> { iocp, entering: AtomicBool::new(false), handles: DashSet::default(), - context: DashMap::default(), phantom_data: PhantomData, }) } @@ -154,12 +153,15 @@ impl Operator<'_> { unsafe { entries.set_len(recv_count as _) }; for entry in entries { let overlapped = unsafe { &*entry.lpOverlapped.cast::() }; + cq.push(Overlapped { + base: overlapped.base, + from_fd: overlapped.from_fd, + socket: overlapped.socket, + token: overlapped.token, + syscall: overlapped.syscall, + bytes_transferred: entry.dwNumberOfBytesTransferred, + }); eprintln!("IOCP got Overlapped:{overlapped}"); - if let Some((_, mut overlapped)) = self.context.remove(&overlapped.token) { - overlapped.bytes_transferred = entry.dwNumberOfBytesTransferred; - eprintln!("after correct Overlapped bytes_transferred:{overlapped}"); - cq.push(overlapped); - } } if cq.len() >= want { break; @@ -198,7 +200,7 @@ impl Operator<'_> { .saturating_add(16) .try_into() .expect("size overflow"); - let mut overlapped: Overlapped = std::mem::zeroed(); + let mut overlapped: ManuallyDrop = ManuallyDrop::new(std::mem::zeroed()); overlapped.from_fd = fd; overlapped.socket = socket; overlapped.token = user_data; @@ -212,18 +214,14 @@ impl Operator<'_> { size, size, std::ptr::null_mut(), - std::ptr::from_mut::(&mut overlapped).cast(), + std::ptr::from_mut(&mut overlapped).cast(), ) == FALSE { if WSA_IO_PENDING == WSAGetLastError() { break; } } - eprintln!("add accept operation Overlapped:{overlapped}"); - assert!( - self.context.insert(user_data, overlapped).is_none(), - "The previous token was not retrieved in a timely manner" - ); + eprintln!("add accept operation Overlapped:{}", &*overlapped); } Ok(()) } @@ -238,7 +236,7 @@ impl Operator<'_> { ) -> std::io::Result<()> { self.add_handle(fd as HANDLE)?; unsafe { - let mut overlapped: Overlapped = std::mem::zeroed(); + let mut overlapped: ManuallyDrop = ManuallyDrop::new(std::mem::zeroed()); overlapped.from_fd = fd; overlapped.token = user_data; overlapped.syscall = Syscall::recv; @@ -252,7 +250,7 @@ impl Operator<'_> { buf.len().try_into().expect("len overflow"), std::ptr::null_mut(), &mut u32::try_from(flags).expect("overflow"), - std::ptr::from_mut::(&mut overlapped).cast(), + std::ptr::from_mut(&mut overlapped).cast(), None, ) == SOCKET_ERROR && WSA_IO_PENDING != WSAGetLastError() @@ -262,10 +260,6 @@ impl Operator<'_> { "add recv operation failed", )); } - assert!( - self.context.insert(user_data, overlapped).is_none(), - "The previous token was not retrieved in a timely manner" - ); } Ok(()) } @@ -287,7 +281,7 @@ impl Operator<'_> { ); self.add_handle(fd as HANDLE)?; unsafe { - let mut overlapped: Overlapped = std::mem::zeroed(); + let mut overlapped: ManuallyDrop = ManuallyDrop::new(std::mem::zeroed()); overlapped.from_fd = fd; overlapped.token = user_data; overlapped.syscall = Syscall::WSARecv; @@ -297,7 +291,7 @@ impl Operator<'_> { dwbuffercount, lpnumberofbytesrecvd, lpflags, - std::ptr::from_mut::(&mut overlapped).cast(), + std::ptr::from_mut(&mut overlapped).cast(), lpcompletionroutine, ) == SOCKET_ERROR && WSA_IO_PENDING != WSAGetLastError() @@ -307,10 +301,6 @@ impl Operator<'_> { "add WSARecv operation failed", )); } - assert!( - self.context.insert(user_data, overlapped).is_none(), - "The previous token was not retrieved in a timely manner" - ); } Ok(()) } @@ -325,7 +315,7 @@ impl Operator<'_> { ) -> std::io::Result<()> { self.add_handle(fd as HANDLE)?; unsafe { - let mut overlapped: Overlapped = std::mem::zeroed(); + let mut overlapped: ManuallyDrop = ManuallyDrop::new(std::mem::zeroed()); overlapped.from_fd = fd; overlapped.token = user_data; overlapped.syscall = Syscall::send; @@ -339,7 +329,7 @@ impl Operator<'_> { buf.len().try_into().expect("len overflow"), std::ptr::null_mut(), u32::try_from(flags).expect("overflow"), - std::ptr::from_mut::(&mut overlapped).cast(), + std::ptr::from_mut(&mut overlapped).cast(), None, ) == SOCKET_ERROR && WSA_IO_PENDING != WSAGetLastError() @@ -349,10 +339,6 @@ impl Operator<'_> { "add send operation failed", )); } - assert!( - self.context.insert(user_data, overlapped).is_none(), - "The previous token was not retrieved in a timely manner" - ); } Ok(()) } @@ -374,7 +360,7 @@ impl Operator<'_> { ); self.add_handle(fd as HANDLE)?; unsafe { - let mut overlapped: Overlapped = std::mem::zeroed(); + let mut overlapped: ManuallyDrop = ManuallyDrop::new(std::mem::zeroed()); overlapped.from_fd = fd; overlapped.token = user_data; overlapped.syscall = Syscall::WSASend; @@ -384,7 +370,7 @@ impl Operator<'_> { dwbuffercount, lpnumberofbytesrecvd, dwflags, - std::ptr::from_mut::(&mut overlapped).cast(), + std::ptr::from_mut(&mut overlapped).cast(), lpcompletionroutine, ) == SOCKET_ERROR && WSA_IO_PENDING != WSAGetLastError() @@ -394,10 +380,6 @@ impl Operator<'_> { "add WSASend operation failed", )); } - assert!( - self.context.insert(user_data, overlapped).is_none(), - "The previous token was not retrieved in a timely manner" - ); } Ok(()) } From 9c7918f22c82ba333394a1efc4fbe5f25e8956ec Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Thu, 14 Nov 2024 10:31:04 +0800 Subject: [PATCH 25/42] try fix IOCP --- core/src/coroutine/local.rs | 2 +- core/src/net/event_loop.rs | 2 +- core/src/net/operator/windows.rs | 13 ++++++------- core/src/syscall/windows/accept.rs | 28 +++++++++++++++------------- open-coroutine/src/lib.rs | 8 ++++---- 5 files changed, 27 insertions(+), 26 deletions(-) diff --git a/core/src/coroutine/local.rs b/core/src/coroutine/local.rs index 8354f9ee..42ddf52a 100644 --- a/core/src/coroutine/local.rs +++ b/core/src/coroutine/local.rs @@ -16,7 +16,7 @@ impl<'c> CoroutineLocal<'c> { pub fn put(&self, key: &'c str, val: V) -> Option { let v = Box::leak(Box::new(val)); self.0 - .insert(key, std::ptr::from_mut::(v) as usize) + .insert(key, std::ptr::from_mut(v) as usize) .map(|ptr| unsafe { *Box::from_raw((ptr as *mut c_void).cast::()) }) } diff --git a/core/src/net/event_loop.rs b/core/src/net/event_loop.rs index b09f3f57..f49d8256 100644 --- a/core/src/net/event_loop.rs +++ b/core/src/net/event_loop.rs @@ -318,7 +318,7 @@ impl<'e> EventLoop<'e> { cqe.socket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, - std::ptr::from_ref::(&cqe.from_fd).cast(), + std::ptr::from_ref(&cqe.from_fd).cast(), c_int::try_from(size_of::()).expect("overflow"), ); }; diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index fc694f15..fb06a2c5 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -6,7 +6,6 @@ use once_cell::sync::Lazy; use std::ffi::{c_int, c_uint}; use std::io::{Error, ErrorKind}; use std::marker::PhantomData; -use std::mem::ManuallyDrop; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, Instant}; use windows_sys::core::{PCSTR, PSTR}; @@ -200,7 +199,7 @@ impl Operator<'_> { .saturating_add(16) .try_into() .expect("size overflow"); - let mut overlapped: ManuallyDrop = ManuallyDrop::new(std::mem::zeroed()); + let mut overlapped: Overlapped = std::mem::zeroed(); overlapped.from_fd = fd; overlapped.socket = socket; overlapped.token = user_data; @@ -221,7 +220,7 @@ impl Operator<'_> { break; } } - eprintln!("add accept operation Overlapped:{}", &*overlapped); + eprintln!("add accept operation Overlapped:{overlapped}"); } Ok(()) } @@ -236,7 +235,7 @@ impl Operator<'_> { ) -> std::io::Result<()> { self.add_handle(fd as HANDLE)?; unsafe { - let mut overlapped: ManuallyDrop = ManuallyDrop::new(std::mem::zeroed()); + let mut overlapped: Overlapped = std::mem::zeroed(); overlapped.from_fd = fd; overlapped.token = user_data; overlapped.syscall = Syscall::recv; @@ -281,7 +280,7 @@ impl Operator<'_> { ); self.add_handle(fd as HANDLE)?; unsafe { - let mut overlapped: ManuallyDrop = ManuallyDrop::new(std::mem::zeroed()); + let mut overlapped: Overlapped = std::mem::zeroed(); overlapped.from_fd = fd; overlapped.token = user_data; overlapped.syscall = Syscall::WSARecv; @@ -315,7 +314,7 @@ impl Operator<'_> { ) -> std::io::Result<()> { self.add_handle(fd as HANDLE)?; unsafe { - let mut overlapped: ManuallyDrop = ManuallyDrop::new(std::mem::zeroed()); + let mut overlapped: Overlapped = std::mem::zeroed(); overlapped.from_fd = fd; overlapped.token = user_data; overlapped.syscall = Syscall::send; @@ -360,7 +359,7 @@ impl Operator<'_> { ); self.add_handle(fd as HANDLE)?; unsafe { - let mut overlapped: ManuallyDrop = ManuallyDrop::new(std::mem::zeroed()); + let mut overlapped: Overlapped = std::mem::zeroed(); overlapped.from_fd = fd; overlapped.token = user_data; overlapped.syscall = Syscall::WSASend; diff --git a/core/src/syscall/windows/accept.rs b/core/src/syscall/windows/accept.rs index f70f13e2..0c7ca018 100644 --- a/core/src/syscall/windows/accept.rs +++ b/core/src/syscall/windows/accept.rs @@ -9,16 +9,18 @@ pub extern "system" fn accept( address: *mut SOCKADDR, address_len: *mut c_int, ) -> SOCKET { - cfg_if::cfg_if! { - if #[cfg(feature = "iocp")] { - static CHAIN: Lazy< - AcceptSyscallFacade>> - > = Lazy::new(Default::default); - } else { - 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); + // } + // } + static CHAIN: Lazy>> = + Lazy::new(Default::default); CHAIN.accept(fn_ptr, fd, address, address_len) } @@ -36,9 +38,9 @@ impl_facade!(AcceptSyscallFacade, AcceptSyscall, accept(fd: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET ); -impl_iocp!(IocpAcceptSyscall, AcceptSyscall, - accept(fd: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET -); +// impl_iocp!(IocpAcceptSyscall, AcceptSyscall, +// accept(fd: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET +// ); impl_nio_read!(NioAcceptSyscall, AcceptSyscall, accept(fd: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET diff --git a/open-coroutine/src/lib.rs b/open-coroutine/src/lib.rs index 62b0d65f..f6d0aec2 100644 --- a/open-coroutine/src/lib.rs +++ b/open-coroutine/src/lib.rs @@ -114,14 +114,14 @@ pub fn task R>(f: F, param: P) -> JoinHa let ptr = &mut *((input as *mut c_void).cast::<(F, P)>()); let data = std::ptr::read_unaligned(ptr); let result: &'static mut R = Box::leak(Box::new((data.0)(data.1))); - std::ptr::from_mut::(result).cast::() as usize + std::ptr::from_mut(result).cast::() as usize } } let inner = Box::leak(Box::new((f, param))); unsafe { task_crate( task_main::, - std::ptr::from_mut::<(F, P)>(inner).cast::() as usize, + std::ptr::from_mut(inner).cast::() as usize, ) .into() } @@ -210,7 +210,7 @@ pub fn maybe_grow R>( let ptr = &mut *((input as *mut c_void).cast::()); let data = std::ptr::read_unaligned(ptr); let result: &'static mut R = Box::leak(Box::new(data())); - std::ptr::from_mut::(result).cast::() as usize + std::ptr::from_mut(result).cast::() as usize } } let inner = Box::leak(Box::new(f)); @@ -219,7 +219,7 @@ pub fn maybe_grow R>( red_zone, stack_size, execute_on_stack::, - std::ptr::from_mut::(inner).cast::() as usize, + std::ptr::from_mut(inner).cast::() as usize, ); if ptr < 0 { return Err(Error::new(ErrorKind::InvalidInput, "grow stack failed")); From fdb7d041e183f85513a14cee17e59ace93c93dfa Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Thu, 14 Nov 2024 10:50:45 +0800 Subject: [PATCH 26/42] try fix IOCP --- core/src/net/event_loop.rs | 9 +++---- core/src/net/operator/windows.rs | 41 +++++++++++++++--------------- core/src/syscall/windows/accept.rs | 28 ++++++++++---------- 3 files changed, 38 insertions(+), 40 deletions(-) diff --git a/core/src/net/event_loop.rs b/core/src/net/event_loop.rs index f49d8256..a4be4e1a 100644 --- a/core/src/net/event_loop.rs +++ b/core/src/net/event_loop.rs @@ -306,23 +306,22 @@ impl<'e> EventLoop<'e> { let (count, mut cq, left) = self.operator.select(left_time, 0)?; if count > 0 { for cqe in &mut cq { - let token = cqe.token; + let token = *cqe.token; let bytes_transferred = cqe.bytes_transferred; - eprintln!("IOCP finish {token} {bytes_transferred}"); // resolve completed read/write tasks // todo refactor IOCP impl - let result = match cqe.syscall { + let result = match *cqe.syscall { Syscall::accept => { unsafe { _ = setsockopt( - cqe.socket, + *cqe.socket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, std::ptr::from_ref(&cqe.from_fd).cast(), c_int::try_from(size_of::()).expect("overflow"), ); }; - cqe.socket.try_into().expect("result overflow") + (*cqe.socket).try_into().expect("result overflow") } Syscall::recv | Syscall::WSARecv | Syscall::send | Syscall::WSASend => { bytes_transferred.into() diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index fb06a2c5..01db58cd 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -6,6 +6,7 @@ use once_cell::sync::Lazy; use std::ffi::{c_int, c_uint}; use std::io::{Error, ErrorKind}; use std::marker::PhantomData; +use std::mem::ManuallyDrop; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, Instant}; use windows_sys::core::{PCSTR, PSTR}; @@ -38,10 +39,10 @@ pub(crate) struct Overlapped { /// The base [`OVERLAPPED`]. #[educe(Debug(ignore))] pub base: OVERLAPPED, - pub from_fd: SOCKET, - pub socket: SOCKET, - pub token: usize, - pub syscall: Syscall, + pub from_fd: ManuallyDrop, + pub socket: ManuallyDrop, + pub token: ManuallyDrop, + pub syscall: ManuallyDrop, pub bytes_transferred: u32, } @@ -200,10 +201,10 @@ impl Operator<'_> { .try_into() .expect("size overflow"); let mut overlapped: Overlapped = std::mem::zeroed(); - overlapped.from_fd = fd; - overlapped.socket = socket; - overlapped.token = user_data; - overlapped.syscall = Syscall::accept; + overlapped.from_fd = ManuallyDrop::new(fd); + overlapped.socket = ManuallyDrop::new(socket); + overlapped.token = ManuallyDrop::new(user_data); + overlapped.syscall = ManuallyDrop::new(Syscall::accept); let mut buf: Vec = Vec::with_capacity(size as usize * 2); while AcceptEx( fd, @@ -236,9 +237,9 @@ impl Operator<'_> { self.add_handle(fd as HANDLE)?; unsafe { let mut overlapped: Overlapped = std::mem::zeroed(); - overlapped.from_fd = fd; - overlapped.token = user_data; - overlapped.syscall = Syscall::recv; + overlapped.from_fd = ManuallyDrop::new(fd); + overlapped.token = ManuallyDrop::new(user_data); + overlapped.syscall = ManuallyDrop::new(Syscall::recv); let buf = [WSABUF { len: len.try_into().expect("len overflow"), buf: buf.cast(), @@ -281,9 +282,9 @@ impl Operator<'_> { self.add_handle(fd as HANDLE)?; unsafe { let mut overlapped: Overlapped = std::mem::zeroed(); - overlapped.from_fd = fd; - overlapped.token = user_data; - overlapped.syscall = Syscall::WSARecv; + overlapped.from_fd = ManuallyDrop::new(fd); + overlapped.token = ManuallyDrop::new(user_data); + overlapped.syscall = ManuallyDrop::new(Syscall::WSARecv); if WSARecv( fd, buf, @@ -315,9 +316,9 @@ impl Operator<'_> { self.add_handle(fd as HANDLE)?; unsafe { let mut overlapped: Overlapped = std::mem::zeroed(); - overlapped.from_fd = fd; - overlapped.token = user_data; - overlapped.syscall = Syscall::send; + overlapped.from_fd = ManuallyDrop::new(fd); + overlapped.token = ManuallyDrop::new(user_data); + overlapped.syscall = ManuallyDrop::new(Syscall::send); let buf = [WSABUF { len: len.try_into().expect("len overflow"), buf: buf.cast_mut(), @@ -360,9 +361,9 @@ impl Operator<'_> { self.add_handle(fd as HANDLE)?; unsafe { let mut overlapped: Overlapped = std::mem::zeroed(); - overlapped.from_fd = fd; - overlapped.token = user_data; - overlapped.syscall = Syscall::WSASend; + overlapped.from_fd = ManuallyDrop::new(fd); + overlapped.token = ManuallyDrop::new(user_data); + overlapped.syscall = ManuallyDrop::new(Syscall::WSASend); if WSASend( fd, buf, diff --git a/core/src/syscall/windows/accept.rs b/core/src/syscall/windows/accept.rs index 0c7ca018..f70f13e2 100644 --- a/core/src/syscall/windows/accept.rs +++ b/core/src/syscall/windows/accept.rs @@ -9,18 +9,16 @@ pub extern "system" fn accept( address: *mut SOCKADDR, address_len: *mut c_int, ) -> SOCKET { - // cfg_if::cfg_if! { - // if #[cfg(feature = "iocp")] { - // static CHAIN: Lazy< - // AcceptSyscallFacade>> - // > = Lazy::new(Default::default); - // } else { - // static CHAIN: Lazy>> = - // Lazy::new(Default::default); - // } - // } - 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) } @@ -38,9 +36,9 @@ impl_facade!(AcceptSyscallFacade, AcceptSyscall, accept(fd: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET ); -// impl_iocp!(IocpAcceptSyscall, AcceptSyscall, -// accept(fd: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET -// ); +impl_iocp!(IocpAcceptSyscall, AcceptSyscall, + accept(fd: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET +); impl_nio_read!(NioAcceptSyscall, AcceptSyscall, accept(fd: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET From d1715e9f323c22c24668a531798e70c4c858710b Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Thu, 14 Nov 2024 11:22:14 +0800 Subject: [PATCH 27/42] try fix IOCP --- core/src/net/event_loop.rs | 8 +-- core/src/net/operator/windows.rs | 115 ++++++++++++++++++++++--------- 2 files changed, 87 insertions(+), 36 deletions(-) diff --git a/core/src/net/event_loop.rs b/core/src/net/event_loop.rs index a4be4e1a..92af4ac5 100644 --- a/core/src/net/event_loop.rs +++ b/core/src/net/event_loop.rs @@ -306,22 +306,22 @@ impl<'e> EventLoop<'e> { let (count, mut cq, left) = self.operator.select(left_time, 0)?; if count > 0 { for cqe in &mut cq { - let token = *cqe.token; + let token = cqe.token; let bytes_transferred = cqe.bytes_transferred; // resolve completed read/write tasks // todo refactor IOCP impl - let result = match *cqe.syscall { + let result = match cqe.syscall { Syscall::accept => { unsafe { _ = setsockopt( - *cqe.socket, + cqe.socket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, std::ptr::from_ref(&cqe.from_fd).cast(), c_int::try_from(size_of::()).expect("overflow"), ); }; - (*cqe.socket).try_into().expect("result overflow") + cqe.socket.try_into().expect("result overflow") } Syscall::recv | Syscall::WSARecv | Syscall::send | Syscall::WSASend => { bytes_transferred.into() diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index 01db58cd..90a56bad 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -6,7 +6,6 @@ use once_cell::sync::Lazy; use std::ffi::{c_int, c_uint}; use std::io::{Error, ErrorKind}; use std::marker::PhantomData; -use std::mem::ManuallyDrop; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, Instant}; use windows_sys::core::{PCSTR, PSTR}; @@ -39,10 +38,10 @@ pub(crate) struct Overlapped { /// The base [`OVERLAPPED`]. #[educe(Debug(ignore))] pub base: OVERLAPPED, - pub from_fd: ManuallyDrop, - pub socket: ManuallyDrop, - pub token: ManuallyDrop, - pub syscall: ManuallyDrop, + pub from_fd: SOCKET, + pub socket: SOCKET, + pub token: usize, + pub syscall: Syscall, pub bytes_transferred: u32, } @@ -55,6 +54,7 @@ pub(crate) struct Operator<'o> { iocp: HANDLE, entering: AtomicBool, handles: DashSet, + context: DashMap<(u32, u32), Overlapped>, phantom_data: PhantomData<&'o HANDLE>, } @@ -70,6 +70,7 @@ impl Operator<'_> { iocp, entering: AtomicBool::new(false), handles: DashSet::default(), + context: DashMap::default(), phantom_data: PhantomData, }) } @@ -152,16 +153,16 @@ impl Operator<'_> { } unsafe { entries.set_len(recv_count as _) }; for entry in entries { - let overlapped = unsafe { &*entry.lpOverlapped.cast::() }; - cq.push(Overlapped { - base: overlapped.base, - from_fd: overlapped.from_fd, - socket: overlapped.socket, - token: overlapped.token, - syscall: overlapped.syscall, - bytes_transferred: entry.dwNumberOfBytesTransferred, - }); - eprintln!("IOCP got Overlapped:{overlapped}"); + let parts = unsafe { + let union = &(*entry.lpOverlapped).Anonymous.Anonymous; + (union.Offset, union.OffsetHigh) + }; + eprintln!("IOCP got OVERLAPPED:{parts:?}"); + if let Some((_, mut overlapped)) = self.context.remove(&parts) { + overlapped.bytes_transferred = entry.dwNumberOfBytesTransferred; + eprintln!("correct IOCP Overlapped:{overlapped}"); + cq.push(overlapped); + } } if cq.len() >= want { break; @@ -201,10 +202,16 @@ impl Operator<'_> { .try_into() .expect("size overflow"); let mut overlapped: Overlapped = std::mem::zeroed(); - overlapped.from_fd = ManuallyDrop::new(fd); - overlapped.socket = ManuallyDrop::new(socket); - overlapped.token = ManuallyDrop::new(user_data); - overlapped.syscall = ManuallyDrop::new(Syscall::accept); + let parts = ( + (user_data as u64 & 0xFFFF_FFFF) as u32, + (user_data as u64 >> 32) as u32, + ); + overlapped.base.Anonymous.Anonymous.Offset = parts.0; + overlapped.base.Anonymous.Anonymous.OffsetHigh = parts.1; + overlapped.from_fd = fd; + overlapped.socket = socket; + overlapped.token = user_data; + overlapped.syscall = Syscall::accept; let mut buf: Vec = Vec::with_capacity(size as usize * 2); while AcceptEx( fd, @@ -221,7 +228,11 @@ impl Operator<'_> { break; } } - eprintln!("add accept operation Overlapped:{overlapped}"); + eprintln!("add accept operation OVERLAPPED:{parts:?}"); + assert!( + self.context.insert(parts, overlapped).is_none(), + "The previous token was not retrieved in a timely manner" + ); } Ok(()) } @@ -237,9 +248,15 @@ impl Operator<'_> { self.add_handle(fd as HANDLE)?; unsafe { let mut overlapped: Overlapped = std::mem::zeroed(); - overlapped.from_fd = ManuallyDrop::new(fd); - overlapped.token = ManuallyDrop::new(user_data); - overlapped.syscall = ManuallyDrop::new(Syscall::recv); + let parts = ( + (user_data as u64 & 0xFFFF_FFFF) as u32, + (user_data as u64 >> 32) as u32, + ); + overlapped.base.Anonymous.Anonymous.Offset = parts.0; + overlapped.base.Anonymous.Anonymous.OffsetHigh = parts.1; + overlapped.from_fd = fd; + overlapped.token = user_data; + overlapped.syscall = Syscall::recv; let buf = [WSABUF { len: len.try_into().expect("len overflow"), buf: buf.cast(), @@ -260,6 +277,10 @@ impl Operator<'_> { "add recv operation failed", )); } + assert!( + self.context.insert(parts, overlapped).is_none(), + "The previous token was not retrieved in a timely manner" + ); } Ok(()) } @@ -282,9 +303,15 @@ impl Operator<'_> { self.add_handle(fd as HANDLE)?; unsafe { let mut overlapped: Overlapped = std::mem::zeroed(); - overlapped.from_fd = ManuallyDrop::new(fd); - overlapped.token = ManuallyDrop::new(user_data); - overlapped.syscall = ManuallyDrop::new(Syscall::WSARecv); + let parts = ( + (user_data as u64 & 0xFFFF_FFFF) as u32, + (user_data as u64 >> 32) as u32, + ); + overlapped.base.Anonymous.Anonymous.Offset = parts.0; + overlapped.base.Anonymous.Anonymous.OffsetHigh = parts.1; + overlapped.from_fd = fd; + overlapped.token = user_data; + overlapped.syscall = Syscall::WSARecv; if WSARecv( fd, buf, @@ -301,6 +328,10 @@ impl Operator<'_> { "add WSARecv operation failed", )); } + assert!( + self.context.insert(parts, overlapped).is_none(), + "The previous token was not retrieved in a timely manner" + ); } Ok(()) } @@ -316,9 +347,15 @@ impl Operator<'_> { self.add_handle(fd as HANDLE)?; unsafe { let mut overlapped: Overlapped = std::mem::zeroed(); - overlapped.from_fd = ManuallyDrop::new(fd); - overlapped.token = ManuallyDrop::new(user_data); - overlapped.syscall = ManuallyDrop::new(Syscall::send); + let parts = ( + (user_data as u64 & 0xFFFF_FFFF) as u32, + (user_data as u64 >> 32) as u32, + ); + overlapped.base.Anonymous.Anonymous.Offset = parts.0; + overlapped.base.Anonymous.Anonymous.OffsetHigh = parts.1; + overlapped.from_fd = fd; + overlapped.token = user_data; + overlapped.syscall = Syscall::send; let buf = [WSABUF { len: len.try_into().expect("len overflow"), buf: buf.cast_mut(), @@ -339,6 +376,10 @@ impl Operator<'_> { "add send operation failed", )); } + assert!( + self.context.insert(parts, overlapped).is_none(), + "The previous token was not retrieved in a timely manner" + ); } Ok(()) } @@ -361,9 +402,15 @@ impl Operator<'_> { self.add_handle(fd as HANDLE)?; unsafe { let mut overlapped: Overlapped = std::mem::zeroed(); - overlapped.from_fd = ManuallyDrop::new(fd); - overlapped.token = ManuallyDrop::new(user_data); - overlapped.syscall = ManuallyDrop::new(Syscall::WSASend); + let parts = ( + (user_data as u64 & 0xFFFF_FFFF) as u32, + (user_data as u64 >> 32) as u32, + ); + overlapped.base.Anonymous.Anonymous.Offset = parts.0; + overlapped.base.Anonymous.Anonymous.OffsetHigh = parts.1; + overlapped.from_fd = fd; + overlapped.token = user_data; + overlapped.syscall = Syscall::WSASend; if WSASend( fd, buf, @@ -380,6 +427,10 @@ impl Operator<'_> { "add WSASend operation failed", )); } + assert!( + self.context.insert(parts, overlapped).is_none(), + "The previous token was not retrieved in a timely manner" + ); } Ok(()) } From 39c68d23384a756a966abced2dece5d90edf0913 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Thu, 14 Nov 2024 11:37:01 +0800 Subject: [PATCH 28/42] add log --- core/src/net/operator/windows.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index 90a56bad..3d901c9c 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -157,10 +157,10 @@ impl Operator<'_> { let union = &(*entry.lpOverlapped).Anonymous.Anonymous; (union.Offset, union.OffsetHigh) }; - eprintln!("IOCP got OVERLAPPED:{parts:?}"); + eprintln!("IOCP got parts:{parts:?}"); if let Some((_, mut overlapped)) = self.context.remove(&parts) { overlapped.bytes_transferred = entry.dwNumberOfBytesTransferred; - eprintln!("correct IOCP Overlapped:{overlapped}"); + eprintln!("IOCP got Overlapped:{overlapped}"); cq.push(overlapped); } } @@ -228,7 +228,7 @@ impl Operator<'_> { break; } } - eprintln!("add accept operation OVERLAPPED:{parts:?}"); + eprintln!("add accept operation parts:{parts:?} Overlapped:{overlapped}"); assert!( self.context.insert(parts, overlapped).is_none(), "The previous token was not retrieved in a timely manner" @@ -277,6 +277,7 @@ impl Operator<'_> { "add recv operation failed", )); } + eprintln!("add recv operation parts:{parts:?} Overlapped:{overlapped}"); assert!( self.context.insert(parts, overlapped).is_none(), "The previous token was not retrieved in a timely manner" @@ -328,6 +329,7 @@ impl Operator<'_> { "add WSARecv operation failed", )); } + eprintln!("add WSARecv operation parts:{parts:?} Overlapped:{overlapped}"); assert!( self.context.insert(parts, overlapped).is_none(), "The previous token was not retrieved in a timely manner" @@ -376,6 +378,7 @@ impl Operator<'_> { "add send operation failed", )); } + eprintln!("add send operation parts:{parts:?} Overlapped:{overlapped}"); assert!( self.context.insert(parts, overlapped).is_none(), "The previous token was not retrieved in a timely manner" @@ -427,6 +430,7 @@ impl Operator<'_> { "add WSASend operation failed", )); } + eprintln!("add WSASend operation parts:{parts:?} Overlapped:{overlapped}"); assert!( self.context.insert(parts, overlapped).is_none(), "The previous token was not retrieved in a timely manner" From c92f5c8c6c8142983c9ac75a6a3bb545a625e18c Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Thu, 14 Nov 2024 13:38:25 +0800 Subject: [PATCH 29/42] add log --- core/src/net/event_loop.rs | 28 ++++++++++++++++------------ core/src/syscall/windows/mod.rs | 24 ++++++++++++------------ 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/core/src/net/event_loop.rs b/core/src/net/event_loop.rs index 92af4ac5..c738d2bd 100644 --- a/core/src/net/event_loop.rs +++ b/core/src/net/event_loop.rs @@ -311,18 +311,22 @@ impl<'e> EventLoop<'e> { // resolve completed read/write tasks // todo refactor IOCP impl let result = match cqe.syscall { - Syscall::accept => { - unsafe { - _ = setsockopt( - cqe.socket, - SOL_SOCKET, - SO_UPDATE_ACCEPT_CONTEXT, - std::ptr::from_ref(&cqe.from_fd).cast(), - c_int::try_from(size_of::()).expect("overflow"), - ); - }; - cqe.socket.try_into().expect("result overflow") - } + Syscall::accept => unsafe { + if setsockopt( + cqe.socket, + SOL_SOCKET, + SO_UPDATE_ACCEPT_CONTEXT, + std::ptr::from_ref(&cqe.from_fd).cast(), + c_int::try_from(size_of::()).expect("overflow"), + ) == 0 + { + #[cfg(feature = "syscall")] + crate::syscall::common::reset_errno(); + cqe.socket.try_into().expect("result overflow") + } else { + -c_longlong::from(windows_sys::Win32::Foundation::GetLastError()) + } + }, Syscall::recv | Syscall::WSARecv | Syscall::send | Syscall::WSASend => { bytes_transferred.into() } diff --git a/core/src/syscall/windows/mod.rs b/core/src/syscall/windows/mod.rs index 747214c3..eaaf9f23 100644 --- a/core/src/syscall/windows/mod.rs +++ b/core/src/syscall/windows/mod.rs @@ -95,22 +95,22 @@ macro_rules! impl_iocp { } } let (lock, cvar) = &*arc; - let syscall_result: $result = cvar + let mut syscall_result = cvar .wait_while(lock.lock().expect("lock failed"), |&mut result| result.is_none() ) .expect("lock failed") - .expect("no syscall result") - .try_into() - .expect("IOCP syscall result overflow"); - // fixme 错误处理 - // if syscall_result < 0 { - // let errno: std::ffi::c_int = (-syscall_result).try_into() - // .expect("IOCP errno overflow"); - // $crate::syscall::common::set_errno(errno); - // syscall_result = -1; - // } - syscall_result + .expect("no syscall result"); + if syscall_result < 0 { + let errno = -syscall_result; + $crate::syscall::common::set_errno(errno.try_into().expect("errno overflow")); + if $crate::common::constants::Syscall::accept == $crate::common::constants::Syscall::$syscall { + syscall_result = 0; + } else { + syscall_result = -1; + } + } + <$result>::try_from(syscall_result).expect("overflow") } Err(e) => { if e.kind() == std::io::ErrorKind::Other { From bb33f7c97f17eb0708cd94f21340546a1dd845ab Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Thu, 14 Nov 2024 15:59:54 +0800 Subject: [PATCH 30/42] add log --- core/src/net/event_loop.rs | 2 -- core/src/syscall/windows/mod.rs | 8 ++++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/core/src/net/event_loop.rs b/core/src/net/event_loop.rs index c738d2bd..6fe58748 100644 --- a/core/src/net/event_loop.rs +++ b/core/src/net/event_loop.rs @@ -283,7 +283,6 @@ impl<'e> EventLoop<'e> { } // resolve completed read/write tasks let result = c_longlong::from(cqe.result()); - eprintln!("io_uring finish {token} {result}"); if let Some((_, pair)) = self.syscall_wait_table.remove(&token) { let (lock, cvar) = &*pair; let mut pending = lock.lock().expect("lock failed"); @@ -332,7 +331,6 @@ impl<'e> EventLoop<'e> { } _ => panic!("unsupported"), }; - eprintln!("IOCP finish {token} {result}"); if let Some((_, pair)) = self.syscall_wait_table.remove(&token) { let (lock, cvar) = &*pair; let mut pending = lock.lock().expect("lock failed"); diff --git a/core/src/syscall/windows/mod.rs b/core/src/syscall/windows/mod.rs index eaaf9f23..0b5f7757 100644 --- a/core/src/syscall/windows/mod.rs +++ b/core/src/syscall/windows/mod.rs @@ -59,7 +59,7 @@ macro_rules! impl_iocp { fn_ptr: Option<&extern "system" fn($($arg_type),*) -> $result>, $($arg: $arg_type),* ) -> $result { - use $crate::common::constants::{CoroutineState, SyscallState}; + use $crate::common::constants::{CoroutineState, Syscall, SyscallState}; use $crate::scheduler::{SchedulableCoroutine, SchedulableSuspender}; match $crate::net::EventLoops::$syscall($($arg, )*) { @@ -101,10 +101,14 @@ macro_rules! impl_iocp { ) .expect("lock failed") .expect("no syscall result"); + eprintln!( + "syscall:{} returns:{} e:{}", + Syscall::$syscall, syscall_result, std::io::Error::last_os_error() + ); if syscall_result < 0 { let errno = -syscall_result; $crate::syscall::common::set_errno(errno.try_into().expect("errno overflow")); - if $crate::common::constants::Syscall::accept == $crate::common::constants::Syscall::$syscall { + if Syscall::accept == Syscall::$syscall { syscall_result = 0; } else { syscall_result = -1; From dc8c18a29fa9afeb03368915bceb6306ad612271 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Thu, 14 Nov 2024 16:10:31 +0800 Subject: [PATCH 31/42] add log --- core/src/net/event_loop.rs | 2 -- core/src/syscall/windows/mod.rs | 4 +++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/net/event_loop.rs b/core/src/net/event_loop.rs index 6fe58748..93708580 100644 --- a/core/src/net/event_loop.rs +++ b/core/src/net/event_loop.rs @@ -319,8 +319,6 @@ impl<'e> EventLoop<'e> { c_int::try_from(size_of::()).expect("overflow"), ) == 0 { - #[cfg(feature = "syscall")] - crate::syscall::common::reset_errno(); cqe.socket.try_into().expect("result overflow") } else { -c_longlong::from(windows_sys::Win32::Foundation::GetLastError()) diff --git a/core/src/syscall/windows/mod.rs b/core/src/syscall/windows/mod.rs index 0b5f7757..8174747d 100644 --- a/core/src/syscall/windows/mod.rs +++ b/core/src/syscall/windows/mod.rs @@ -105,7 +105,9 @@ macro_rules! impl_iocp { "syscall:{} returns:{} e:{}", Syscall::$syscall, syscall_result, std::io::Error::last_os_error() ); - if syscall_result < 0 { + if syscall_result >= 0 { + $crate::syscall::common::reset_errno(); + } else { let errno = -syscall_result; $crate::syscall::common::set_errno(errno.try_into().expect("errno overflow")); if Syscall::accept == Syscall::$syscall { From cce5961ae6bb1e30d1239298ddc1e5f60adcea13 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Thu, 14 Nov 2024 16:22:24 +0800 Subject: [PATCH 32/42] add log --- core/src/syscall/windows/accept.rs | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/core/src/syscall/windows/accept.rs b/core/src/syscall/windows/accept.rs index f70f13e2..0c7ca018 100644 --- a/core/src/syscall/windows/accept.rs +++ b/core/src/syscall/windows/accept.rs @@ -9,16 +9,18 @@ pub extern "system" fn accept( address: *mut SOCKADDR, address_len: *mut c_int, ) -> SOCKET { - cfg_if::cfg_if! { - if #[cfg(feature = "iocp")] { - static CHAIN: Lazy< - AcceptSyscallFacade>> - > = Lazy::new(Default::default); - } else { - 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); + // } + // } + static CHAIN: Lazy>> = + Lazy::new(Default::default); CHAIN.accept(fn_ptr, fd, address, address_len) } @@ -36,9 +38,9 @@ impl_facade!(AcceptSyscallFacade, AcceptSyscall, accept(fd: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET ); -impl_iocp!(IocpAcceptSyscall, AcceptSyscall, - accept(fd: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET -); +// impl_iocp!(IocpAcceptSyscall, AcceptSyscall, +// accept(fd: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET +// ); impl_nio_read!(NioAcceptSyscall, AcceptSyscall, accept(fd: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET From ffe34cb8bfe5f536ba980ae867730c413fca9e70 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Fri, 15 Nov 2024 17:03:11 +0800 Subject: [PATCH 33/42] make CI faster --- .github/workflows/ci.sh | 7 ++ core/src/net/mod.rs | 2 +- core/src/net/operator/windows.rs | 120 +++++++++++-------------------- 3 files changed, 49 insertions(+), 80 deletions(-) diff --git a/.github/workflows/ci.sh b/.github/workflows/ci.sh index e97641eb..27e1dcab 100644 --- a/.github/workflows/ci.sh +++ b/.github/workflows/ci.sh @@ -15,6 +15,13 @@ fi export RUST_TEST_THREADS=1 export RUST_BACKTRACE=1 +# todo remove this +if [ "${OS}" = "windows-latest" ]; then + cd "${PROJECT_DIR}"/open-coroutine + "${CARGO}" test --target "${TARGET}" --no-default-features --features iocp + "${CARGO}" test --target "${TARGET}" --no-default-features --features iocp --release +fi + # test open-coroutine-core mod cd "${PROJECT_DIR}"/core "${CARGO}" test --target "${TARGET}" diff --git a/core/src/net/mod.rs b/core/src/net/mod.rs index f1818c8a..1871a8b7 100644 --- a/core/src/net/mod.rs +++ b/core/src/net/mod.rs @@ -48,7 +48,7 @@ mod selector; all(target_os = "linux", feature = "io_uring"), all(windows, feature = "iocp") ))] -mod operator; +pub(crate) mod operator; #[allow(missing_docs)] pub mod event_loop; diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index 3d901c9c..9c20911a 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -45,6 +45,25 @@ pub(crate) struct Overlapped { pub bytes_transferred: u32, } +impl Default for Overlapped { + fn default() -> Self { + unsafe { std::mem::zeroed() } + } +} + +impl From<&Overlapped> for Overlapped { + fn from(val: &Overlapped) -> Self { + Self { + base: val.base.clone(), + from_fd: val.from_fd, + socket: val.socket, + token: val.token, + syscall: val.syscall, + bytes_transferred: val.bytes_transferred, + } + } +} + impl_display_by_debug!(Overlapped); #[repr(C)] @@ -54,11 +73,10 @@ pub(crate) struct Operator<'o> { iocp: HANDLE, entering: AtomicBool, handles: DashSet, - context: DashMap<(u32, u32), Overlapped>, - phantom_data: PhantomData<&'o HANDLE>, + phantom_data: PhantomData<&'o Overlapped>, } -impl Operator<'_> { +impl<'o> Operator<'o> { pub(crate) fn new(cpu: usize) -> std::io::Result { let iocp = unsafe { CreateIoCompletionPort(INVALID_HANDLE_VALUE, std::ptr::null_mut(), 0, 0) }; @@ -70,7 +88,6 @@ impl Operator<'_> { iocp, entering: AtomicBool::new(false), handles: DashSet::default(), - context: DashMap::default(), phantom_data: PhantomData, }) } @@ -153,16 +170,11 @@ impl Operator<'_> { } unsafe { entries.set_len(recv_count as _) }; for entry in entries { - let parts = unsafe { - let union = &(*entry.lpOverlapped).Anonymous.Anonymous; - (union.Offset, union.OffsetHigh) - }; - eprintln!("IOCP got parts:{parts:?}"); - if let Some((_, mut overlapped)) = self.context.remove(&parts) { - overlapped.bytes_transferred = entry.dwNumberOfBytesTransferred; - eprintln!("IOCP got Overlapped:{overlapped}"); - cq.push(overlapped); - } + let mut overlapped = + Overlapped::from(unsafe { &*entry.lpOverlapped.cast::() }); + overlapped.bytes_transferred = entry.dwNumberOfBytesTransferred; + eprintln!("IOCP got Overlapped:{overlapped}"); + cq.push(overlapped); } if cq.len() >= want { break; @@ -201,13 +213,7 @@ impl Operator<'_> { .saturating_add(16) .try_into() .expect("size overflow"); - let mut overlapped: Overlapped = std::mem::zeroed(); - let parts = ( - (user_data as u64 & 0xFFFF_FFFF) as u32, - (user_data as u64 >> 32) as u32, - ); - overlapped.base.Anonymous.Anonymous.Offset = parts.0; - overlapped.base.Anonymous.Anonymous.OffsetHigh = parts.1; + let overlapped: &'o mut Overlapped = Box::leak(Box::default()); overlapped.from_fd = fd; overlapped.socket = socket; overlapped.token = user_data; @@ -221,18 +227,14 @@ impl Operator<'_> { size, size, std::ptr::null_mut(), - std::ptr::from_mut(&mut overlapped).cast(), + std::ptr::from_mut(overlapped).cast(), ) == FALSE { if WSA_IO_PENDING == WSAGetLastError() { break; } } - eprintln!("add accept operation parts:{parts:?} Overlapped:{overlapped}"); - assert!( - self.context.insert(parts, overlapped).is_none(), - "The previous token was not retrieved in a timely manner" - ); + eprintln!("add accept operation Overlapped:{overlapped}"); } Ok(()) } @@ -247,13 +249,7 @@ impl Operator<'_> { ) -> std::io::Result<()> { self.add_handle(fd as HANDLE)?; unsafe { - let mut overlapped: Overlapped = std::mem::zeroed(); - let parts = ( - (user_data as u64 & 0xFFFF_FFFF) as u32, - (user_data as u64 >> 32) as u32, - ); - overlapped.base.Anonymous.Anonymous.Offset = parts.0; - overlapped.base.Anonymous.Anonymous.OffsetHigh = parts.1; + let overlapped: &'o mut Overlapped = Box::leak(Box::default()); overlapped.from_fd = fd; overlapped.token = user_data; overlapped.syscall = Syscall::recv; @@ -267,7 +263,7 @@ impl Operator<'_> { buf.len().try_into().expect("len overflow"), std::ptr::null_mut(), &mut u32::try_from(flags).expect("overflow"), - std::ptr::from_mut(&mut overlapped).cast(), + std::ptr::from_mut(overlapped).cast(), None, ) == SOCKET_ERROR && WSA_IO_PENDING != WSAGetLastError() @@ -277,11 +273,7 @@ impl Operator<'_> { "add recv operation failed", )); } - eprintln!("add recv operation parts:{parts:?} Overlapped:{overlapped}"); - assert!( - self.context.insert(parts, overlapped).is_none(), - "The previous token was not retrieved in a timely manner" - ); + eprintln!("add recv operation Overlapped:{overlapped}"); } Ok(()) } @@ -303,13 +295,7 @@ impl Operator<'_> { ); self.add_handle(fd as HANDLE)?; unsafe { - let mut overlapped: Overlapped = std::mem::zeroed(); - let parts = ( - (user_data as u64 & 0xFFFF_FFFF) as u32, - (user_data as u64 >> 32) as u32, - ); - overlapped.base.Anonymous.Anonymous.Offset = parts.0; - overlapped.base.Anonymous.Anonymous.OffsetHigh = parts.1; + let overlapped: &'o mut Overlapped = Box::leak(Box::default()); overlapped.from_fd = fd; overlapped.token = user_data; overlapped.syscall = Syscall::WSARecv; @@ -319,7 +305,7 @@ impl Operator<'_> { dwbuffercount, lpnumberofbytesrecvd, lpflags, - std::ptr::from_mut(&mut overlapped).cast(), + std::ptr::from_mut(overlapped).cast(), lpcompletionroutine, ) == SOCKET_ERROR && WSA_IO_PENDING != WSAGetLastError() @@ -329,11 +315,7 @@ impl Operator<'_> { "add WSARecv operation failed", )); } - eprintln!("add WSARecv operation parts:{parts:?} Overlapped:{overlapped}"); - assert!( - self.context.insert(parts, overlapped).is_none(), - "The previous token was not retrieved in a timely manner" - ); + eprintln!("add WSARecv operation Overlapped:{overlapped}"); } Ok(()) } @@ -348,13 +330,7 @@ impl Operator<'_> { ) -> std::io::Result<()> { self.add_handle(fd as HANDLE)?; unsafe { - let mut overlapped: Overlapped = std::mem::zeroed(); - let parts = ( - (user_data as u64 & 0xFFFF_FFFF) as u32, - (user_data as u64 >> 32) as u32, - ); - overlapped.base.Anonymous.Anonymous.Offset = parts.0; - overlapped.base.Anonymous.Anonymous.OffsetHigh = parts.1; + let overlapped: &'o mut Overlapped = Box::leak(Box::default()); overlapped.from_fd = fd; overlapped.token = user_data; overlapped.syscall = Syscall::send; @@ -368,7 +344,7 @@ impl Operator<'_> { buf.len().try_into().expect("len overflow"), std::ptr::null_mut(), u32::try_from(flags).expect("overflow"), - std::ptr::from_mut(&mut overlapped).cast(), + std::ptr::from_mut(overlapped).cast(), None, ) == SOCKET_ERROR && WSA_IO_PENDING != WSAGetLastError() @@ -378,11 +354,7 @@ impl Operator<'_> { "add send operation failed", )); } - eprintln!("add send operation parts:{parts:?} Overlapped:{overlapped}"); - assert!( - self.context.insert(parts, overlapped).is_none(), - "The previous token was not retrieved in a timely manner" - ); + eprintln!("add send operation Overlapped:{overlapped}"); } Ok(()) } @@ -404,13 +376,7 @@ impl Operator<'_> { ); self.add_handle(fd as HANDLE)?; unsafe { - let mut overlapped: Overlapped = std::mem::zeroed(); - let parts = ( - (user_data as u64 & 0xFFFF_FFFF) as u32, - (user_data as u64 >> 32) as u32, - ); - overlapped.base.Anonymous.Anonymous.Offset = parts.0; - overlapped.base.Anonymous.Anonymous.OffsetHigh = parts.1; + let overlapped: &'o mut Overlapped = Box::leak(Box::default()); overlapped.from_fd = fd; overlapped.token = user_data; overlapped.syscall = Syscall::WSASend; @@ -420,7 +386,7 @@ impl Operator<'_> { dwbuffercount, lpnumberofbytesrecvd, dwflags, - std::ptr::from_mut(&mut overlapped).cast(), + std::ptr::from_mut(overlapped).cast(), lpcompletionroutine, ) == SOCKET_ERROR && WSA_IO_PENDING != WSAGetLastError() @@ -430,11 +396,7 @@ impl Operator<'_> { "add WSASend operation failed", )); } - eprintln!("add WSASend operation parts:{parts:?} Overlapped:{overlapped}"); - assert!( - self.context.insert(parts, overlapped).is_none(), - "The previous token was not retrieved in a timely manner" - ); + eprintln!("add WSASend operation Overlapped:{overlapped}"); } Ok(()) } From 054174b5125c6318ce17e857e4ec21410a35c8bd Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Fri, 15 Nov 2024 17:19:07 +0800 Subject: [PATCH 34/42] try pass IOCP CI --- core/src/net/operator/windows.rs | 15 +-------------- hook/src/syscall/windows.rs | 1 + 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index 9c20911a..673a8226 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -51,19 +51,6 @@ impl Default for Overlapped { } } -impl From<&Overlapped> for Overlapped { - fn from(val: &Overlapped) -> Self { - Self { - base: val.base.clone(), - from_fd: val.from_fd, - socket: val.socket, - token: val.token, - syscall: val.syscall, - bytes_transferred: val.bytes_transferred, - } - } -} - impl_display_by_debug!(Overlapped); #[repr(C)] @@ -171,7 +158,7 @@ impl<'o> Operator<'o> { unsafe { entries.set_len(recv_count as _) }; for entry in entries { let mut overlapped = - Overlapped::from(unsafe { &*entry.lpOverlapped.cast::() }); + unsafe { *Box::from_raw(entry.lpOverlapped.cast::()) }; overlapped.bytes_transferred = entry.dwNumberOfBytesTransferred; eprintln!("IOCP got Overlapped:{overlapped}"); cq.push(overlapped); diff --git a/hook/src/syscall/windows.rs b/hook/src/syscall/windows.rs index 418335fa..50666697 100644 --- a/hook/src/syscall/windows.rs +++ b/hook/src/syscall/windows.rs @@ -143,6 +143,7 @@ unsafe fn attach() -> std::io::Result<()> { nfds: c_uint, timeout: c_int ) -> c_int); + #[cfg(not(feature = "iocp"))] impl_hook!("kernel32.dll", SLEEP, Sleep(dw_milliseconds: u32) -> ()); impl_hook!("kernel32.dll", CREATEFILEW, CreateFileW( lpfilename: PCWSTR, From 37e7853bf6befeff81dee6301eb845128dc4fb32 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Fri, 15 Nov 2024 17:41:40 +0800 Subject: [PATCH 35/42] test accept IOCP --- core/src/net/operator/mod.rs | 3 +-- core/src/net/operator/windows.rs | 41 +++++++++++++++++++++++++++++ core/src/syscall/windows/WSARecv.rs | 22 +++++++++------- core/src/syscall/windows/WSASend.rs | 22 +++++++++------- core/src/syscall/windows/accept.rs | 28 +++++++++----------- core/src/syscall/windows/recv.rs | 22 +++++++++------- core/src/syscall/windows/send.rs | 22 +++++++++------- hook/src/syscall/windows.rs | 8 +----- 8 files changed, 104 insertions(+), 64 deletions(-) diff --git a/core/src/net/operator/mod.rs b/core/src/net/operator/mod.rs index d75a5fd4..1b246c8b 100644 --- a/core/src/net/operator/mod.rs +++ b/core/src/net/operator/mod.rs @@ -1,10 +1,9 @@ -#[allow(clippy::too_many_arguments)] #[cfg(all(target_os = "linux", feature = "io_uring"))] mod linux; #[cfg(all(target_os = "linux", feature = "io_uring"))] pub(crate) use linux::*; -#[allow(non_snake_case, clippy::too_many_arguments)] +#[allow(non_snake_case)] #[cfg(all(windows, feature = "iocp"))] mod windows; #[cfg(all(windows, feature = "iocp"))] diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index 673a8226..0c9b20e0 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -346,6 +346,47 @@ impl<'o> Operator<'o> { Ok(()) } + pub(crate) fn write( + &self, + user_data: usize, + fd: c_int, + buf: *const c_void, + count: c_uint, + ) -> std::io::Result<()> { + self.add_handle(fd as HANDLE)?; + unsafe { + if SOCKET_CONTEXT.get(&(fd as SOCKET)).is_some() { + let overlapped: &'o mut Overlapped = Box::leak(Box::default()); + overlapped.from_fd = fd as _; + overlapped.token = user_data; + overlapped.syscall = Syscall::write; + let buf = [WSABUF { + len: count, + buf: buf.cast_mut().cast(), + }]; + if WSASend( + fd as _, + buf.as_ptr(), + buf.len().try_into().expect("len overflow"), + std::ptr::null_mut(), + 0, + std::ptr::from_mut(overlapped).cast(), + None, + ) == SOCKET_ERROR + && WSA_IO_PENDING != WSAGetLastError() + { + return Err(Error::new( + ErrorKind::WouldBlock, + "add write operation failed", + )); + } + eprintln!("add write operation Overlapped:{overlapped}"); + return Ok(()); + } + } + todo!() + } + pub(crate) fn WSASend( &self, user_data: usize, diff --git a/core/src/syscall/windows/WSARecv.rs b/core/src/syscall/windows/WSARecv.rs index 9df06b71..3ab8e89c 100644 --- a/core/src/syscall/windows/WSARecv.rs +++ b/core/src/syscall/windows/WSARecv.rs @@ -27,16 +27,18 @@ pub extern "system" fn WSARecv( lpoverlapped: *mut OVERLAPPED, lpcompletionroutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, ) -> c_int { - cfg_if::cfg_if! { - if #[cfg(all(windows, feature = "iocp"))] { - static CHAIN: Lazy< - WSARecvSyscallFacade>> - > = Lazy::new(Default::default); - } else { - static CHAIN: Lazy>> = - Lazy::new(Default::default); - } - } + // cfg_if::cfg_if! { + // if #[cfg(all(windows, feature = "iocp"))] { + // static CHAIN: Lazy< + // WSARecvSyscallFacade>> + // > = Lazy::new(Default::default); + // } else { + // static CHAIN: Lazy>> = + // Lazy::new(Default::default); + // } + // } + static CHAIN: Lazy>> = + Lazy::new(Default::default); CHAIN.WSARecv( fn_ptr, fd, diff --git a/core/src/syscall/windows/WSASend.rs b/core/src/syscall/windows/WSASend.rs index 8e1f763f..0b5134d9 100644 --- a/core/src/syscall/windows/WSASend.rs +++ b/core/src/syscall/windows/WSASend.rs @@ -27,16 +27,18 @@ pub extern "system" fn WSASend( lpoverlapped: *mut OVERLAPPED, lpcompletionroutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, ) -> c_int { - cfg_if::cfg_if! { - if #[cfg(all(windows, feature = "iocp"))] { - static CHAIN: Lazy< - WSASendSyscallFacade>> - > = Lazy::new(Default::default); - } else { - static CHAIN: Lazy>> = - Lazy::new(Default::default); - } - } + // cfg_if::cfg_if! { + // if #[cfg(all(windows, feature = "iocp"))] { + // static CHAIN: Lazy< + // WSASendSyscallFacade>> + // > = Lazy::new(Default::default); + // } else { + // static CHAIN: Lazy>> = + // Lazy::new(Default::default); + // } + // } + static CHAIN: Lazy>> = + Lazy::new(Default::default); CHAIN.WSASend( fn_ptr, fd, diff --git a/core/src/syscall/windows/accept.rs b/core/src/syscall/windows/accept.rs index 0c7ca018..f70f13e2 100644 --- a/core/src/syscall/windows/accept.rs +++ b/core/src/syscall/windows/accept.rs @@ -9,18 +9,16 @@ pub extern "system" fn accept( address: *mut SOCKADDR, address_len: *mut c_int, ) -> SOCKET { - // cfg_if::cfg_if! { - // if #[cfg(feature = "iocp")] { - // static CHAIN: Lazy< - // AcceptSyscallFacade>> - // > = Lazy::new(Default::default); - // } else { - // static CHAIN: Lazy>> = - // Lazy::new(Default::default); - // } - // } - 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) } @@ -38,9 +36,9 @@ impl_facade!(AcceptSyscallFacade, AcceptSyscall, accept(fd: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET ); -// impl_iocp!(IocpAcceptSyscall, AcceptSyscall, -// accept(fd: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET -// ); +impl_iocp!(IocpAcceptSyscall, AcceptSyscall, + accept(fd: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET +); impl_nio_read!(NioAcceptSyscall, AcceptSyscall, accept(fd: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET diff --git a/core/src/syscall/windows/recv.rs b/core/src/syscall/windows/recv.rs index a0b28fc3..aee998dc 100644 --- a/core/src/syscall/windows/recv.rs +++ b/core/src/syscall/windows/recv.rs @@ -11,16 +11,18 @@ pub extern "system" fn recv( len: c_int, flags: SEND_RECV_FLAGS, ) -> c_int { - cfg_if::cfg_if! { - if #[cfg(all(windows, feature = "iocp"))] { - static CHAIN: Lazy< - RecvSyscallFacade>> - > = Lazy::new(Default::default); - } else { - static CHAIN: Lazy>> = - Lazy::new(Default::default); - } - } + // cfg_if::cfg_if! { + // if #[cfg(all(windows, feature = "iocp"))] { + // static CHAIN: Lazy< + // RecvSyscallFacade>> + // > = Lazy::new(Default::default); + // } else { + // static CHAIN: Lazy>> = + // Lazy::new(Default::default); + // } + // } + static CHAIN: Lazy>> = + Lazy::new(Default::default); CHAIN.recv(fn_ptr, fd, buf, len, flags) } diff --git a/core/src/syscall/windows/send.rs b/core/src/syscall/windows/send.rs index 16d7af4f..ba5a1d47 100644 --- a/core/src/syscall/windows/send.rs +++ b/core/src/syscall/windows/send.rs @@ -11,16 +11,18 @@ pub extern "system" fn send( len: c_int, flags: SEND_RECV_FLAGS, ) -> c_int { - cfg_if::cfg_if! { - if #[cfg(all(windows, feature = "iocp"))] { - static CHAIN: Lazy< - SendSyscallFacade>> - > = Lazy::new(Default::default); - } else { - static CHAIN: Lazy>> = - Lazy::new(Default::default); - } - } + // cfg_if::cfg_if! { + // if #[cfg(all(windows, feature = "iocp"))] { + // static CHAIN: Lazy< + // SendSyscallFacade>> + // > = Lazy::new(Default::default); + // } else { + // static CHAIN: Lazy>> = + // Lazy::new(Default::default); + // } + // } + static CHAIN: Lazy>> = + Lazy::new(Default::default); CHAIN.send(fn_ptr, fd, buf, len, flags) } diff --git a/hook/src/syscall/windows.rs b/hook/src/syscall/windows.rs index 50666697..224da9b3 100644 --- a/hook/src/syscall/windows.rs +++ b/hook/src/syscall/windows.rs @@ -143,7 +143,6 @@ unsafe fn attach() -> std::io::Result<()> { nfds: c_uint, timeout: c_int ) -> c_int); - #[cfg(not(feature = "iocp"))] impl_hook!("kernel32.dll", SLEEP, Sleep(dw_milliseconds: u32) -> ()); impl_hook!("kernel32.dll", CREATEFILEW, CreateFileW( lpfilename: PCWSTR, @@ -160,18 +159,13 @@ unsafe fn attach() -> std::io::Result<()> { lpnewfilepointer : *mut c_longlong, dwmovemethod : SET_FILE_POINTER_MOVE_METHOD ) -> BOOL); - // NOTE: unhook WaitOnAddress/connect due to stack overflow or bug + // NOTE: unhook WaitOnAddress due to stack overflow or bug // impl_hook!("api-ms-win-core-synch-l1-2-0.dll", WAITONADDRESS, WaitOnAddress( // address: *const c_void, // compareaddress: *const c_void, // addresssize: usize, // dwmilliseconds: c_uint // ) -> BOOL); - // impl_hook!("ws2_32.dll", CONNECT, connect( - // fd: SOCKET, - // address: *const SOCKADDR, - // len: c_int - // ) -> c_int); // Enable the hook minhook::MinHook::enable_all_hooks() .map_err(|_| Error::new(ErrorKind::Other, "init all hooks failed !")) From 193c73baf2a09f021dd3f19a9b1dcb3a8e7f3559 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Fri, 15 Nov 2024 17:46:41 +0800 Subject: [PATCH 36/42] test accept IOCP --- core/src/net/operator/windows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows.rs index 0c9b20e0..b1bacea3 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows.rs @@ -3,7 +3,7 @@ use crate::common::{get_timeout_time, now}; use crate::impl_display_by_debug; use dashmap::{DashMap, DashSet}; use once_cell::sync::Lazy; -use std::ffi::{c_int, c_uint}; +use std::ffi::{c_int, c_uint, c_void}; use std::io::{Error, ErrorKind}; use std::marker::PhantomData; use std::sync::atomic::{AtomicBool, Ordering}; From d9f2e41541eee298e900c752e582de66eab8f40c Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Fri, 15 Nov 2024 17:52:35 +0800 Subject: [PATCH 37/42] test accept IOCP --- core/src/syscall/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/syscall/mod.rs b/core/src/syscall/mod.rs index 81ab16c8..f38f5e01 100644 --- a/core/src/syscall/mod.rs +++ b/core/src/syscall/mod.rs @@ -9,6 +9,6 @@ mod unix; #[cfg(windows)] pub use windows::*; -#[allow(non_snake_case)] +#[allow(non_snake_case, dead_code)] #[cfg(windows)] mod windows; From 04e996e33a07553df81f098591f03d3c94ef74c6 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Fri, 15 Nov 2024 18:19:03 +0800 Subject: [PATCH 38/42] test WSARecv/WSASend IOCP --- core/src/syscall/windows/WSARecv.rs | 22 ++++++++++------------ core/src/syscall/windows/WSASend.rs | 22 ++++++++++------------ core/src/syscall/windows/accept.rs | 22 ++++++++++++---------- 3 files changed, 32 insertions(+), 34 deletions(-) diff --git a/core/src/syscall/windows/WSARecv.rs b/core/src/syscall/windows/WSARecv.rs index 3ab8e89c..9df06b71 100644 --- a/core/src/syscall/windows/WSARecv.rs +++ b/core/src/syscall/windows/WSARecv.rs @@ -27,18 +27,16 @@ pub extern "system" fn WSARecv( lpoverlapped: *mut OVERLAPPED, lpcompletionroutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, ) -> c_int { - // cfg_if::cfg_if! { - // if #[cfg(all(windows, feature = "iocp"))] { - // static CHAIN: Lazy< - // WSARecvSyscallFacade>> - // > = Lazy::new(Default::default); - // } else { - // static CHAIN: Lazy>> = - // Lazy::new(Default::default); - // } - // } - static CHAIN: Lazy>> = - Lazy::new(Default::default); + cfg_if::cfg_if! { + if #[cfg(all(windows, feature = "iocp"))] { + static CHAIN: Lazy< + WSARecvSyscallFacade>> + > = Lazy::new(Default::default); + } else { + static CHAIN: Lazy>> = + Lazy::new(Default::default); + } + } CHAIN.WSARecv( fn_ptr, fd, diff --git a/core/src/syscall/windows/WSASend.rs b/core/src/syscall/windows/WSASend.rs index 0b5134d9..8e1f763f 100644 --- a/core/src/syscall/windows/WSASend.rs +++ b/core/src/syscall/windows/WSASend.rs @@ -27,18 +27,16 @@ pub extern "system" fn WSASend( lpoverlapped: *mut OVERLAPPED, lpcompletionroutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, ) -> c_int { - // cfg_if::cfg_if! { - // if #[cfg(all(windows, feature = "iocp"))] { - // static CHAIN: Lazy< - // WSASendSyscallFacade>> - // > = Lazy::new(Default::default); - // } else { - // static CHAIN: Lazy>> = - // Lazy::new(Default::default); - // } - // } - static CHAIN: Lazy>> = - Lazy::new(Default::default); + cfg_if::cfg_if! { + if #[cfg(all(windows, feature = "iocp"))] { + static CHAIN: Lazy< + WSASendSyscallFacade>> + > = Lazy::new(Default::default); + } else { + static CHAIN: Lazy>> = + Lazy::new(Default::default); + } + } CHAIN.WSASend( fn_ptr, fd, diff --git a/core/src/syscall/windows/accept.rs b/core/src/syscall/windows/accept.rs index f70f13e2..92ae4166 100644 --- a/core/src/syscall/windows/accept.rs +++ b/core/src/syscall/windows/accept.rs @@ -9,16 +9,18 @@ pub extern "system" fn accept( address: *mut SOCKADDR, address_len: *mut c_int, ) -> SOCKET { - cfg_if::cfg_if! { - if #[cfg(feature = "iocp")] { - static CHAIN: Lazy< - AcceptSyscallFacade>> - > = Lazy::new(Default::default); - } else { - 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); + // } + // } + static CHAIN: Lazy>> = + Lazy::new(Default::default); CHAIN.accept(fn_ptr, fd, address, address_len) } From 19c84534e44cf62f501080213a8fc699c5e8e297 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Fri, 15 Nov 2024 18:25:25 +0800 Subject: [PATCH 39/42] test send IOCP --- core/src/syscall/windows/WSARecv.rs | 22 ++++++++++++---------- core/src/syscall/windows/WSASend.rs | 22 ++++++++++++---------- core/src/syscall/windows/send.rs | 22 ++++++++++------------ 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/core/src/syscall/windows/WSARecv.rs b/core/src/syscall/windows/WSARecv.rs index 9df06b71..3ab8e89c 100644 --- a/core/src/syscall/windows/WSARecv.rs +++ b/core/src/syscall/windows/WSARecv.rs @@ -27,16 +27,18 @@ pub extern "system" fn WSARecv( lpoverlapped: *mut OVERLAPPED, lpcompletionroutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, ) -> c_int { - cfg_if::cfg_if! { - if #[cfg(all(windows, feature = "iocp"))] { - static CHAIN: Lazy< - WSARecvSyscallFacade>> - > = Lazy::new(Default::default); - } else { - static CHAIN: Lazy>> = - Lazy::new(Default::default); - } - } + // cfg_if::cfg_if! { + // if #[cfg(all(windows, feature = "iocp"))] { + // static CHAIN: Lazy< + // WSARecvSyscallFacade>> + // > = Lazy::new(Default::default); + // } else { + // static CHAIN: Lazy>> = + // Lazy::new(Default::default); + // } + // } + static CHAIN: Lazy>> = + Lazy::new(Default::default); CHAIN.WSARecv( fn_ptr, fd, diff --git a/core/src/syscall/windows/WSASend.rs b/core/src/syscall/windows/WSASend.rs index 8e1f763f..0b5134d9 100644 --- a/core/src/syscall/windows/WSASend.rs +++ b/core/src/syscall/windows/WSASend.rs @@ -27,16 +27,18 @@ pub extern "system" fn WSASend( lpoverlapped: *mut OVERLAPPED, lpcompletionroutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, ) -> c_int { - cfg_if::cfg_if! { - if #[cfg(all(windows, feature = "iocp"))] { - static CHAIN: Lazy< - WSASendSyscallFacade>> - > = Lazy::new(Default::default); - } else { - static CHAIN: Lazy>> = - Lazy::new(Default::default); - } - } + // cfg_if::cfg_if! { + // if #[cfg(all(windows, feature = "iocp"))] { + // static CHAIN: Lazy< + // WSASendSyscallFacade>> + // > = Lazy::new(Default::default); + // } else { + // static CHAIN: Lazy>> = + // Lazy::new(Default::default); + // } + // } + static CHAIN: Lazy>> = + Lazy::new(Default::default); CHAIN.WSASend( fn_ptr, fd, diff --git a/core/src/syscall/windows/send.rs b/core/src/syscall/windows/send.rs index ba5a1d47..16d7af4f 100644 --- a/core/src/syscall/windows/send.rs +++ b/core/src/syscall/windows/send.rs @@ -11,18 +11,16 @@ pub extern "system" fn send( len: c_int, flags: SEND_RECV_FLAGS, ) -> c_int { - // cfg_if::cfg_if! { - // if #[cfg(all(windows, feature = "iocp"))] { - // static CHAIN: Lazy< - // SendSyscallFacade>> - // > = Lazy::new(Default::default); - // } else { - // static CHAIN: Lazy>> = - // Lazy::new(Default::default); - // } - // } - static CHAIN: Lazy>> = - Lazy::new(Default::default); + cfg_if::cfg_if! { + if #[cfg(all(windows, feature = "iocp"))] { + static CHAIN: Lazy< + SendSyscallFacade>> + > = Lazy::new(Default::default); + } else { + static CHAIN: Lazy>> = + Lazy::new(Default::default); + } + } CHAIN.send(fn_ptr, fd, buf, len, flags) } From aaaf15ef8b7f76ea210beadbe27b4ece06a973d7 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Fri, 15 Nov 2024 18:37:00 +0800 Subject: [PATCH 40/42] test send IOCP --- hook/src/syscall/windows.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/hook/src/syscall/windows.rs b/hook/src/syscall/windows.rs index 224da9b3..b5226941 100644 --- a/hook/src/syscall/windows.rs +++ b/hook/src/syscall/windows.rs @@ -143,6 +143,7 @@ unsafe fn attach() -> std::io::Result<()> { nfds: c_uint, timeout: c_int ) -> c_int); + #[cfg(not(feature = "iocp"))] impl_hook!("kernel32.dll", SLEEP, Sleep(dw_milliseconds: u32) -> ()); impl_hook!("kernel32.dll", CREATEFILEW, CreateFileW( lpfilename: PCWSTR, From 11d96b76f5a8fc2feb3202489b9ed05e5133dacb Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Fri, 15 Nov 2024 20:50:49 +0800 Subject: [PATCH 41/42] test send IOCP --- .../operator/{windows.rs => windows/mod.rs} | 3 + core/src/net/operator/windows/tests.rs | 174 ++++++++++++++++++ 2 files changed, 177 insertions(+) rename core/src/net/operator/{windows.rs => windows/mod.rs} (99%) create mode 100644 core/src/net/operator/windows/tests.rs diff --git a/core/src/net/operator/windows.rs b/core/src/net/operator/windows/mod.rs similarity index 99% rename from core/src/net/operator/windows.rs rename to core/src/net/operator/windows/mod.rs index b1bacea3..6d1adea6 100644 --- a/core/src/net/operator/windows.rs +++ b/core/src/net/operator/windows/mod.rs @@ -19,6 +19,9 @@ use windows_sys::Win32::System::IO::{ CreateIoCompletionPort, GetQueuedCompletionStatusEx, OVERLAPPED, OVERLAPPED_ENTRY, }; +#[cfg(test)] +mod tests; + #[repr(C)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub(crate) struct SocketContext { diff --git a/core/src/net/operator/windows/tests.rs b/core/src/net/operator/windows/tests.rs new file mode 100644 index 00000000..b8feabf3 --- /dev/null +++ b/core/src/net/operator/windows/tests.rs @@ -0,0 +1,174 @@ +use crate::net::operator::Operator; +use slab::Slab; +use std::io::{BufRead, BufReader, Write}; +use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener, TcpStream}; +use std::os::windows::io::AsRawSocket; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; +use std::time::Duration; +use windows_sys::Win32::Networking::WinSock::{closesocket, SOCKET}; + +#[derive(Clone, Debug)] +enum Token { + Accept, + Read { + fd: SOCKET, + buf_index: usize, + }, + Write { + fd: SOCKET, + buf_index: usize, + offset: usize, + len: usize, + }, +} + +fn crate_client(port: u16, server_started: Arc) { + //等服务端起来 + while !server_started.load(Ordering::Acquire) {} + let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port); + let mut stream = TcpStream::connect_timeout(&socket, Duration::from_secs(3)) + .unwrap_or_else(|_| panic!("connect to 127.0.0.1:{port} failed !")); + let mut data: [u8; 512] = [b'1'; 512]; + data[511] = b'\n'; + let mut buffer: Vec = Vec::with_capacity(512); + for _ in 0..3 { + //写入stream流,如果写入失败,提示"写入失败" + assert_eq!(512, stream.write(&data).expect("Failed to write!")); + print!("Client Send: {}", String::from_utf8_lossy(&data[..])); + + let mut reader = BufReader::new(&stream); + //一直读到换行为止(b'\n'中的b表示字节),读到buffer里面 + assert_eq!( + 512, + reader + .read_until(b'\n', &mut buffer) + .expect("Failed to read into buffer") + ); + print!("Client Received: {}", String::from_utf8_lossy(&buffer[..])); + assert_eq!(&data, &buffer as &[u8]); + buffer.clear(); + } + //发送终止符 + assert_eq!(1, stream.write(&[b'e']).expect("Failed to write!")); + println!("client closed"); +} + +fn crate_server2(port: u16, server_started: Arc) -> anyhow::Result<()> { + let operator = Operator::new(0)?; + let listener = TcpListener::bind(("127.0.0.1", port))?; + + let mut bufpool = Vec::with_capacity(64); + let mut buf_alloc = Slab::with_capacity(64); + let mut token_alloc = Slab::with_capacity(64); + + println!("listen {}", listener.local_addr()?); + server_started.store(true, Ordering::Release); + + operator.accept( + token_alloc.insert(Token::Accept), + listener.as_raw_socket() as _, + std::ptr::null_mut(), + std::ptr::null_mut(), + )?; + + loop { + let (_, mut cq, _) = operator.select(None, 1)?; + for cqe in &mut cq { + let token_index = cqe.token; + let token = &mut token_alloc[token_index]; + match token.clone() { + Token::Accept => { + println!("accept"); + let fd = cqe.socket; + let (buf_index, buf) = match bufpool.pop() { + Some(buf_index) => (buf_index, &mut buf_alloc[buf_index]), + None => { + let buf = vec![0u8; 2048].into_boxed_slice(); + let buf_entry = buf_alloc.vacant_entry(); + let buf_index = buf_entry.key(); + (buf_index, buf_entry.insert(buf)) + } + }; + *token = Token::Read { fd, buf_index }; + operator.recv(token_index, fd, buf.as_mut_ptr() as _, buf.len() as _, 0)?; + } + Token::Read { fd, buf_index } => { + let ret = cqe.bytes_transferred as _; + if ret == 0 { + bufpool.push(buf_index); + _ = token_alloc.remove(token_index); + println!("shutdown connection"); + _ = unsafe { closesocket(fd) }; + println!("Server closed"); + return Ok(()); + } else { + let len = ret; + let buf = &buf_alloc[buf_index]; + *token = Token::Write { + fd, + buf_index, + len, + offset: 0, + }; + operator.send(token_index, fd, buf.as_ptr() as _, len as _, 0)?; + } + } + Token::Write { + fd, + buf_index, + offset, + len, + } => { + let write_len = cqe.bytes_transferred as usize; + if offset + write_len >= len { + bufpool.push(buf_index); + let (buf_index, buf) = match bufpool.pop() { + Some(buf_index) => (buf_index, &mut buf_alloc[buf_index]), + None => { + let buf = vec![0u8; 2048].into_boxed_slice(); + let buf_entry = buf_alloc.vacant_entry(); + let buf_index = buf_entry.key(); + (buf_index, buf_entry.insert(buf)) + } + }; + *token = Token::Read { fd, buf_index }; + operator.recv(token_index, fd, buf.as_mut_ptr() as _, buf.len() as _, 0)?; + } else { + let offset = offset + write_len; + let len = len - offset; + let buf = &buf_alloc[buf_index][offset..]; + *token = Token::Write { + fd, + buf_index, + offset, + len, + }; + operator.write(token_index, fd as _, buf.as_ptr() as _, len as _)?; + }; + } + } + } + } +} + +#[test] +fn framework() -> anyhow::Result<()> { + #[cfg(feature = "log")] + let _ = tracing_subscriber::fmt() + .with_thread_names(true) + .with_line_number(true) + .with_timer(tracing_subscriber::fmt::time::OffsetTime::new( + time::UtcOffset::from_hms(8, 0, 0).expect("create UtcOffset failed !"), + time::format_description::well_known::Rfc2822, + )) + .try_init(); + let port = 7061; + let server_started = Arc::new(AtomicBool::new(false)); + let clone = server_started.clone(); + let handle = std::thread::spawn(move || crate_server2(port, clone)); + std::thread::spawn(move || crate_client(port, server_started)) + .join() + .expect("client has error"); + handle.join().expect("server has error") +} From 7af988e40140eefc5dfe15b4b20159d3f11adb27 Mon Sep 17 00:00:00 2001 From: dragon-zhang Date: Mon, 6 Jan 2025 18:27:16 +0800 Subject: [PATCH 42/42] try IOCP --- core/src/net/operator/windows/mod.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/src/net/operator/windows/mod.rs b/core/src/net/operator/windows/mod.rs index 6d1adea6..4952e626 100644 --- a/core/src/net/operator/windows/mod.rs +++ b/core/src/net/operator/windows/mod.rs @@ -103,6 +103,15 @@ impl<'o> Operator<'o> { )); } debug_assert_eq!(ret, self.iocp); + if unsafe { + windows_sys::Win32::Storage::FileSystem::SetFileCompletionNotificationModes( + handle, + windows_sys::Win32::System::WindowsProgramming::FILE_SKIP_SET_EVENT_ON_HANDLE as u8, + ) + } == 0 + { + return Err(Error::last_os_error()); + } Ok(()) }