From bf0dd81051b616712ccbe2ad3579a8f4692fe0ca Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Wed, 14 May 2025 20:23:32 +0300 Subject: [PATCH 1/4] select defination --- src/core/libraries/kernel/kernel.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/core/libraries/kernel/kernel.cpp b/src/core/libraries/kernel/kernel.cpp index c7eafe799..5086ed8b2 100644 --- a/src/core/libraries/kernel/kernel.cpp +++ b/src/core/libraries/kernel/kernel.cpp @@ -227,6 +227,11 @@ int PS4_SYSV_ABI posix_getsockname(Libraries::Net::OrbisNetId s, LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode); return -1; } + +int PS4_SYSV_ABI posix_select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, + const timeval* timeout) { + return 0; +} void RegisterKernel(Core::Loader::SymbolsResolver* sym) { service_thread = std::jthread{KernelServiceThread}; @@ -270,6 +275,7 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) { Libraries::Net::sceNetInetNtop); // TODO fix it to sys_ ... LIB_FUNCTION("4n51s0zEf0c", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sceNetInetPton); // TODO fix it to sys_ ... + LIB_FUNCTION("T8fER+tIGgk", "libScePosix", 1, "libkernel", 1, 1, posix_select); } } // namespace Libraries::Kernel From bc2ed18cc4ae747bbb0386035f6707227641be89 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Wed, 14 May 2025 20:23:32 +0300 Subject: [PATCH 2/4] select defination --- src/core/libraries/kernel/kernel.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/core/libraries/kernel/kernel.cpp b/src/core/libraries/kernel/kernel.cpp index 180850217..7fa9040b3 100644 --- a/src/core/libraries/kernel/kernel.cpp +++ b/src/core/libraries/kernel/kernel.cpp @@ -230,6 +230,11 @@ int PS4_SYSV_ABI posix_getsockname(Libraries::Net::OrbisNetId s, LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode); return -1; } + +int PS4_SYSV_ABI posix_select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, + const timeval* timeout) { + return 0; +} void RegisterKernel(Core::Loader::SymbolsResolver* sym) { service_thread = std::jthread{KernelServiceThread}; @@ -273,6 +278,7 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) { Libraries::Net::sceNetInetNtop); // TODO fix it to sys_ ... LIB_FUNCTION("4n51s0zEf0c", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sceNetInetPton); // TODO fix it to sys_ ... + LIB_FUNCTION("T8fER+tIGgk", "libScePosix", 1, "libkernel", 1, 1, posix_select); } } // namespace Libraries::Kernel From 140db2d9babfc858d120ac2374da806193ed1d0a Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Wed, 4 Jun 2025 23:12:27 +0300 Subject: [PATCH 3/4] select first draft --- src/core/libraries/kernel/kernel.cpp | 76 +++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/src/core/libraries/kernel/kernel.cpp b/src/core/libraries/kernel/kernel.cpp index 7fa9040b3..76ffb2220 100644 --- a/src/core/libraries/kernel/kernel.cpp +++ b/src/core/libraries/kernel/kernel.cpp @@ -28,6 +28,7 @@ #ifdef _WIN64 #include +#include #else #include #endif @@ -231,9 +232,82 @@ int PS4_SYSV_ABI posix_getsockname(Libraries::Net::OrbisNetId s, return -1; } +#ifdef _WIN32 + +int IsSocket(int fd) { + intptr_t handle = _get_osfhandle(fd); + WSANETWORKEVENTS ne; + SOCKET s = (SOCKET)handle; + WSAEnumNetworkEvents(s, NULL, &ne); + return (WSAGetLastError() != WSAENOTSOCK); +} + +int IsPipeOrFile(int fd) { + HANDLE h = (HANDLE)_get_osfhandle(fd); + DWORD t = GetFileType(h); + return (t == FILE_TYPE_PIPE || t == FILE_TYPE_DISK); +} + +#endif + int PS4_SYSV_ABI posix_select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, const timeval* timeout) { - return 0; + // note writefds,exceptfds will not work +#ifdef _WIN32 + fd_set sock_r, sock_w, sock_x; + FD_ZERO(&sock_r); + FD_ZERO(&sock_w); + FD_ZERO(&sock_x); + int fd; + + // Separate socket FDs + for (fd = 0; fd < nfds; ++fd) { + if (readfds && FD_ISSET(fd, readfds) && IsSocket(fd)) { + FD_SET((SOCKET)_get_osfhandle(fd), &sock_r); + } + if (writefds && FD_ISSET(fd, writefds) && IsSocket(fd)) { + FD_SET((SOCKET)_get_osfhandle(fd), &sock_w); + } + if (exceptfds && FD_ISSET(fd, exceptfds) && IsSocket(fd)) { + FD_SET((SOCKET)_get_osfhandle(fd), &sock_x); + } + } + + int result = select(0, &sock_r, &sock_w, &sock_x, timeout); + int total_ready = result; + + // Poll pipes/files for read readiness + for (fd = 0; fd < nfds; ++fd) { + if (readfds && FD_ISSET(fd, readfds) && IsPipeOrFile(fd) && !IsSocket(fd)) { + HANDLE h = (HANDLE)_get_osfhandle(fd); + DWORD avail = 0; + + if (GetFileType(h) == FILE_TYPE_PIPE) { + if (PeekNamedPipe(h, NULL, 0, NULL, &avail, NULL) && avail > 0) { + total_ready++; + } else { + FD_CLR(fd, readfds); + } + } else if (GetFileType(h) == FILE_TYPE_DISK) { + char buf[1]; + long pos = _lseek(fd, 0, SEEK_CUR); + int r = _read(fd, buf, 1); + if (r > 0) { + _lseek(fd, pos, SEEK_SET); + total_ready++; + } else { + FD_CLR(fd, readfds); + } + } + } + } + + return total_ready; + +#else + // POSIX: just use select directly + return select(nfds, readfds, writefds, exceptfds, timeout); +#endif } void RegisterKernel(Core::Loader::SymbolsResolver* sym) { service_thread = std::jthread{KernelServiceThread}; From d1c64ce5579defd9de543a71dc886847015c227d Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Thu, 5 Jun 2025 10:08:42 +0300 Subject: [PATCH 4/4] support for writefds,errorfds --- src/core/libraries/kernel/kernel.cpp | 96 ++++++++++++++++++++-------- 1 file changed, 68 insertions(+), 28 deletions(-) diff --git a/src/core/libraries/kernel/kernel.cpp b/src/core/libraries/kernel/kernel.cpp index 76ffb2220..b9e6d0c51 100644 --- a/src/core/libraries/kernel/kernel.cpp +++ b/src/core/libraries/kernel/kernel.cpp @@ -242,17 +242,10 @@ int IsSocket(int fd) { return (WSAGetLastError() != WSAENOTSOCK); } -int IsPipeOrFile(int fd) { - HANDLE h = (HANDLE)_get_osfhandle(fd); - DWORD t = GetFileType(h); - return (t == FILE_TYPE_PIPE || t == FILE_TYPE_DISK); -} - #endif int PS4_SYSV_ABI posix_select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, - const timeval* timeout) { - // note writefds,exceptfds will not work + timeval* timeout) { #ifdef _WIN32 fd_set sock_r, sock_w, sock_x; FD_ZERO(&sock_r); @@ -260,39 +253,41 @@ int PS4_SYSV_ABI posix_select(int nfds, fd_set* readfds, fd_set* writefds, fd_se FD_ZERO(&sock_x); int fd; - // Separate socket FDs + // Separate sockets for select() for (fd = 0; fd < nfds; ++fd) { - if (readfds && FD_ISSET(fd, readfds) && IsSocket(fd)) { - FD_SET((SOCKET)_get_osfhandle(fd), &sock_r); - } - if (writefds && FD_ISSET(fd, writefds) && IsSocket(fd)) { - FD_SET((SOCKET)_get_osfhandle(fd), &sock_w); - } - if (exceptfds && FD_ISSET(fd, exceptfds) && IsSocket(fd)) { - FD_SET((SOCKET)_get_osfhandle(fd), &sock_x); + if (IsSocket(fd)) { + SOCKET s = (SOCKET)_get_osfhandle(fd); + if (readfds && FD_ISSET(fd, readfds)) + FD_SET(s, &sock_r); + if (writefds && FD_ISSET(fd, writefds)) + FD_SET(s, &sock_w); + if (exceptfds && FD_ISSET(fd, exceptfds)) + FD_SET(s, &sock_x); } } int result = select(0, &sock_r, &sock_w, &sock_x, timeout); int total_ready = result; - // Poll pipes/files for read readiness for (fd = 0; fd < nfds; ++fd) { - if (readfds && FD_ISSET(fd, readfds) && IsPipeOrFile(fd) && !IsSocket(fd)) { - HANDLE h = (HANDLE)_get_osfhandle(fd); - DWORD avail = 0; + HANDLE h = (HANDLE)_get_osfhandle(fd); + DWORD type = GetFileType(h); + if (type == FILE_TYPE_UNKNOWN || IsSocket(fd)) + continue; - if (GetFileType(h) == FILE_TYPE_PIPE) { + // READ check + if (readfds && FD_ISSET(fd, readfds)) { + if (type == FILE_TYPE_PIPE) { + DWORD avail = 0; if (PeekNamedPipe(h, NULL, 0, NULL, &avail, NULL) && avail > 0) { total_ready++; } else { FD_CLR(fd, readfds); } - } else if (GetFileType(h) == FILE_TYPE_DISK) { - char buf[1]; + } else if (type == FILE_TYPE_DISK) { + char tmp; long pos = _lseek(fd, 0, SEEK_CUR); - int r = _read(fd, buf, 1); - if (r > 0) { + if (_read(fd, &tmp, 1) > 0) { _lseek(fd, pos, SEEK_SET); total_ready++; } else { @@ -300,13 +295,58 @@ int PS4_SYSV_ABI posix_select(int nfds, fd_set* readfds, fd_set* writefds, fd_se } } } + + // WRITE check + if (writefds && FD_ISSET(fd, writefds)) { + DWORD written = 0; + char dummy = 0; + BOOL writable = FALSE; + if (type == FILE_TYPE_PIPE) { + // Try writing 0 bytes to check if it's broken + writable = WriteFile(h, &dummy, 0, &written, NULL); + } else if (type == FILE_TYPE_DISK) { + writable = true; // Disk files are always "writable" + } + if (writable) { + total_ready++; + } else { + FD_CLR(fd, writefds); + } + } + + // EXCEPTION check + if (exceptfds && FD_ISSET(fd, exceptfds)) { + DWORD err = 0, size = sizeof(err); + BOOL error_detected = false; + + if (type == FILE_TYPE_PIPE) { + // Check broken pipe by trying non-blocking zero write + DWORD written; + char tmp = 0; + if (!WriteFile(h, &tmp, 0, &written, NULL)) { + DWORD e = GetLastError(); + if (e == ERROR_NO_DATA || e == ERROR_BROKEN_PIPE) { + error_detected = true; + } + } + } + + if (error_detected) { + total_ready++; + } else { + FD_CLR(fd, exceptfds); + } + } } return total_ready; #else - // POSIX: just use select directly - return select(nfds, readfds, writefds, exceptfds, timeout); + // return select(nfds, readfds, writefds, exceptfds, timeout); + // nfds is shared with pipes , sockets , files in which we use separate maps so it can't work + // like this + LOG_ERROR(Lib_Net, "unimplemented (suck it linux) nfds={}", nfds); + return 0; #endif } void RegisterKernel(Core::Loader::SymbolsResolver* sym) {