mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-26 04:39:17 +08:00
96fde5764f
* Cpu/Kernel: harden VEH trampoline and keep TBB on native workers Route FastFail/CLR/stack-overflow around managed VEH, serialize managed entry with a recursive spinlock, require native workers for tbb_thead, and abandon pthread mutexes when a guest thread is torn down by worker abort so splash waiters are not left holding locks forever. * Cpu: soft-fail TBB native worker storms and cap concurrent Runs Throwing on worker/prologue faults killed the process mid tbb_thead burst (FailFast 0xC0000409). Soft-return 0x80020012, limit in-flight native Runs (default 2), and keep prewarm small so back-to-back boots do not need an artificial settle delay. * Agc/VideoOut: poison-only empty-SRT reject and clear procedural ES/PS Skip QueueSubmit only when Address-0 image slots remain; run the Astro title clear pair via CmdClearColorImage so the pass executes without descriptors that lose the device. * VideoOut: recreate swapchain with fallback extent on 0x0 surface Minimized Win32 surfaces report 0x0 / MaxImageExtent=0; deferring recreate forever left an OutOfDate swapchain with no presents. Clamp to last/default size and recreate instead of early-return. * Psml: stub MFSR init/shared/context and dispatch packet size Astro Bot asserts in GfxRenderStagePSSR when scePsmlMfsrInit is unresolved (Mfsr initialized failed). Soft HLE for the MFSR shared-resource and 800M3_2 context path plus dispatch packet size lets boot pass splash to first frame without claiming real upscaling. * Psml: stub MFSR GetDispatchMfsrPacket900 for logo PSSR Astro StartLevel ps_logo asserted GfxRenderStagePSSR.cpp:266 when GetDispatchMfsrPacket900 (RUNLFro+qok) was unresolved. Return SCE_OK from SizeInDwords so the 900 fill runs, soft-clear the guest packet buffer, and register 1000/1100 siblings for the same ABI.
114 lines
3.6 KiB
C#
114 lines
3.6 KiB
C#
// Copyright (C) 2026 SharpEmu Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
using System.Collections.Concurrent;
|
|
using System.Runtime.InteropServices;
|
|
using System.Threading;
|
|
using SharpEmu.HLE;
|
|
|
|
namespace SharpEmu.Libs.Kernel;
|
|
|
|
internal static class KernelPthreadState
|
|
{
|
|
private const int ThreadObjectSize = 0x1000;
|
|
|
|
private static readonly ConcurrentDictionary<ulong, ThreadIdentity> Threads = new();
|
|
private static readonly byte[] ZeroThreadObject = new byte[ThreadObjectSize];
|
|
private static long _nextUniqueThreadId = 1;
|
|
|
|
[ThreadStatic]
|
|
private static ulong _currentThreadHandle;
|
|
|
|
[ThreadStatic]
|
|
private static ulong _currentThreadUniqueId;
|
|
|
|
internal readonly record struct ThreadIdentity(ulong UniqueId, string Name);
|
|
|
|
internal static ulong GetCurrentThreadHandle()
|
|
{
|
|
var guestThreadHandle = GuestThreadExecution.CurrentGuestThreadHandle;
|
|
// Prefer the bound guest handle even when it is not yet in Threads.
|
|
// Falling through to a synthetic ThreadStatic handle while a guest
|
|
// thread is bound causes mutex owner mismatches (unlock PERM → hang).
|
|
if (guestThreadHandle != 0)
|
|
{
|
|
EnsureGuestThreadIdentity(guestThreadHandle);
|
|
return guestThreadHandle;
|
|
}
|
|
|
|
EnsureCurrentThreadRegistered();
|
|
return _currentThreadHandle;
|
|
}
|
|
|
|
internal static ulong GetCurrentThreadUniqueId()
|
|
{
|
|
var guestThreadHandle = GuestThreadExecution.CurrentGuestThreadHandle;
|
|
if (guestThreadHandle != 0)
|
|
{
|
|
return EnsureGuestThreadIdentity(guestThreadHandle).UniqueId;
|
|
}
|
|
|
|
EnsureCurrentThreadRegistered();
|
|
return _currentThreadUniqueId;
|
|
}
|
|
|
|
internal static string DescribeThreadHandle(ulong threadHandle)
|
|
{
|
|
if (threadHandle == 0)
|
|
{
|
|
return "none";
|
|
}
|
|
|
|
return TryGetThreadIdentity(threadHandle, out var identity)
|
|
? $"0x{threadHandle:X16}('{identity.Name}')"
|
|
: $"0x{threadHandle:X16}";
|
|
}
|
|
|
|
internal static ulong CreateThreadHandle(string name)
|
|
{
|
|
var uniqueId = unchecked((ulong)Interlocked.Increment(ref _nextUniqueThreadId));
|
|
return AllocateThreadHandle(uniqueId, name);
|
|
}
|
|
|
|
internal static bool TryGetThreadIdentity(ulong threadHandle, out ThreadIdentity identity)
|
|
{
|
|
return Threads.TryGetValue(threadHandle, out identity);
|
|
}
|
|
|
|
private static ThreadIdentity EnsureGuestThreadIdentity(ulong guestThreadHandle)
|
|
{
|
|
if (Threads.TryGetValue(guestThreadHandle, out var existing))
|
|
{
|
|
return existing;
|
|
}
|
|
|
|
var uniqueId = unchecked((ulong)Interlocked.Increment(ref _nextUniqueThreadId));
|
|
var identity = new ThreadIdentity(uniqueId, $"Guest-0x{guestThreadHandle:X}");
|
|
return Threads.GetOrAdd(guestThreadHandle, identity);
|
|
}
|
|
|
|
private static void EnsureCurrentThreadRegistered()
|
|
{
|
|
if (_currentThreadHandle != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var uniqueId = unchecked((ulong)Interlocked.Increment(ref _nextUniqueThreadId));
|
|
var name = $"Thread-{uniqueId:X}";
|
|
_currentThreadHandle = AllocateThreadHandle(uniqueId, name);
|
|
_currentThreadUniqueId = uniqueId;
|
|
}
|
|
|
|
private static ulong AllocateThreadHandle(ulong uniqueId, string name)
|
|
{
|
|
var pointer = Marshal.AllocHGlobal(ThreadObjectSize);
|
|
Marshal.Copy(ZeroThreadObject, 0, pointer, ThreadObjectSize);
|
|
|
|
var handle = unchecked((ulong)pointer.ToInt64());
|
|
Threads[handle] = new ThreadIdentity(uniqueId, string.IsNullOrWhiteSpace(name) ? $"Thread-{uniqueId:X}" : name);
|
|
|
|
return handle;
|
|
}
|
|
}
|