// 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 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; if (guestThreadHandle != 0 && TryGetThreadIdentity(guestThreadHandle, out _)) { return guestThreadHandle; } EnsureCurrentThreadRegistered(); return _currentThreadHandle; } internal static ulong GetCurrentThreadUniqueId() { var guestThreadHandle = GuestThreadExecution.CurrentGuestThreadHandle; if (guestThreadHandle != 0 && TryGetThreadIdentity(guestThreadHandle, out var identity)) { return identity.UniqueId; } EnsureCurrentThreadRegistered(); return _currentThreadUniqueId; } 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 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; } }