mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-05 13:20:11 +00:00
Merge pull request #7282 from T3cm0/bionic/unlocked-stream-queries
feat(libc): implement clearerr_unlocked, fileno_unlocked and fgetln
This commit is contained in:
3 files changed
+34
No files matched your search
@@ -1,6 +1,9 @@
|
||||
#include "prx/libc/include/FileStream.hpp"
|
||||
#include "prx/libc/include/general/VabiMacros.hpp"
|
||||
#include <cerrno>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#else
|
||||
@@ -134,6 +137,16 @@ int APS5_VABI fileno_nid_postfix(FileStream* stream) {
|
||||
stream->GuestState().descriptor = static_cast<std::int16_t>(descriptor);
|
||||
return descriptor;
|
||||
}
|
||||
void APS5_VABI clearerr_unlocked_nid_postfix(FileStream* stream) {
|
||||
stream->ClearError();
|
||||
}
|
||||
int APS5_VABI fileno_unlocked_nid_postfix(FileStream* stream) {
|
||||
if (stream == nullptr || !stream->IsOpen()) return -1;
|
||||
return fileno_nid_postfix(stream);
|
||||
}
|
||||
[[noreturn]] char* APS5_VABI fgetln_nid_postfix(FileStream*, std::size_t*) {
|
||||
throw std::runtime_error("fgetln: the console's export is a hlt instruction, which ends the process");
|
||||
}
|
||||
int APS5_VABI setvbuf_nid_postfix(FileStream* stream, char* buffer, int mode, std::size_t size) {
|
||||
if (stream && !stream->IsOpen()) { errno = 9; return -1; }
|
||||
if (mode < 0 || mode > 2) return -1;
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
#endif
|
||||
extern "C" {
|
||||
FileStream* APS5_VABI fopen_nid_postfix(const char*, const char*);
|
||||
void APS5_VABI clearerr_unlocked_nid_postfix(FileStream*);
|
||||
int APS5_VABI fileno_unlocked_nid_postfix(FileStream*);
|
||||
char* APS5_VABI fgetln_nid_postfix(FileStream*, std::size_t*);
|
||||
std::size_t APS5_VABI fread_nid_postfix(void*, std::size_t, std::size_t, FileStream*);
|
||||
std::size_t APS5_VABI fwrite_nid_postfix(const void*, std::size_t, std::size_t, FileStream*);
|
||||
FileStream* APS5_VABI freopen_nid_postfix(const char*, const char*, FileStream*);
|
||||
@@ -169,6 +172,22 @@ static void CheckUnlockedStreams() {
|
||||
Require(std::filesystem::remove(filename));
|
||||
}
|
||||
|
||||
static void CheckUnlockedQueries() {
|
||||
FileStream stream(std::tmpfile());
|
||||
Require(fputc_nid_postfix(0x7f, &stream) == 0x7f);
|
||||
std::rewind(stream.GetHandle());
|
||||
Require(fgetc_nid_postfix(&stream) == 0x7f && feof_nid_postfix(&stream) == 0);
|
||||
Require(fgetc_nid_postfix(&stream) == -1 && feof_nid_postfix(&stream) != 0);
|
||||
clearerr_unlocked_nid_postfix(&stream);
|
||||
Require(feof_nid_postfix(&stream) == 0 && ferror_nid_postfix(&stream) == 0);
|
||||
Require(fileno_unlocked_nid_postfix(&stream) == fileno_nid_postfix(&stream) && fileno_unlocked_nid_postfix(&stream) >= 0);
|
||||
Require(fileno_unlocked_nid_postfix(nullptr) == -1);
|
||||
bool halted = false;
|
||||
std::size_t length = 0;
|
||||
try { fgetln_nid_postfix(&stream, &length); } catch (const std::runtime_error&) { halted = true; }
|
||||
Require(halted);
|
||||
}
|
||||
|
||||
static void CheckTryLock() {
|
||||
FileStream stream(std::tmpfile());
|
||||
const auto tryFromOtherThread = [&] {
|
||||
@@ -843,5 +862,6 @@ int main(int argc, char** argv) {
|
||||
CheckUnlockedStreamLock(false);
|
||||
CheckUnlockedStreamLock(true);
|
||||
CheckTryLock();
|
||||
CheckUnlockedQueries();
|
||||
return CheckBinaryModes() ? 0 : 1;
|
||||
}
|
||||
@@ -48,6 +48,7 @@
|
||||
- [getc_unlocked, putc_unlocked, getchar_unlocked, putchar_unlocked](../../../core/libs/prx/libc/src/StandardStreams.cpp) (libc) - byte I/O uses the host unlocked operations; guest EOF/error flags and macro counters follow `FileStream`. Linux status queries use `feof_unlocked`/`ferror_unlocked` because [glibc `feof`](https://github.com/bminor/glibc/blob/d2097651cc57834dbfcaa102ddfacae0d86cfb66/libio/feof.c) and [`ferror`](https://github.com/bminor/glibc/blob/d2097651cc57834dbfcaa102ddfacae0d86cfb66/libio/ferror.c) can acquire the stream lock. Windows uses [the CRT no-lock byte operations](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/fgetc-nolock-fgetwc-nolock) and `feof`/`ferror`, verified under a held stream lock on UCRT. Console behavior and other host CRTs remain unverified.
|
||||
- [fgetws, getwc, getwchar, putwc, putwchar](../../../core/libs/prx/libc/src/FormattingWide.cpp) (libc) - wide stream I/O encodes and decodes wide characters as UTF-8 on the underlying byte stream; `fgetws` reads characters into the destination buffer until newline or EOF and null-terminates, returning null on stream error. Console wide stream buffering and encoding details remain unverified.
|
||||
- [ftrylockfile](../../../core/libs/prx/libc/src/RuntimeSupport.cpp) (libc) - tries the host CRT stream lock that `flockfile`, `funlockfile` and each locking host stdio call on the stream take, so it returns -1 while another thread holds the stream through `flockfile` or is inside such a call, and 0 when it acquires the lock or already owns it (recursively, released by as many `funlockfile` calls), as FreeBSD 11 [`_ftrylockfile`](https://github.com/freebsd/freebsd-src/blob/8c639945a44588f6cfdddfb057bb5aad88735da0/lib/libc/stdio/_flock_stub.c#L89-L104) does. A libc export holds the lock only for each host call it makes, not across several host calls or while it updates the guest `FILE` prefix. Linux uses glibc `ftrylockfile`. UCRT has no try variant of `_lock_file`, so Windows calls `TryEnterCriticalSection` on the `CRITICAL_SECTION` that `_lock_file` enters, found through the private UCRT stream layout (`__crt_stdio_stream_data` in `ucrt/inc/corecrt_internal_stdio.h`, unchanged from Windows SDK 10.0.19041 to 10.0.26100); another CRT or a change of that layout breaks it. A null or closed stream throws where FreeBSD dereferences it
|
||||
- [fgetln](../../../core/libs/prx/libc/src/StandardStreams.cpp) (libSceLibcInternal, implemented in libc) throws: in the console's `libSceLibcInternal.sprx` (SDK 4.5x build of `J03950001`, 0x5FE80) the export is a `hlt` instruction, which faults in user mode and ends the process
|
||||
- [Wide-character conversions](../../../core/libs/prx/libc/src/Multibyte.cpp) (libc) - The wide `wcsto*` functions parse the ASCII prefix of the guest string, as the C locale accepts only ASCII white space and digits. [`wcsrtombs`](../../../core/libs/prx/libc/src/Multibyte.cpp) uses the guest's single-byte C locale through `wcrtomb`; other encodings and shift states are not supported
|
||||
- [realpath](../../../core/libs/prx/libc/src/RealPath.cpp) (libc) follows FreeBSD 11's [`realpath.c`](https://github.com/freebsd/freebsd-src/blob/stable/11/lib/libc/stdlib/realpath.c) except for symlinks. The console's guest filesystem has none, so a host symlink under the guest root is followed for existence and type but not expanded, and `..` drops the previous component lexically, as `Resolve` does for every guest path. Through a host link `linkdir -> sub/deep`, `linkdir/../x` gives `x` beside the link, not beside its target.
|
||||
- [strtod, strtof, strtold](../../../core/libs/prx/libc/src/Strings.cpp) (libc) - `NAN(n-char-sequence)` converts to the quiet NaN that `nan` and `nanf` return, negated after a minus sign, and ignores the sequence as they ignore their tag. This is inferred from C17 7.12.11.2p2, which makes `nan("n")` equivalent to `strtod("NAN(n)", NULL)`, and not observed on the console. No console `nanl` was observed, so `strtold` returns the x87 default quiet NaN (exponent `0x7fff`, significand `0xc000000000000000`)
|
||||
|
||||
Reference in new issue
Block a user