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)
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;
}

View File

@ -6,8 +6,13 @@
#include "common/logging/log.h"
#include "common/types.h"
#include "net_epoll.h"
#ifdef __linux__
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#elif defined(__linux__)
#include <sys/eventfd.h>
#else
#include <fcntl.h>
#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<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);
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;

View File

@ -16,6 +16,7 @@
#include <wepoll.h>
#endif
// TODO: FreeBSD requires libepoll-shim for epoll support
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
#include <sys/epoll.h>
#include <unistd.h>
@ -35,8 +36,12 @@ struct Epoll {
epoll_handle epoll_fd;
std::deque<u32> async_resolutions{};
std::atomic<bool> 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_);