Merge pull request #3542 from BharatYadav007/bharat/libc-setlogmask

feat(libc): implement setlogmask
This commit is contained in:
Adrià 2026-10-11 23:32:17 +02:00 committed by GitHub
commit 28400c02d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 59 additions and 9 deletions

View File

@ -19,6 +19,7 @@ constexpr int priorityMask = 0x07;
constexpr int facilityMask = 0x3f8;
constexpr int userFacility = 1 << 3;
constexpr int internalLogPriority = 3 | 0x02 | 0x20 | 0x01;
int logMask = 0xff;
std::mutex& OutputMutex() {
static std::mutex mutex;
@ -26,7 +27,6 @@ std::mutex& OutputMutex() {
}
void Emit(int priority, const std::string& message) {
std::lock_guard lock(OutputMutex());
std::fprintf(stderr, "[syslog:%d] %s", priority, message.c_str());
if (message.empty() || message.back() != '\n') std::fputc('\n', stderr);
std::fflush(stderr);
@ -75,16 +75,28 @@ std::string Format(const char* format, VaList* args) {
}
extern "C" {
int APS5_VABI setlogmask_nid_postfix(int mask) {
std::lock_guard lock(OutputMutex());
const int previous = logMask;
if (mask != 0) logMask = mask;
return previous;
}
void APS5_VABI vsyslog_nid_postfix(int priority, const char* format, VaList* args) {
const int saved = *__error_nid_postfix();
std::lock_guard lock(OutputMutex());
if (priority & ~(priorityMask | facilityMask)) {
char complaint[64];
std::snprintf(complaint, sizeof(complaint), "syslog: unknown facility/priority: %x", priority);
Emit(internalLogPriority, complaint);
if (logMask & (1 << (internalLogPriority & priorityMask))) {
char complaint[64];
std::snprintf(complaint, sizeof(complaint), "syslog: unknown facility/priority: %x", priority);
Emit(internalLogPriority, complaint);
}
priority &= priorityMask | facilityMask;
}
if ((priority & facilityMask) == 0) priority |= userFacility;
Emit(priority, format ? Format(ExpandErrorText(format, saved).c_str(), args) : std::string());
if (logMask & (1 << (priority & priorityMask))) {
if ((priority & facilityMask) == 0) priority |= userFacility;
Emit(priority, format ? Format(ExpandErrorText(format, saved).c_str(), args) : std::string());
}
*__error_nid_postfix() = saved;
}

View File

@ -2,6 +2,7 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <thread>
#ifdef _WIN32
#include <io.h>
#else
@ -10,6 +11,7 @@
extern "C" {
void APS5_VABI syslog_nid_postfix(int, const char*, ...);
int APS5_VABI setlogmask_nid_postfix(int);
int* APS5_VABI __error_nid_postfix();
}
static void Require(bool value) { if (!value) std::abort(); }
@ -25,11 +27,38 @@ int main() {
Require(saved >= 0 && ::dup2(::fileno(captured), ::fileno(stderr)) == ::fileno(stderr));
#endif
*__error_nid_postfix() = 2;
Require(setlogmask_nid_postfix(0) == 0xff);
syslog_nid_postfix(6, "station %s at %d kbps", "radio", 128);
const int afterFirst = *__error_nid_postfix();
syslog_nid_postfix(16 | 3, "open: %m, %%m kept, %d%%\n", 50);
syslog_nid_postfix(0x10000 | 4, "masked");
syslog_nid_postfix(7, "");
Require(setlogmask_nid_postfix(1 << 3) == 0xff);
Require(setlogmask_nid_postfix(0) == (1 << 3));
int count = -1;
syslog_nid_postfix(7, "suppressed %m%n", &count);
Require(count == -1 && *__error_nid_postfix() == 2);
syslog_nid_postfix(16 | 3, "allowed: %m");
Require(*__error_nid_postfix() == 2);
syslog_nid_postfix(0x10000 | 7, "suppressed %n", &count);
Require(count == -1 && *__error_nid_postfix() == 2);
Require(setlogmask_nid_postfix(1 << 4) == (1 << 3));
syslog_nid_postfix(0x10000 | 4, "warning without diagnostic");
syslog_nid_postfix(0x10000 | 7, "both suppressed %n", &count);
Require(count == -1 && *__error_nid_postfix() == 2);
Require(setlogmask_nid_postfix(0x100) == (1 << 4));
Require(setlogmask_nid_postfix(0) == 0x100);
syslog_nid_postfix(0x10000 | 3, "no priorities enabled %n", &count);
Require(count == -1 && *__error_nid_postfix() == 2);
Require(setlogmask_nid_postfix(-1) == 0x100);
Require(setlogmask_nid_postfix(0) == -1);
syslog_nid_postfix(7, "negative mask");
Require(setlogmask_nid_postfix(0x55) == -1);
for (int priority = 0; priority < 8; ++priority)
syslog_nid_postfix(16 | priority, "level %d", priority);
std::thread([] { Require(setlogmask_nid_postfix(0xff) == 0x55); }).join();
Require(setlogmask_nid_postfix(0) == 0xff);
syslog_nid_postfix(7, "mask shared across threads");
std::fflush(stderr);
#ifdef _WIN32
Require(::_dup2(saved, ::_fileno(stderr)) == 0 && ::_close(saved) == 0);
@ -38,14 +67,23 @@ int main() {
#endif
Require(afterFirst == 2 && *__error_nid_postfix() == 2);
std::rewind(captured);
char text[512]{};
char text[1024]{};
const auto length = std::fread(text, 1, sizeof(text) - 1, captured);
const char* expected =
"[syslog:14] station radio at 128 kbps\n"
"[syslog:19] open: No such file or directory, %m kept, 50%\n"
"[syslog:35] syslog: unknown facility/priority: 10004\n"
"[syslog:12] masked\n"
"[syslog:15] \n";
"[syslog:15] \n"
"[syslog:19] allowed: No such file or directory\n"
"[syslog:35] syslog: unknown facility/priority: 10007\n"
"[syslog:12] warning without diagnostic\n"
"[syslog:15] negative mask\n"
"[syslog:16] level 0\n"
"[syslog:18] level 2\n"
"[syslog:20] level 4\n"
"[syslog:22] level 6\n"
"[syslog:15] mask shared across threads\n";
Require(length == std::strlen(expected) && std::strcmp(text, expected) == 0);
Require(std::fclose(captured) == 0);
}

View File

@ -589,7 +589,7 @@ Throughout the project, every function at every stage either **does exactly what
- [DB_RENDER_CONTROL resummarize draws](../../core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp) (libSceAgcDriver) - HTILE is not modeled, so a RESUMMARIZE_ENABLE draw without depth or stencil tests and without color writes changes no modeled state and draws nothing; any other resummarize, copy or decompress draw throws
- [s_call_b64](../../core/shader/recompiler/Translation/src/ScalarInstructions.cpp) saves `PC + 4` over `GetShaderBase` and branches to `PC + 4 + signext(SIMM16) * 4`, following [AMD RDNA2 ISA](https://gpuopen.com/download/rdna2-shader-instruction-set-architecture.pdf) sections 3.6.3, 12.2 and 12.3. Forward callees after `s_endpgm` are decoded. Measured on RDNA2 (gfx1036) in wave32 and wave64 with SIMM16 = 3: the link pair receives `PC + 4`, the branch goes to `PC + 4 + signext(SIMM16) * 4`, and `s_setpc_b64` of the link returns to the instruction after the call. Execution on the PS5 (gfx1013) and title compatibility for these bounded scalar calls remain unverified; `s_rfe_b64` still throws in translation.
- [sceVideodec2CreateDecoder](../../core/libs/prx/libSceVideodec2/Export.cpp) (libSceVideodec2) decodes HEVC (codec type 974921) and VP9 (2382845) through FFmpeg, besides H.264. The tags come from SharpProspero's `Videodec2CodecType` and EVO-PLAYER-PS5's `sce_videodec2.h`, which records them from hardware runs. HEVC input is converted from length-prefixed NAL units to Annex B as for H.264, and VP9 frames are passed through. Output is the same 8-bit NV12 for every codec; a decoder for HEVC Main10 or VP9 Profile 2 is created, but a frame deeper than 8 bits throws, since the console's 10-bit output layout is unknown, and `QueryDecoderMemoryInfo` reports the 8-bit frame size for it. `sceVideodec2GetPictureInfo` and `sceVideodec2GetAvcPictureInfo` throw for HEVC and VP9 pictures, which use other layouts (`SceVideodec2HevcPictureInfo`, `SceVideodec2Vp9PictureInfo`), and `sceVideodec2GetHevcPictureInfo` and `sceVideodec2GetVp9PictureInfo` are not exported
- [syslog](../../core/libs/prx/libc/src/Syslog.cpp) (libc) writes each message to `stderr` as `[syslog:<priority>] <message>`, with a newline added when missing, instead of sending it to the console's system log. Priority and facility handling follow FreeBSD's `vsyslog`: `%m` expands to the guest errno's message, unknown bits are reported (as priority 0x23, since FreeBSD passes `LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID` as the priority) and masked, a missing facility becomes `LOG_USER`, and errno is preserved. `openlog`, `setlogmask` and `closelog` are not implemented, so the identity, options and mask they set are not applied
- [syslog](../../core/libs/prx/libc/src/Syslog.cpp) (libc) writes each message to `stderr` as `[syslog:<priority>] <message>`, with a newline added when missing, instead of sending it to the console's system log. Priority and facility handling follow FreeBSD's `vsyslog`: `%m` expands to the guest errno's message, unknown bits are reported (as priority 0x23, since FreeBSD passes `LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID` as the priority) and masked, a missing facility becomes `LOG_USER`, and errno is preserved. `setlogmask` follows [FreeBSD 11](https://github.com/freebsd/freebsd-src/blob/8d2708de5d6112a492744d367cfdfb8fd219227a/lib/libc/gen/syslog.c): the process-wide mask defaults to 0xff, zero queries it, and nonzero values replace it; masked messages are skipped before formatting, including the unknown-priority diagnostic. The console's mask behaviour is unverified. `openlog` and `closelog` are not implemented, so their identity and options are not applied
- [daemon](../../core/libs/prx/libc/src/Process.cpp) (libc) throws: forking into the background is not supported. PPSA85300 imports it and fails to load without it. VLC 3.0 calls it only when its `daemon` option is set ([libvlc.c](https://github.com/videolan/vlc/blob/6de05adcbaf2e8b85fe86aad4169393098628119/src/libvlc.c#L190-L197)), and the title starts libVLC with `--ignore-config` and without `--daemon` ([player.cc](https://github.com/ZiZc3/VLC/blob/f3253020a64368153233ede29183014c0b6c8979/src/player.cc#L960-L981))
- [sigtimedwait](../../core/libs/prx/libkernel/System/src/Signals.cpp) (libkernel) throws: guest signals are delivered when raised and never left pending, so there is nothing to wait for or take. PPSA85300 imports it and fails to load without it. Its only call site is VLC's `vlc_writev` ([filesystem.c](https://github.com/videolan/vlc/blob/6de05adcbaf2e8b85fe86aad4169393098628119/src/posix/filesystem.c#L243-L278)), which polls with a zero timeout to drain a `SIGPIPE` only after `writev` fails with `EPIPE`
- [sigaction](../../core/libs/prx/libkernel/System/src/Signals.cpp) (libkernel) records the handler, flags and mask of every signal from 1 to 128 and reports them back, following FreeBSD's `sigaction` (`EINVAL` for other signals, and for a handler on `SIGKILL` or `SIGSTOP`); `signal` records its handler with `SA_RESTART`, as FreeBSD's libc does. Only handlers without `SA_SIGINFO` on the signals `signal` already delivers (`SIGINT`, `SIGILL`, `SIGABRT`, `SIGFPE`, `SIGSEGV`, `SIGTERM`) run, the same way `signal` handlers do; their mask and flags are not applied. `SA_SIGINFO` handlers are recorded but never called, since that needs FreeBSD's `siginfo_t` and `ucontext_t`, and neither are the handlers of other signals (`SIGBUS`, `SIGHUP`, ...), whether they are set by `sigaction` or by `signal`, which records them too (every number from 1 to 128, with `SA_RESTART` and an empty mask replacing what `sigaction` stored; `SIGKILL` and `SIGSTOP` accept only the default handler in both calls, as in FreeBSD's `kern_sigaction`). `raise` of an `SA_SIGINFO` handler on a signal `signal` delivers throws instead of terminating, and `raise` and `kill` of the other signals still fail with `EINVAL`, recorded handler or not