fix(libSceNet): sceNetEpollWait takes 2 as the OUT event

sceNetEpollWait used Linux's EPOLLOUT bit (4) for writability. The SCE
value is 2 (shadPS4 net_types.h ORBIS_NET_EPOLLOUT, KytyPS5 network.cpp
EPOLL_OUT, SharpProspero Socket.cs EpollOut); IN (1), ERR (8) and HUP
(0x10) already match. A socket registered for OUT was never polled for
writability, so the wait ran out its timeout or blocked forever, and an
IN|OUT registration never reported OUT.
This commit is contained in:
Yunus Shaikh 2026-10-12 14:54:51 +00:00
parent 2a5eca11cd
commit b19a74f5bf
2 changed files with 37 additions and 4 deletions

View File

@ -1071,14 +1071,14 @@ int APS5_VABI sceNetEpollWait(int eid, NetEpollEvent* events, int maxevents, int
for (std::size_t index = 0; index < descriptors.size(); ++index) {
descriptors[index].fd = native_sockets[index]->value;
if (registered_events[index].events & 1) descriptors[index].events |= POLLRDNORM;
if (registered_events[index].events & 4) descriptors[index].events |= POLLWRNORM;
if (registered_events[index].events & 2) descriptors[index].events |= POLLWRNORM;
}
#else
std::vector<pollfd> descriptors(registered_events.size());
for (std::size_t index = 0; index < descriptors.size(); ++index) {
descriptors[index].fd = native_sockets[index]->value;
if (registered_events[index].events & 1) descriptors[index].events |= POLLIN;
if (registered_events[index].events & 4) descriptors[index].events |= POLLOUT;
if (registered_events[index].events & 2) descriptors[index].events |= POLLOUT;
}
#endif
const auto now = std::chrono::steady_clock::now();
@ -1108,10 +1108,10 @@ int APS5_VABI sceNetEpollWait(int eid, NetEpollEvent* events, int maxevents, int
std::uint32_t guest_events = 0;
#ifdef _WIN32
if (native_events & (POLLRDNORM | POLLPRI)) guest_events |= 1;
if (native_events & POLLWRNORM) guest_events |= 4;
if (native_events & POLLWRNORM) guest_events |= 2;
#else
if (native_events & (POLLIN | POLLPRI)) guest_events |= 1;
if (native_events & POLLOUT) guest_events |= 4;
if (native_events & POLLOUT) guest_events |= 2;
#endif
if (native_events & POLLERR) guest_events |= 8;
if (native_events & POLLHUP) guest_events |= 16;

View File

@ -149,6 +149,38 @@ static void CheckEmptyEpoll() {
}
}
static void CheckEpollWritable() {
std::array<std::uint8_t, 16> address{16, 2, 0, 0, 127, 0, 0, 1};
const int receiver = sceNetSocket("epoll-receiver", 2, 2, 17);
const int sender = sceNetSocket("epoll-sender", 2, 2, 17);
Require(receiver >= 0 && sender >= 0);
Require(sceNetBind_nid_postfix(receiver, address.data(), address.size()) == 0);
std::uint32_t size = address.size();
Require(sceNetGetsockname(receiver, address.data(), &size) == 0 && size == address.size());
const int epoll = sceNetEpollCreate("epoll-writable", 0);
Require(epoll >= 0);
NetEpollEvent registration{};
registration.events = 2;
registration.ident = static_cast<std::uint64_t>(sender);
registration.data.u32 = 41;
Require(sceNetEpollControl(epoll, 1, sender, &registration) == 0);
NetEpollEvent ready{};
Require(sceNetEpollWait(epoll, &ready, 1, 1000000) == 1);
Require(ready.events == 2 && ready.ident == static_cast<std::uint64_t>(sender) && ready.data.u32 == 41);
Require(sceNetEpollControl(epoll, 3, sender, nullptr) == 0);
const char payload[] = "epoll";
char peeked[sizeof(payload)]{};
Require(sceNetSendto(sender, payload, sizeof(payload), 0, address.data(), address.size()) == sizeof(payload));
Require(sceNetRecv(receiver, peeked, sizeof(peeked), 2) == sizeof(payload));
registration.events = 3;
registration.ident = static_cast<std::uint64_t>(receiver);
Require(sceNetEpollControl(epoll, 1, receiver, &registration) == 0);
Require(sceNetEpollWait(epoll, &ready, 1, 1000000) == 1);
Require(ready.events == 3 && ready.ident == static_cast<std::uint64_t>(receiver) && ready.data.u32 == 41);
Require(sceNetEpollDestroy(epoll) == 0);
Require(sceNetSocketClose(sender) == 0 && sceNetSocketClose(receiver) == 0);
}
static void CheckReceiveTimeout(int receiver, int sender, const std::array<std::uint8_t, 16>& address) {
const int timeout = 50000;
Require(sceNetSetsockopt(receiver, 0xffff, 0x1006, &timeout, sizeof(timeout)) == 0);
@ -353,6 +385,7 @@ int main() {
Require(sceNetInit_nid_postfix() == 0);
CheckPoolStats();
CheckEmptyEpoll();
CheckEpollWritable();
CheckAddressText(2, "127.0.0.1");
CheckAddressText(2, "255.255.255.255");
CheckAddressText(28, "::1");