diff options
author | TSR Berry <20988865+TSRBerry@users.noreply.github.com> | 2023-04-08 01:22:00 +0200 |
---|---|---|
committer | Mary <thog@protonmail.com> | 2023-04-27 23:51:14 +0200 |
commit | cee712105850ac3385cd0091a923438167433f9f (patch) | |
tree | 4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs | |
parent | cd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff) |
Move solution and projects to src
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs')
-rw-r--r-- | Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs | 1196 |
1 files changed, 0 insertions, 1196 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs deleted file mode 100644 index 21e89944..00000000 --- a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs +++ /dev/null @@ -1,1196 +0,0 @@ -using Ryujinx.Common; -using Ryujinx.Common.Logging; -using Ryujinx.Cpu; -using Ryujinx.HLE.Exceptions; -using Ryujinx.HLE.HOS.Kernel.Common; -using Ryujinx.HLE.HOS.Kernel.Memory; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.Horizon.Common; -using Ryujinx.Memory; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; - -namespace Ryujinx.HLE.HOS.Kernel.Process -{ - class KProcess : KSynchronizationObject - { - public const uint KernelVersionMajor = 10; - public const uint KernelVersionMinor = 4; - public const uint KernelVersionRevision = 0; - - public const uint KernelVersionPacked = - (KernelVersionMajor << 19) | - (KernelVersionMinor << 15) | - (KernelVersionRevision << 0); - - public KPageTableBase MemoryManager { get; private set; } - - private SortedDictionary<ulong, KTlsPageInfo> _fullTlsPages; - private SortedDictionary<ulong, KTlsPageInfo> _freeTlsPages; - - public int DefaultCpuCore { get; set; } - - public bool Debug { get; private set; } - - public KResourceLimit ResourceLimit { get; private set; } - - public ulong PersonalMmHeapPagesCount { get; private set; } - - public ProcessState State { get; private set; } - - private object _processLock; - private object _threadingLock; - - public KAddressArbiter AddressArbiter { get; private set; } - - public ulong[] RandomEntropy { get; private set; } - public KThread[] PinnedThreads { get; private set; } - - private bool _signaled; - - public string Name { get; private set; } - - private int _threadCount; - - public ProcessCreationFlags Flags { get; private set; } - - private MemoryRegion _memRegion; - - public KProcessCapabilities Capabilities { get; private set; } - - public bool AllowCodeMemoryForJit { get; private set; } - - public ulong TitleId { get; private set; } - public bool IsApplication { get; private set; } - public ulong Pid { get; private set; } - - private long _creationTimestamp; - private ulong _entrypoint; - private ThreadStart _customThreadStart; - private ulong _imageSize; - private ulong _mainThreadStackSize; - private ulong _memoryUsageCapacity; - private int _version; - - public KHandleTable HandleTable { get; private set; } - - public ulong UserExceptionContextAddress { get; private set; } - - private LinkedList<KThread> _threads; - - public bool IsPaused { get; private set; } - - private long _totalTimeRunning; - - public long TotalTimeRunning => _totalTimeRunning; - - private IProcessContextFactory _contextFactory; - public IProcessContext Context { get; private set; } - public IVirtualMemoryManager CpuMemory => Context.AddressSpace; - - public HleProcessDebugger Debugger { get; private set; } - - public KProcess(KernelContext context, bool allowCodeMemoryForJit = false) : base(context) - { - _processLock = new object(); - _threadingLock = new object(); - - AddressArbiter = new KAddressArbiter(context); - - _fullTlsPages = new SortedDictionary<ulong, KTlsPageInfo>(); - _freeTlsPages = new SortedDictionary<ulong, KTlsPageInfo>(); - - Capabilities = new KProcessCapabilities(); - - AllowCodeMemoryForJit = allowCodeMemoryForJit; - - RandomEntropy = new ulong[KScheduler.CpuCoresCount]; - PinnedThreads = new KThread[KScheduler.CpuCoresCount]; - - // TODO: Remove once we no longer need to initialize it externally. - HandleTable = new KHandleTable(context); - - _threads = new LinkedList<KThread>(); - - Debugger = new HleProcessDebugger(this); - } - - public Result InitializeKip( - ProcessCreationInfo creationInfo, - ReadOnlySpan<uint> capabilities, - KPageList pageList, - KResourceLimit resourceLimit, - MemoryRegion memRegion, - IProcessContextFactory contextFactory, - ThreadStart customThreadStart = null) - { - ResourceLimit = resourceLimit; - _memRegion = memRegion; - _contextFactory = contextFactory ?? new ProcessContextFactory(); - _customThreadStart = customThreadStart; - - AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift); - - Pid = KernelContext.NewKipId(); - - if (Pid == 0 || Pid >= KernelConstants.InitialProcessId) - { - throw new InvalidOperationException($"Invalid KIP Id {Pid}."); - } - - InitializeMemoryManager(creationInfo.Flags); - - bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr); - - ulong codeAddress = creationInfo.CodeAddress; - - ulong codeSize = (ulong)creationInfo.CodePagesCount * KPageTableBase.PageSize; - - KMemoryBlockSlabManager slabManager = creationInfo.Flags.HasFlag(ProcessCreationFlags.IsApplication) - ? KernelContext.LargeMemoryBlockSlabManager - : KernelContext.SmallMemoryBlockSlabManager; - - Result result = MemoryManager.InitializeForProcess( - addrSpaceType, - aslrEnabled, - !aslrEnabled, - memRegion, - codeAddress, - codeSize, - slabManager); - - if (result != Result.Success) - { - return result; - } - - if (!MemoryManager.CanContain(codeAddress, codeSize, MemoryState.CodeStatic)) - { - return KernelResult.InvalidMemRange; - } - - result = MemoryManager.MapPages(codeAddress, pageList, MemoryState.CodeStatic, KMemoryPermission.None); - - if (result != Result.Success) - { - return result; - } - - result = Capabilities.InitializeForKernel(capabilities, MemoryManager); - - if (result != Result.Success) - { - return result; - } - - return ParseProcessInfo(creationInfo); - } - - public Result Initialize( - ProcessCreationInfo creationInfo, - ReadOnlySpan<uint> capabilities, - KResourceLimit resourceLimit, - MemoryRegion memRegion, - IProcessContextFactory contextFactory, - ThreadStart customThreadStart = null) - { - ResourceLimit = resourceLimit; - _memRegion = memRegion; - _contextFactory = contextFactory ?? new ProcessContextFactory(); - _customThreadStart = customThreadStart; - IsApplication = creationInfo.Flags.HasFlag(ProcessCreationFlags.IsApplication); - - ulong personalMmHeapSize = GetPersonalMmHeapSize((ulong)creationInfo.SystemResourcePagesCount, memRegion); - - ulong codePagesCount = (ulong)creationInfo.CodePagesCount; - - ulong neededSizeForProcess = personalMmHeapSize + codePagesCount * KPageTableBase.PageSize; - - if (neededSizeForProcess != 0 && resourceLimit != null) - { - if (!resourceLimit.Reserve(LimitableResource.Memory, neededSizeForProcess)) - { - return KernelResult.ResLimitExceeded; - } - } - - void CleanUpForError() - { - if (neededSizeForProcess != 0 && resourceLimit != null) - { - resourceLimit.Release(LimitableResource.Memory, neededSizeForProcess); - } - } - - PersonalMmHeapPagesCount = (ulong)creationInfo.SystemResourcePagesCount; - - KMemoryBlockSlabManager slabManager; - - if (PersonalMmHeapPagesCount != 0) - { - slabManager = new KMemoryBlockSlabManager(PersonalMmHeapPagesCount * KPageTableBase.PageSize); - } - else - { - slabManager = creationInfo.Flags.HasFlag(ProcessCreationFlags.IsApplication) - ? KernelContext.LargeMemoryBlockSlabManager - : KernelContext.SmallMemoryBlockSlabManager; - } - - AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift); - - Pid = KernelContext.NewProcessId(); - - if (Pid == ulong.MaxValue || Pid < KernelConstants.InitialProcessId) - { - throw new InvalidOperationException($"Invalid Process Id {Pid}."); - } - - InitializeMemoryManager(creationInfo.Flags); - - bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr); - - ulong codeAddress = creationInfo.CodeAddress; - - ulong codeSize = codePagesCount * KPageTableBase.PageSize; - - Result result = MemoryManager.InitializeForProcess( - addrSpaceType, - aslrEnabled, - !aslrEnabled, - memRegion, - codeAddress, - codeSize, - slabManager); - - if (result != Result.Success) - { - CleanUpForError(); - - return result; - } - - if (!MemoryManager.CanContain(codeAddress, codeSize, MemoryState.CodeStatic)) - { - CleanUpForError(); - - return KernelResult.InvalidMemRange; - } - - result = MemoryManager.MapPages( - codeAddress, - codePagesCount, - MemoryState.CodeStatic, - KMemoryPermission.None); - - if (result != Result.Success) - { - CleanUpForError(); - - return result; - } - - result = Capabilities.InitializeForUser(capabilities, MemoryManager); - - if (result != Result.Success) - { - CleanUpForError(); - - return result; - } - - result = ParseProcessInfo(creationInfo); - - if (result != Result.Success) - { - CleanUpForError(); - } - - return result; - } - - private Result ParseProcessInfo(ProcessCreationInfo creationInfo) - { - // Ensure that the current kernel version is equal or above to the minimum required. - uint requiredKernelVersionMajor = (uint)Capabilities.KernelReleaseVersion >> 19; - uint requiredKernelVersionMinor = ((uint)Capabilities.KernelReleaseVersion >> 15) & 0xf; - - if (KernelContext.EnableVersionChecks) - { - if (requiredKernelVersionMajor > KernelVersionMajor) - { - return KernelResult.InvalidCombination; - } - - if (requiredKernelVersionMajor != KernelVersionMajor && requiredKernelVersionMajor < 3) - { - return KernelResult.InvalidCombination; - } - - if (requiredKernelVersionMinor > KernelVersionMinor) - { - return KernelResult.InvalidCombination; - } - } - - Result result = AllocateThreadLocalStorage(out ulong userExceptionContextAddress); - - if (result != Result.Success) - { - return result; - } - - UserExceptionContextAddress = userExceptionContextAddress; - - MemoryHelper.FillWithZeros(CpuMemory, userExceptionContextAddress, KTlsPageInfo.TlsEntrySize); - - Name = creationInfo.Name; - - State = ProcessState.Created; - - _creationTimestamp = PerformanceCounter.ElapsedMilliseconds; - - Flags = creationInfo.Flags; - _version = creationInfo.Version; - TitleId = creationInfo.TitleId; - _entrypoint = creationInfo.CodeAddress; - _imageSize = (ulong)creationInfo.CodePagesCount * KPageTableBase.PageSize; - - switch (Flags & ProcessCreationFlags.AddressSpaceMask) - { - case ProcessCreationFlags.AddressSpace32Bit: - case ProcessCreationFlags.AddressSpace64BitDeprecated: - case ProcessCreationFlags.AddressSpace64Bit: - _memoryUsageCapacity = MemoryManager.HeapRegionEnd - - MemoryManager.HeapRegionStart; - break; - - case ProcessCreationFlags.AddressSpace32BitWithoutAlias: - _memoryUsageCapacity = MemoryManager.HeapRegionEnd - - MemoryManager.HeapRegionStart + - MemoryManager.AliasRegionEnd - - MemoryManager.AliasRegionStart; - break; - - default: throw new InvalidOperationException($"Invalid MMU flags value 0x{Flags:x2}."); - } - - GenerateRandomEntropy(); - - return Result.Success; - } - - public Result AllocateThreadLocalStorage(out ulong address) - { - KernelContext.CriticalSection.Enter(); - - Result result; - - if (_freeTlsPages.Count > 0) - { - // If we have free TLS pages available, just use the first one. - KTlsPageInfo pageInfo = _freeTlsPages.Values.First(); - - if (!pageInfo.TryGetFreePage(out address)) - { - throw new InvalidOperationException("Unexpected failure getting free TLS page!"); - } - - if (pageInfo.IsFull()) - { - _freeTlsPages.Remove(pageInfo.PageVirtualAddress); - - _fullTlsPages.Add(pageInfo.PageVirtualAddress, pageInfo); - } - - result = Result.Success; - } - else - { - // Otherwise, we need to create a new one. - result = AllocateTlsPage(out KTlsPageInfo pageInfo); - - if (result == Result.Success) - { - if (!pageInfo.TryGetFreePage(out address)) - { - throw new InvalidOperationException("Unexpected failure getting free TLS page!"); - } - - _freeTlsPages.Add(pageInfo.PageVirtualAddress, pageInfo); - } - else - { - address = 0; - } - } - - KernelContext.CriticalSection.Leave(); - - return result; - } - - private Result AllocateTlsPage(out KTlsPageInfo pageInfo) - { - pageInfo = default; - - if (!KernelContext.UserSlabHeapPages.TryGetItem(out ulong tlsPagePa)) - { - return KernelResult.OutOfMemory; - } - - ulong regionStart = MemoryManager.TlsIoRegionStart; - ulong regionSize = MemoryManager.TlsIoRegionEnd - regionStart; - - ulong regionPagesCount = regionSize / KPageTableBase.PageSize; - - Result result = MemoryManager.MapPages( - 1, - KPageTableBase.PageSize, - tlsPagePa, - true, - regionStart, - regionPagesCount, - MemoryState.ThreadLocal, - KMemoryPermission.ReadAndWrite, - out ulong tlsPageVa); - - if (result != Result.Success) - { - KernelContext.UserSlabHeapPages.Free(tlsPagePa); - } - else - { - pageInfo = new KTlsPageInfo(tlsPageVa, tlsPagePa); - - MemoryHelper.FillWithZeros(CpuMemory, tlsPageVa, KPageTableBase.PageSize); - } - - return result; - } - - public Result FreeThreadLocalStorage(ulong tlsSlotAddr) - { - ulong tlsPageAddr = BitUtils.AlignDown<ulong>(tlsSlotAddr, KPageTableBase.PageSize); - - KernelContext.CriticalSection.Enter(); - - Result result = Result.Success; - - KTlsPageInfo pageInfo; - - if (_fullTlsPages.TryGetValue(tlsPageAddr, out pageInfo)) - { - // TLS page was full, free slot and move to free pages tree. - _fullTlsPages.Remove(tlsPageAddr); - - _freeTlsPages.Add(tlsPageAddr, pageInfo); - } - else if (!_freeTlsPages.TryGetValue(tlsPageAddr, out pageInfo)) - { - result = KernelResult.InvalidAddress; - } - - if (pageInfo != null) - { - pageInfo.FreeTlsSlot(tlsSlotAddr); - - if (pageInfo.IsEmpty()) - { - // TLS page is now empty, we should ensure it is removed - // from all trees, and free the memory it was using. - _freeTlsPages.Remove(tlsPageAddr); - - KernelContext.CriticalSection.Leave(); - - FreeTlsPage(pageInfo); - - return Result.Success; - } - } - - KernelContext.CriticalSection.Leave(); - - return result; - } - - private Result FreeTlsPage(KTlsPageInfo pageInfo) - { - Result result = MemoryManager.UnmapForKernel(pageInfo.PageVirtualAddress, 1, MemoryState.ThreadLocal); - - if (result == Result.Success) - { - KernelContext.UserSlabHeapPages.Free(pageInfo.PagePhysicalAddress); - } - - return result; - } - - private void GenerateRandomEntropy() - { - // TODO. - } - - public Result Start(int mainThreadPriority, ulong stackSize) - { - lock (_processLock) - { - if (State > ProcessState.CreatedAttached) - { - return KernelResult.InvalidState; - } - - if (ResourceLimit != null && !ResourceLimit.Reserve(LimitableResource.Thread, 1)) - { - return KernelResult.ResLimitExceeded; - } - - KResourceLimit threadResourceLimit = ResourceLimit; - KResourceLimit memoryResourceLimit = null; - - if (_mainThreadStackSize != 0) - { - throw new InvalidOperationException("Trying to start a process with a invalid state!"); - } - - ulong stackSizeRounded = BitUtils.AlignUp<ulong>(stackSize, KPageTableBase.PageSize); - - ulong neededSize = stackSizeRounded + _imageSize; - - // Check if the needed size for the code and the stack will fit on the - // memory usage capacity of this Process. Also check for possible overflow - // on the above addition. - if (neededSize > _memoryUsageCapacity || neededSize < stackSizeRounded) - { - threadResourceLimit?.Release(LimitableResource.Thread, 1); - - return KernelResult.OutOfMemory; - } - - if (stackSizeRounded != 0 && ResourceLimit != null) - { - memoryResourceLimit = ResourceLimit; - - if (!memoryResourceLimit.Reserve(LimitableResource.Memory, stackSizeRounded)) - { - threadResourceLimit?.Release(LimitableResource.Thread, 1); - - return KernelResult.ResLimitExceeded; - } - } - - Result result; - - KThread mainThread = null; - - ulong stackTop = 0; - - void CleanUpForError() - { - HandleTable.Destroy(); - - mainThread?.DecrementReferenceCount(); - - if (_mainThreadStackSize != 0) - { - ulong stackBottom = stackTop - _mainThreadStackSize; - - ulong stackPagesCount = _mainThreadStackSize / KPageTableBase.PageSize; - - MemoryManager.UnmapForKernel(stackBottom, stackPagesCount, MemoryState.Stack); - - _mainThreadStackSize = 0; - } - - memoryResourceLimit?.Release(LimitableResource.Memory, stackSizeRounded); - threadResourceLimit?.Release(LimitableResource.Thread, 1); - } - - if (stackSizeRounded != 0) - { - ulong stackPagesCount = stackSizeRounded / KPageTableBase.PageSize; - - ulong regionStart = MemoryManager.StackRegionStart; - ulong regionSize = MemoryManager.StackRegionEnd - regionStart; - - ulong regionPagesCount = regionSize / KPageTableBase.PageSize; - - result = MemoryManager.MapPages( - stackPagesCount, - KPageTableBase.PageSize, - 0, - false, - regionStart, - regionPagesCount, - MemoryState.Stack, - KMemoryPermission.ReadAndWrite, - out ulong stackBottom); - - if (result != Result.Success) - { - CleanUpForError(); - - return result; - } - - _mainThreadStackSize += stackSizeRounded; - - stackTop = stackBottom + stackSizeRounded; - } - - ulong heapCapacity = _memoryUsageCapacity - _mainThreadStackSize - _imageSize; - - result = MemoryManager.SetHeapCapacity(heapCapacity); - - if (result != Result.Success) - { - CleanUpForError(); - - return result; - } - - HandleTable = new KHandleTable(KernelContext); - - result = HandleTable.Initialize(Capabilities.HandleTableSize); - - if (result != Result.Success) - { - CleanUpForError(); - - return result; - } - - mainThread = new KThread(KernelContext); - - result = mainThread.Initialize( - _entrypoint, - 0, - stackTop, - mainThreadPriority, - DefaultCpuCore, - this, - ThreadType.User, - _customThreadStart); - - if (result != Result.Success) - { - CleanUpForError(); - - return result; - } - - result = HandleTable.GenerateHandle(mainThread, out int mainThreadHandle); - - if (result != Result.Success) - { - CleanUpForError(); - - return result; - } - - mainThread.SetEntryArguments(0, mainThreadHandle); - - ProcessState oldState = State; - ProcessState newState = State != ProcessState.Created - ? ProcessState.Attached - : ProcessState.Started; - - SetState(newState); - - result = mainThread.Start(); - - if (result != Result.Success) - { - SetState(oldState); - - CleanUpForError(); - } - - if (result == Result.Success) - { - mainThread.IncrementReferenceCount(); - } - - mainThread.DecrementReferenceCount(); - - return result; - } - } - - private void SetState(ProcessState newState) - { - if (State != newState) - { - State = newState; - _signaled = true; - - Signal(); - } - } - - public Result InitializeThread( - KThread thread, - ulong entrypoint, - ulong argsPtr, - ulong stackTop, - int priority, - int cpuCore, - ThreadStart customThreadStart = null) - { - lock (_processLock) - { - return thread.Initialize(entrypoint, argsPtr, stackTop, priority, cpuCore, this, ThreadType.User, customThreadStart); - } - } - - public IExecutionContext CreateExecutionContext() - { - return Context?.CreateExecutionContext(new ExceptionCallbacks( - InterruptHandler, - null, - KernelContext.SyscallHandler.SvcCall, - UndefinedInstructionHandler)); - } - - private void InterruptHandler(IExecutionContext context) - { - KThread currentThread = KernelStatic.GetCurrentThread(); - - if (currentThread.Context.Running && - currentThread.Owner != null && - currentThread.GetUserDisableCount() != 0 && - currentThread.Owner.PinnedThreads[currentThread.CurrentCore] == null) - { - KernelContext.CriticalSection.Enter(); - - currentThread.Owner.PinThread(currentThread); - - currentThread.SetUserInterruptFlag(); - - KernelContext.CriticalSection.Leave(); - } - - if (currentThread.IsSchedulable) - { - KernelContext.Schedulers[currentThread.CurrentCore].Schedule(); - } - - currentThread.HandlePostSyscall(); - } - - public void IncrementThreadCount() - { - Interlocked.Increment(ref _threadCount); - } - - public void DecrementThreadCountAndTerminateIfZero() - { - if (Interlocked.Decrement(ref _threadCount) == 0) - { - Terminate(); - } - } - - public void DecrementToZeroWhileTerminatingCurrent() - { - while (Interlocked.Decrement(ref _threadCount) != 0) - { - Destroy(); - TerminateCurrentProcess(); - } - - // Nintendo panic here because if it reaches this point, the current thread should be already dead. - // As we handle the death of the thread in the post SVC handler and inside the CPU emulator, we don't panic here. - } - - public ulong GetMemoryCapacity() - { - ulong totalCapacity = (ulong)ResourceLimit.GetRemainingValue(LimitableResource.Memory); - - totalCapacity += MemoryManager.GetTotalHeapSize(); - - totalCapacity += GetPersonalMmHeapSize(); - - totalCapacity += _imageSize + _mainThreadStackSize; - - if (totalCapacity <= _memoryUsageCapacity) - { - return totalCapacity; - } - - return _memoryUsageCapacity; - } - - public ulong GetMemoryUsage() - { - return _imageSize + _mainThreadStackSize + MemoryManager.GetTotalHeapSize() + GetPersonalMmHeapSize(); - } - - public ulong GetMemoryCapacityWithoutPersonalMmHeap() - { - return GetMemoryCapacity() - GetPersonalMmHeapSize(); - } - - public ulong GetMemoryUsageWithoutPersonalMmHeap() - { - return GetMemoryUsage() - GetPersonalMmHeapSize(); - } - - private ulong GetPersonalMmHeapSize() - { - return GetPersonalMmHeapSize(PersonalMmHeapPagesCount, _memRegion); - } - - private static ulong GetPersonalMmHeapSize(ulong personalMmHeapPagesCount, MemoryRegion memRegion) - { - if (memRegion == MemoryRegion.Applet) - { - return 0; - } - - return personalMmHeapPagesCount * KPageTableBase.PageSize; - } - - public void AddCpuTime(long ticks) - { - Interlocked.Add(ref _totalTimeRunning, ticks); - } - - public void AddThread(KThread thread) - { - lock (_threadingLock) - { - thread.ProcessListNode = _threads.AddLast(thread); - } - } - - public void RemoveThread(KThread thread) - { - lock (_threadingLock) - { - _threads.Remove(thread.ProcessListNode); - } - } - - public bool IsCpuCoreAllowed(int core) - { - return (Capabilities.AllowedCpuCoresMask & (1UL << core)) != 0; - } - - public bool IsPriorityAllowed(int priority) - { - return (Capabilities.AllowedThreadPriosMask & (1UL << priority)) != 0; - } - - public override bool IsSignaled() - { - return _signaled; - } - - public Result Terminate() - { - Result result; - - bool shallTerminate = false; - - KernelContext.CriticalSection.Enter(); - - lock (_processLock) - { - if (State >= ProcessState.Started) - { - if (State == ProcessState.Started || - State == ProcessState.Crashed || - State == ProcessState.Attached || - State == ProcessState.DebugSuspended) - { - SetState(ProcessState.Exiting); - - shallTerminate = true; - } - - result = Result.Success; - } - else - { - result = KernelResult.InvalidState; - } - } - - KernelContext.CriticalSection.Leave(); - - if (shallTerminate) - { - UnpauseAndTerminateAllThreadsExcept(KernelStatic.GetCurrentThread()); - - HandleTable.Destroy(); - - SignalExitToDebugTerminated(); - SignalExit(); - } - - return result; - } - - public void TerminateCurrentProcess() - { - bool shallTerminate = false; - - KernelContext.CriticalSection.Enter(); - - lock (_processLock) - { - if (State >= ProcessState.Started) - { - if (State == ProcessState.Started || - State == ProcessState.Attached || - State == ProcessState.DebugSuspended) - { - SetState(ProcessState.Exiting); - - shallTerminate = true; - } - } - } - - KernelContext.CriticalSection.Leave(); - - if (shallTerminate) - { - UnpauseAndTerminateAllThreadsExcept(KernelStatic.GetCurrentThread()); - - HandleTable.Destroy(); - - // NOTE: this is supposed to be called in receiving of the mailbox. - SignalExitToDebugExited(); - SignalExit(); - } - - KernelStatic.GetCurrentThread().Exit(); - } - - private void UnpauseAndTerminateAllThreadsExcept(KThread currentThread) - { - lock (_threadingLock) - { - KernelContext.CriticalSection.Enter(); - - if (currentThread != null && PinnedThreads[currentThread.CurrentCore] == currentThread) - { - UnpinThread(currentThread); - } - - foreach (KThread thread in _threads) - { - if (thread != currentThread && (thread.SchedFlags & ThreadSchedState.LowMask) != ThreadSchedState.TerminationPending) - { - thread.PrepareForTermination(); - } - } - - KernelContext.CriticalSection.Leave(); - } - - while (true) - { - KThread blockedThread = null; - - lock (_threadingLock) - { - foreach (KThread thread in _threads) - { - if (thread != currentThread && (thread.SchedFlags & ThreadSchedState.LowMask) != ThreadSchedState.TerminationPending) - { - thread.IncrementReferenceCount(); - - blockedThread = thread; - break; - } - } - } - - if (blockedThread == null) - { - break; - } - - blockedThread.Terminate(); - blockedThread.DecrementReferenceCount(); - } - } - - private void SignalExitToDebugTerminated() - { - // TODO: Debug events. - } - - private void SignalExitToDebugExited() - { - // TODO: Debug events. - } - - private void SignalExit() - { - if (ResourceLimit != null) - { - ResourceLimit.Release(LimitableResource.Memory, GetMemoryUsage()); - } - - KernelContext.CriticalSection.Enter(); - - SetState(ProcessState.Exited); - - KernelContext.CriticalSection.Leave(); - } - - public Result ClearIfNotExited() - { - Result result; - - KernelContext.CriticalSection.Enter(); - - lock (_processLock) - { - if (State != ProcessState.Exited && _signaled) - { - _signaled = false; - - result = Result.Success; - } - else - { - result = KernelResult.InvalidState; - } - } - - KernelContext.CriticalSection.Leave(); - - return result; - } - - private void InitializeMemoryManager(ProcessCreationFlags flags) - { - int addrSpaceBits = (flags & ProcessCreationFlags.AddressSpaceMask) switch - { - ProcessCreationFlags.AddressSpace32Bit => 32, - ProcessCreationFlags.AddressSpace64BitDeprecated => 36, - ProcessCreationFlags.AddressSpace32BitWithoutAlias => 32, - ProcessCreationFlags.AddressSpace64Bit => 39, - _ => 39 - }; - - bool for64Bit = flags.HasFlag(ProcessCreationFlags.Is64Bit); - - Context = _contextFactory.Create(KernelContext, Pid, 1UL << addrSpaceBits, InvalidAccessHandler, for64Bit); - - MemoryManager = new KPageTable(KernelContext, CpuMemory); - } - - private bool InvalidAccessHandler(ulong va) - { - KernelStatic.GetCurrentThread()?.PrintGuestStackTrace(); - KernelStatic.GetCurrentThread()?.PrintGuestRegisterPrintout(); - - Logger.Error?.Print(LogClass.Cpu, $"Invalid memory access at virtual address 0x{va:X16}."); - - return false; - } - - private void UndefinedInstructionHandler(IExecutionContext context, ulong address, int opCode) - { - KernelStatic.GetCurrentThread().PrintGuestStackTrace(); - KernelStatic.GetCurrentThread()?.PrintGuestRegisterPrintout(); - - throw new UndefinedInstructionException(address, opCode); - } - - protected override void Destroy() => Context.Dispose(); - - public Result SetActivity(bool pause) - { - KernelContext.CriticalSection.Enter(); - - if (State != ProcessState.Exiting && State != ProcessState.Exited) - { - if (pause) - { - if (IsPaused) - { - KernelContext.CriticalSection.Leave(); - - return KernelResult.InvalidState; - } - - lock (_threadingLock) - { - foreach (KThread thread in _threads) - { - thread.Suspend(ThreadSchedState.ProcessPauseFlag); - } - } - - IsPaused = true; - } - else - { - if (!IsPaused) - { - KernelContext.CriticalSection.Leave(); - - return KernelResult.InvalidState; - } - - lock (_threadingLock) - { - foreach (KThread thread in _threads) - { - thread.Resume(ThreadSchedState.ProcessPauseFlag); - } - } - - IsPaused = false; - } - - KernelContext.CriticalSection.Leave(); - - return Result.Success; - } - - KernelContext.CriticalSection.Leave(); - - return KernelResult.InvalidState; - } - - public void PinThread(KThread thread) - { - if (!thread.TerminationRequested) - { - PinnedThreads[thread.CurrentCore] = thread; - - thread.Pin(); - - KernelContext.ThreadReselectionRequested = true; - } - } - - public void UnpinThread(KThread thread) - { - if (!thread.TerminationRequested) - { - thread.Unpin(); - - PinnedThreads[thread.CurrentCore] = null; - - KernelContext.ThreadReselectionRequested = true; - } - } - - public bool IsExceptionUserThread(KThread thread) - { - // TODO - return false; - } - } -}
\ No newline at end of file |