Feat: Further refinemets

This commit is contained in:
Gursukh 2026-04-04 14:29:29 +01:00
parent e763e90c2a
commit c576aefa9f
3 changed files with 94 additions and 15 deletions

View File

@ -727,13 +727,13 @@ int PS4_SYSV_ABI sceNetEpollControl(OrbisNetId epollid, OrbisNetEpollFlag op, Or
} }
// P2P dgram sockets only support EPOLLIN (matches PS4 kernel behavior) // 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) { if (file->socket->socket_type == ORBIS_NET_SOCK_DGRAM_P2P) {
epoll_events_mod &= ORBIS_NET_EPOLLIN; epoll_events &= ORBIS_NET_EPOLLIN;
} }
#ifndef __FreeBSD__ #ifndef __FreeBSD__
epoll_event native_event = {.events = ConvertEpollEventsIn(epoll_events_mod), epoll_event native_event = {.events = ConvertEpollEventsIn(epoll_events),
.data = {.fd = id}}; .data = {.fd = id}};
ASSERT(epoll_ctl(epoll->epoll_fd, EPOLL_CTL_MOD, *native_handle, &native_event) == 0); ASSERT(epoll_ctl(epoll->epoll_fd, EPOLL_CTL_MOD, *native_handle, &native_event) == 0);
#endif #endif
@ -893,6 +893,9 @@ int PS4_SYSV_ABI sceNetEpollWait(OrbisNetId epollid, OrbisNetEpollEvent* events,
LOG_TRACE(Lib_Net, "timed out"); LOG_TRACE(Lib_Net, "timed out");
} else { } else {
for (int j = 0; j < result; ++j) { for (int j = 0; j < result; ++j) {
if (i >= maxevents) {
break;
}
const auto& current_event = native_events[j]; const auto& current_event = native_events[j];
// Skip the abort fd event (registered with data.fd = -1) // Skip the abort fd event (registered with data.fd = -1)
if (current_event.data.fd == -1) { if (current_event.data.fd == -1) {
@ -1734,8 +1737,7 @@ int PS4_SYSV_ABI sceNetSysctl() {
} }
int PS4_SYSV_ABI sceNetTerm() { int PS4_SYSV_ABI sceNetTerm() {
LOG_DEBUG(Lib_Net, "called"); LOG_ERROR(Lib_Net, "(STUBBED) called");
g_isNetInitialized = false;
return ORBIS_OK; return ORBIS_OK;
} }

View File

@ -6,8 +6,13 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/types.h" #include "common/types.h"
#include "net_epoll.h" #include "net_epoll.h"
#ifdef __linux__ #ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#elif defined(__linux__)
#include <sys/eventfd.h> #include <sys/eventfd.h>
#else
#include <fcntl.h>
#endif #endif
namespace Libraries::Net { namespace Libraries::Net {
@ -54,30 +59,85 @@ Epoll::Epoll(const char* name_) : name(name_ ? name_ : "anon"), epoll_fd(epoll_c
#else #else
ASSERT(epoll_fd != -1); ASSERT(epoll_fd != -1);
#endif #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<sockaddr*>(&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<sockaddr*>(&addr), &addrlen) == 0);
ASSERT(::connect(abort_sock, reinterpret_cast<sockaddr*>(&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); abort_fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
ASSERT(abort_fd != -1); ASSERT(abort_fd != -1);
epoll_event ev = {.events = EPOLLIN, .data = {.fd = -1}}; epoll_event ev = {.events = EPOLLIN, .data = {.fd = -1}};
ASSERT(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, abort_fd, &ev) == 0); 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 #endif
} }
void Epoll::Abort() { void Epoll::Abort() {
aborted.store(true, std::memory_order_release); 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) { if (abort_fd != -1) {
uint64_t val = 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 #endif
} }
void Epoll::ClearAbort() { void Epoll::ClearAbort() {
aborted.store(false, std::memory_order_release); 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) { if (abort_fd != -1) {
uint64_t val; 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 #endif
} }
@ -85,17 +145,29 @@ void Epoll::ClearAbort() {
void Epoll::Destroy() noexcept { void Epoll::Destroy() noexcept {
events.clear(); events.clear();
#ifdef _WIN32 #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_close(epoll_fd);
epoll_fd = nullptr; epoll_fd = nullptr;
#else #else
close(epoll_fd);
epoll_fd = -1;
#ifdef __linux__ #ifdef __linux__
if (abort_fd != -1) { if (abort_fd != -1) {
close(abort_fd); close(abort_fd);
abort_fd = -1; 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 #endif
close(epoll_fd);
epoll_fd = -1;
#endif #endif
name = ""; name = "";
destroyed = true; destroyed = true;

View File

@ -16,6 +16,7 @@
#include <wepoll.h> #include <wepoll.h>
#endif #endif
// TODO: FreeBSD requires libepoll-shim for epoll support
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
#include <sys/epoll.h> #include <sys/epoll.h>
#include <unistd.h> #include <unistd.h>
@ -35,8 +36,12 @@ struct Epoll {
epoll_handle epoll_fd; epoll_handle epoll_fd;
std::deque<u32> async_resolutions{}; std::deque<u32> async_resolutions{};
std::atomic<bool> aborted{false}; std::atomic<bool> aborted{false};
#ifdef __linux__ #ifdef _WIN32
int abort_fd = -1; 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 #endif
explicit Epoll(const char* name_); explicit Epoll(const char* name_);