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 UnpauseAndTerminateAllThreadsExcept(KThread currentThread) { lock (_threadingLock) { System.CriticalSection.Enter(); foreach (KThread thread in _threads) { if ((thread.SchedFlags & ThreadSchedState.LowMask) != ThreadSchedState.TerminationPending) { thread.PrepareForTermination(); } } System.CriticalSection.Leave(); } 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) { blockedThread.Terminate(); blockedThread.DecrementReferenceCount(); } }
private KernelResult CreateThread( ulong entrypoint, ulong argsPtr, ulong stackTop, int priority, int cpuCore, out int handle) { handle = 0; KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); if (cpuCore == -2) { cpuCore = currentProcess.DefaultCpuCore; } if ((uint)cpuCore >= KScheduler.CpuCoresCount || !currentProcess.IsCpuCoreAllowed(cpuCore)) { return(KernelResult.InvalidCpuCore); } if ((uint)priority >= KScheduler.PrioritiesCount || !currentProcess.IsPriorityAllowed(priority)) { return(KernelResult.InvalidPriority); } long timeout = KTimeManager.ConvertMillisecondsToNanoseconds(100); if (currentProcess.ResourceLimit != null && !currentProcess.ResourceLimit.Reserve(LimitableResource.Thread, 1, timeout)) { return(KernelResult.ResLimitExceeded); } KThread thread = new KThread(_system); KernelResult result = currentProcess.InitializeThread( thread, entrypoint, argsPtr, stackTop, priority, cpuCore); if (result != KernelResult.Success) { currentProcess.ResourceLimit?.Release(LimitableResource.Thread, 1); return(result); } result = _process.HandleTable.GenerateHandle(thread, out handle); if (result != KernelResult.Success) { thread.Terminate(); currentProcess.ResourceLimit?.Release(LimitableResource.Thread, 1); } return(result); }
public KernelResult 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(stackSize, KMemoryManager.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); } } KernelResult result; KThread mainThread = null; ulong stackTop = 0; void CleanUpForError() { mainThread?.Terminate(); HandleTable.Destroy(); if (_mainThreadStackSize != 0) { ulong stackBottom = stackTop - _mainThreadStackSize; ulong stackPagesCount = _mainThreadStackSize / KMemoryManager.PageSize; MemoryManager.UnmapForKernel(stackBottom, stackPagesCount, MemoryState.Stack); } memoryResourceLimit?.Release(LimitableResource.Memory, stackSizeRounded); threadResourceLimit?.Release(LimitableResource.Thread, 1); } if (stackSizeRounded != 0) { ulong stackPagesCount = stackSizeRounded / KMemoryManager.PageSize; ulong regionStart = MemoryManager.StackRegionStart; ulong regionSize = MemoryManager.StackRegionEnd - regionStart; ulong regionPagesCount = regionSize / KMemoryManager.PageSize; result = MemoryManager.AllocateOrMapPa( stackPagesCount, KMemoryManager.PageSize, 0, false, regionStart, regionPagesCount, MemoryState.Stack, MemoryPermission.ReadAndWrite, out ulong stackBottom); if (result != KernelResult.Success) { CleanUpForError(); return(result); } _mainThreadStackSize += stackSizeRounded; stackTop = stackBottom + stackSizeRounded; } ulong heapCapacity = _memoryUsageCapacity - _mainThreadStackSize - _imageSize; result = MemoryManager.SetHeapCapacity(heapCapacity); if (result != KernelResult.Success) { CleanUpForError(); return(result); } HandleTable = new KHandleTable(System); result = HandleTable.Initialize(Capabilities.HandleTableSize); if (result != KernelResult.Success) { CleanUpForError(); return(result); } mainThread = new KThread(System); result = mainThread.Initialize( _entrypoint, 0, stackTop, mainThreadPriority, DefaultCpuCore, this); if (result != KernelResult.Success) { CleanUpForError(); return(result); } result = HandleTable.GenerateHandle(mainThread, out int mainThreadHandle); if (result != KernelResult.Success) { CleanUpForError(); return(result); } mainThread.SetEntryArguments(0, mainThreadHandle); ProcessState oldState = _state; ProcessState newState = _state != ProcessState.Created ? ProcessState.Attached : ProcessState.Started; SetState(newState); //TODO: We can't call KThread.Start from a non-guest thread. //We will need to make some changes to allow the creation of //dummy threads that will be used to initialize the current //thread on KCoreContext so that GetCurrentThread doesn't fail. /* Result = MainThread.Start(); * * if (Result != KernelResult.Success) * { * SetState(OldState); * * CleanUpForError(); * } */ mainThread.Reschedule(ThreadSchedState.Running); return(result); } }