From 2a27cfe8be9c9b3d6873de78bb1c087194f7e16b Mon Sep 17 00:00:00 2001 From: ParantezTech <12572227+par274@users.noreply.github.com> Date: Tue, 22 Sep 2026 03:07:29 +0300 Subject: [PATCH] [Pthread] implement scePthreadCondSignalto --- .../Kernel/KernelPthreadCompatExports.cs | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/SharpEmu.Libs/Kernel/KernelPthreadCompatExports.cs b/src/SharpEmu.Libs/Kernel/KernelPthreadCompatExports.cs index 0f8c923..c731b1c 100644 --- a/src/SharpEmu.Libs/Kernel/KernelPthreadCompatExports.cs +++ b/src/SharpEmu.Libs/Kernel/KernelPthreadCompatExports.cs @@ -515,6 +515,14 @@ public static class KernelPthreadCompatExports LibraryName = "libKernel")] public static int PthreadCondSignal(CpuContext ctx) => PthreadCondSignalCore(ctx, ctx[CpuRegister.Rdi], broadcast: false); + [SysAbiExport( + Nid = "o69RpYO-Mu0", + ExportName = "scePthreadCondSignalto", + Target = Generation.Gen4 | Generation.Gen5, + LibraryName = "libKernel")] + public static int PthreadCondSignalto(CpuContext ctx) => + PthreadCondSignalToCore(ctx, ctx[CpuRegister.Rdi], ctx[CpuRegister.Rsi]); + [SysAbiExport( Nid = "JGgj7Uvrl+A", ExportName = "scePthreadCondBroadcast", @@ -2060,6 +2068,57 @@ public static class KernelPthreadCompatExports return (int)OrbisGen2Result.ORBIS_GEN2_OK; } + private static int PthreadCondSignalToCore(CpuContext ctx, ulong condAddress, ulong threadId) + { + if (threadId == 0) + { + return PthreadCondSignalCore(ctx, condAddress, broadcast: false); + } + + if (condAddress == 0) + { + return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT; + } + + if (!TryResolveCondState(ctx, condAddress, createIfZero: true, out _, out var state)) + { + return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND; + } + + PthreadCondWaiter? completedWaiter = null; + lock (state.SyncRoot) + { + state.SignalEpoch++; + for (var node = state.WaiterQueue.First; node is not null; node = node.Next) + { + var waiter = node.Value; + if (waiter.ThreadId != threadId || + waiter.CompletionState != 0 || + !CompleteCondWaiterLocked(state, waiter, timedOut: false)) + { + continue; + } + + completedWaiter = waiter; + break; + } + + TracePthreadCond("signalto", condAddress, mutexAddress: 0, state, timed: false, + completedWaiter is null ? 1 : (int)OrbisGen2Result.ORBIS_GEN2_OK); + } + + if (completedWaiter is null) + { + // Matches pthread_cond_signalto_np: a valid target that is not + // currently waiting on this condition returns EPERM (1), which + // the Orbis wrapper maps to its kernel error form. + return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_PERMISSION_DENIED; + } + + WakeCooperativeWaiter(completedWaiter); + return (int)OrbisGen2Result.ORBIS_GEN2_OK; + } + private static PthreadMutexWaiter EnqueueMutexWaiterLocked( PthreadMutexState state, ulong threadId,