From 4d2b7035d945b0921657293afa7fe84ba6f9c91f Mon Sep 17 00:00:00 2001 From: ParantezTech <12572227+par274@users.noreply.github.com> Date: Tue, 6 Oct 2026 13:44:48 +0300 Subject: [PATCH] [Kernel] Poll host semaphore waits and deliver guest exceptions Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com> --- .../Kernel/KernelSemaphoreCompatExports.cs | 55 ++++++++++++------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/src/SharpEmu.Libs/Kernel/KernelSemaphoreCompatExports.cs b/src/SharpEmu.Libs/Kernel/KernelSemaphoreCompatExports.cs index afc2bb7..584a057 100644 --- a/src/SharpEmu.Libs/Kernel/KernelSemaphoreCompatExports.cs +++ b/src/SharpEmu.Libs/Kernel/KernelSemaphoreCompatExports.cs @@ -266,40 +266,55 @@ public static class KernelSemaphoreCompatExports var deadlineMs = hasTimeout ? Environment.TickCount64 + Math.Max(1L, timeoutUsec / 1000L) : long.MaxValue; - lock (semaphore.Gate) + if (_traceSema) { - if (_traceSema) + lock (semaphore.Gate) { TraceSemaphore( $"wait-host-block handle=0x{handle:X8} name='{semaphore.Name}' need={needCount} " + - $"count={semaphore.Count} timeout={(timeoutAddress == 0 ? "infinite" : timeoutUsec)} {FormatCallSite(ctx)}"); + $"count={semaphore.Count} timeout={(hasTimeout ? timeoutUsec : "infinite")} {FormatCallSite(ctx)}"); } - while (semaphore.Count < needCount) + } + + while (true) + { + lock (semaphore.Gate) { + if (semaphore.Count >= needCount) + { + semaphore.Count -= needCount; + semaphore.WaitingThreads = Math.Max(0, semaphore.WaitingThreads - 1); + if (_traceSema) + { + TraceSemaphore( + $"wait-host-wake handle=0x{handle:X8} name='{semaphore.Name}' need={needCount} count={semaphore.Count} {FormatCallSite(ctx)}"); + } + if (timeoutAddress != 0) + { + _ = TryWriteUInt32(ctx, timeoutAddress, 0); + } + + return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_OK); + } + var remaining = deadlineMs - Environment.TickCount64; - if (timeoutAddress != 0 && remaining <= 0) + if (hasTimeout && remaining <= 0) { semaphore.WaitingThreads = Math.Max(0, semaphore.WaitingThreads - 1); - _ = TryWriteUInt32(ctx, timeoutAddress, 0); + if (timeoutAddress != 0) + { + _ = TryWriteUInt32(ctx, timeoutAddress, 0); + } return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_TIMED_OUT); } - Monitor.Wait(semaphore.Gate, (int)Math.Min(remaining, 100)); + var waitMilliseconds = hasTimeout + ? (int)Math.Max(1L, Math.Min(remaining, 10L)) + : 10; + Monitor.Wait(semaphore.Gate, waitMilliseconds); } - semaphore.Count -= needCount; - semaphore.WaitingThreads = Math.Max(0, semaphore.WaitingThreads - 1); - if (_traceSema) - { - TraceSemaphore( - $"wait-host-wake handle=0x{handle:X8} name='{semaphore.Name}' need={needCount} count={semaphore.Count} {FormatCallSite(ctx)}"); - } - if (timeoutAddress != 0) - { - _ = TryWriteUInt32(ctx, timeoutAddress, 0); - } - - return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_OK); + GuestThreadExecution.Scheduler?.DeliverPendingGuestExceptionIfReady(ctx); } }