From c576aefa9fb5d172b33fd5b6d9b5b2e4668831d6 Mon Sep 17 00:00:00 2001 From: Gursukh Date: Sat, 4 Apr 2026 14:29:29 +0100 Subject: [PATCH] Feat: Further refinemets --- src/core/libraries/network/net.cpp | 12 ++-- src/core/libraries/network/net_epoll.cpp | 88 +++++++++++++++++++++--- src/core/libraries/network/net_epoll.h | 9 ++- 3 files changed, 94 insertions(+), 15 deletions(-) diff --git a/src/core/libraries/network/net.cpp b/src/core/libraries/network/net.cpp index 76f67841d..d4e09505e 100644 --- a/src/core/libraries/network/net.cpp +++ b/src/core/libraries/network/net.cpp @@ -727,13 +727,13 @@ int PS4_SYSV_ABI sceNetEpollControl(OrbisNetId epollid, OrbisNetEpollFlag op, Or } // P2P dgram sockets only support EPOLLIN (matches PS4 kernel behavior) - auto epoll_events_mod = event->events; + auto epoll_events = event->events; if (file->socket->socket_type == ORBIS_NET_SOCK_DGRAM_P2P) { - epoll_events_mod &= ORBIS_NET_EPOLLIN; + epoll_events &= ORBIS_NET_EPOLLIN; } #ifndef __FreeBSD__ - epoll_event native_event = {.events = ConvertEpollEventsIn(epoll_events_mod), + epoll_event native_event = {.events = ConvertEpollEventsIn(epoll_events), .data = {.fd = id}}; ASSERT(epoll_ctl(epoll->epoll_fd, EPOLL_CTL_MOD, *native_handle, &native_event) == 0); #endif @@ -893,6 +893,9 @@ int PS4_SYSV_ABI sceNetEpollWait(OrbisNetId epollid, OrbisNetEpollEvent* events, LOG_TRACE(Lib_Net, "timed out"); } else { for (int j = 0; j < result; ++j) { + if (i >= maxevents) { + break; + } const auto& current_event = native_events[j]; // Skip the abort fd event (registered with data.fd = -1) if (current_event.data.fd == -1) { @@ -1734,8 +1737,7 @@ int PS4_SYSV_ABI sceNetSysctl() { } int PS4_SYSV_ABI sceNetTerm() { - LOG_DEBUG(Lib_Net, "called"); - g_isNetInitialized = false; + LOG_ERROR(Lib_Net, "(STUBBED) called"); return ORBIS_OK; } diff --git a/src/core/libraries/network/net_epoll.cpp b/src/core/libraries/network/net_epoll.cpp index 189b5bc72..de9ad121a 100644 --- a/src/core/libraries/network/net_epoll.cpp +++ b/src/core/libraries/network/net_epoll.cpp @@ -6,8 +6,13 @@ #include "common/logging/log.h" #include "common/types.h" #include "net_epoll.h" -#ifdef __linux__ +#ifdef _WIN32 +#include +#include +#elif defined(__linux__) #include +#else +#include #endif namespace Libraries::Net { @@ -54,30 +59,85 @@ Epoll::Epoll(const char* name_) : name(name_ ? name_ : "anon"), epoll_fd(epoll_c #else ASSERT(epoll_fd != -1); #endif -#ifdef __linux__ + + // Set up the abort wake mechanism and register it in epoll with sentinel data.fd = -1. + // Linux: eventfd, macOS/BSD: self-pipe, Windows: loopback UDP socket. +#ifdef _WIN32 + abort_sock = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + ASSERT(abort_sock != INVALID_SOCKET); + sockaddr_in addr{}; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr.sin_port = 0; // OS picks an ephemeral port + ASSERT(::bind(abort_sock, reinterpret_cast(&addr), sizeof(addr)) == 0); + // Connect to self so we can use send() in Abort() + socklen_t addrlen = sizeof(addr); + ASSERT(::getsockname(abort_sock, reinterpret_cast(&addr), &addrlen) == 0); + ASSERT(::connect(abort_sock, reinterpret_cast(&addr), sizeof(addr)) == 0); + u_long nonblocking = 1; + ASSERT(::ioctlsocket(abort_sock, FIONBIO, &nonblocking) == 0); + epoll_event ev = {.events = EPOLLIN, .data = {.fd = -1}}; + ASSERT(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, abort_sock, &ev) == 0); +#elif defined(__linux__) abort_fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); ASSERT(abort_fd != -1); epoll_event ev = {.events = EPOLLIN, .data = {.fd = -1}}; ASSERT(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, abort_fd, &ev) == 0); +#else + // Self-pipe for macOS/BSD + int r = ::pipe(abort_pipe); + ASSERT(r == 0); + // Set both ends non-blocking + for (int i = 0; i < 2; ++i) { + int flags = ::fcntl(abort_pipe[i], F_GETFL); + ::fcntl(abort_pipe[i], F_SETFL, flags | O_NONBLOCK); + ::fcntl(abort_pipe[i], F_SETFD, FD_CLOEXEC); + } + epoll_event ev = {.events = EPOLLIN, .data = {.fd = -1}}; + ASSERT(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, abort_pipe[0], &ev) == 0); #endif } void Epoll::Abort() { aborted.store(true, std::memory_order_release); -#ifdef __linux__ +#ifdef _WIN32 + if (abort_sock != INVALID_SOCKET) { + char byte = 1; + (void)::send(abort_sock, &byte, 1, 0); + } +#elif defined(__linux__) if (abort_fd != -1) { uint64_t val = 1; - ::write(abort_fd, &val, sizeof(val)); + (void)::write(abort_fd, &val, sizeof(val)); + } +#else + if (abort_pipe[1] != -1) { + char byte = 1; + (void)::write(abort_pipe[1], &byte, 1); } #endif } void Epoll::ClearAbort() { aborted.store(false, std::memory_order_release); -#ifdef __linux__ +#ifdef _WIN32 + if (abort_sock != INVALID_SOCKET) { + char buf[64]; + // Drain any pending data + while (::recv(abort_sock, buf, sizeof(buf), 0) > 0) { + } + } +#elif defined(__linux__) if (abort_fd != -1) { uint64_t val; - ::read(abort_fd, &val, sizeof(val)); + (void)::read(abort_fd, &val, sizeof(val)); + } +#else + if (abort_pipe[0] != -1) { + char buf[64]; + // Drain the pipe + while (::read(abort_pipe[0], buf, sizeof(buf)) > 0) { + } } #endif } @@ -85,17 +145,29 @@ void Epoll::ClearAbort() { void Epoll::Destroy() noexcept { events.clear(); #ifdef _WIN32 + if (abort_sock != INVALID_SOCKET) { + epoll_ctl(epoll_fd, EPOLL_CTL_DEL, abort_sock, nullptr); + ::closesocket(abort_sock); + abort_sock = INVALID_SOCKET; + } epoll_close(epoll_fd); epoll_fd = nullptr; #else - close(epoll_fd); - epoll_fd = -1; #ifdef __linux__ if (abort_fd != -1) { close(abort_fd); abort_fd = -1; } +#else + for (int i = 0; i < 2; ++i) { + if (abort_pipe[i] != -1) { + close(abort_pipe[i]); + abort_pipe[i] = -1; + } + } #endif + close(epoll_fd); + epoll_fd = -1; #endif name = ""; destroyed = true; diff --git a/src/core/libraries/network/net_epoll.h b/src/core/libraries/network/net_epoll.h index aa5801195..bccb4ba25 100644 --- a/src/core/libraries/network/net_epoll.h +++ b/src/core/libraries/network/net_epoll.h @@ -16,6 +16,7 @@ #include #endif +// TODO: FreeBSD requires libepoll-shim for epoll support #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) #include #include @@ -35,8 +36,12 @@ struct Epoll { epoll_handle epoll_fd; std::deque async_resolutions{}; std::atomic aborted{false}; -#ifdef __linux__ - int abort_fd = -1; +#ifdef _WIN32 + SOCKET abort_sock = INVALID_SOCKET; // loopback UDP socket for abort wake +#elif defined(__linux__) + int abort_fd = -1; // eventfd for abort wake +#else + int abort_pipe[2] = {-1, -1}; // self-pipe for abort wake (macOS/BSD) #endif explicit Epoll(const char* name_);