public static void YieldUntilCompletion(Task task) { KThread currentThread = Context.Scheduler.GetCurrentThread(); Context.CriticalSection.Enter(); currentThread.Reschedule(ThreadSchedState.Paused); task.ContinueWith((antecedent) => { currentThread.Reschedule(ThreadSchedState.Running); }); Context.CriticalSection.Leave(); }
public void SignalObject(KSynchronizationObject SyncObj) { System.CriticalSection.Enter(); if (SyncObj.IsSignaled()) { LinkedListNode <KThread> Node = SyncObj.WaitingThreads.First; while (Node != null) { KThread Thread = Node.Value; if ((Thread.SchedFlags & ThreadSchedState.LowMask) == ThreadSchedState.Paused) { Thread.SignaledObj = SyncObj; Thread.ObjSyncResult = 0; Thread.Reschedule(ThreadSchedState.Running); } Node = Node.Next; } } System.CriticalSection.Leave(); }
public void SignalObject(KSynchronizationObject syncObj) { _system.CriticalSection.Enter(); if (syncObj.IsSignaled()) { LinkedListNode <KThread> node = syncObj.WaitingThreads.First; while (node != null) { KThread thread = node.Value; if ((thread.SchedFlags & ThreadSchedState.LowMask) == ThreadSchedState.Paused) { thread.SignaledObj = syncObj; thread.ObjSyncResult = 0; thread.Reschedule(ThreadSchedState.Running); } node = node.Next; } } _system.CriticalSection.Leave(); }
public long ArbitrateLock( Process Process, AMemory Memory, int OwnerHandle, long MutexAddress, int RequesterHandle) { System.CriticalSectionLock.Lock(); KThread CurrentThread = System.Scheduler.GetCurrentThread(); CurrentThread.SignaledObj = null; CurrentThread.ObjSyncResult = 0; if (!UserToKernelInt32(Memory, MutexAddress, out int MutexValue)) { System.CriticalSectionLock.Unlock(); return(MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm));; } if (MutexValue != (OwnerHandle | HasListenersMask)) { System.CriticalSectionLock.Unlock(); return(0); } KThread MutexOwner = Process.HandleTable.GetObject <KThread>(OwnerHandle); if (MutexOwner == null) { System.CriticalSectionLock.Unlock(); return(MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle)); } CurrentThread.MutexAddress = MutexAddress; CurrentThread.ThreadHandleForUserMutex = RequesterHandle; MutexOwner.AddMutexWaiter(CurrentThread); CurrentThread.Reschedule(ThreadSchedState.Paused); System.CriticalSectionLock.Unlock(); System.CriticalSectionLock.Lock(); if (CurrentThread.MutexOwner != null) { CurrentThread.MutexOwner.RemoveMutexWaiter(CurrentThread); } System.CriticalSectionLock.Unlock(); return((uint)CurrentThread.ObjSyncResult); }
public static void Wait(Horizon System, LinkedList <KThread> ThreadList, object Mutex, long Timeout) { KThread CurrentThread = System.Scheduler.GetCurrentThread(); System.CriticalSection.Enter(); Monitor.Exit(Mutex); CurrentThread.Withholder = ThreadList; CurrentThread.Reschedule(ThreadSchedState.Paused); CurrentThread.WithholderNode = ThreadList.AddLast(CurrentThread); if (CurrentThread.ShallBeTerminated || CurrentThread.SchedFlags == ThreadSchedState.TerminationPending) { ThreadList.Remove(CurrentThread.WithholderNode); CurrentThread.Reschedule(ThreadSchedState.Running); CurrentThread.Withholder = null; System.CriticalSection.Leave(); } else { if (Timeout > 0) { System.TimeManager.ScheduleFutureInvocation(CurrentThread, Timeout); } System.CriticalSection.Leave(); if (Timeout > 0) { System.TimeManager.UnscheduleFutureInvocation(CurrentThread); } } Monitor.Enter(Mutex); }
public static void Wait(Horizon system, LinkedList <KThread> threadList, object mutex, long timeout) { KThread currentThread = system.Scheduler.GetCurrentThread(); system.CriticalSection.Enter(); Monitor.Exit(mutex); currentThread.Withholder = threadList; currentThread.Reschedule(ThreadSchedState.Paused); currentThread.WithholderNode = threadList.AddLast(currentThread); if (currentThread.ShallBeTerminated || currentThread.SchedFlags == ThreadSchedState.TerminationPending) { threadList.Remove(currentThread.WithholderNode); currentThread.Reschedule(ThreadSchedState.Running); currentThread.Withholder = null; system.CriticalSection.Leave(); } else { if (timeout > 0) { system.TimeManager.ScheduleFutureInvocation(currentThread, timeout); } system.CriticalSection.Leave(); if (timeout > 0) { system.TimeManager.UnscheduleFutureInvocation(currentThread); } } Monitor.Enter(mutex); }
public long ArbitrateLock(int ownerHandle, long mutexAddress, int requesterHandle) { KThread currentThread = _system.Scheduler.GetCurrentThread(); _system.CriticalSection.Enter(); currentThread.SignaledObj = null; currentThread.ObjSyncResult = 0; KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); if (!KernelTransfer.UserToKernelInt32(_system, mutexAddress, out int mutexValue)) { _system.CriticalSection.Leave(); return(MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm)); } if (mutexValue != (ownerHandle | HasListenersMask)) { _system.CriticalSection.Leave(); return(0); } KThread mutexOwner = currentProcess.HandleTable.GetObject <KThread>(ownerHandle); if (mutexOwner == null) { _system.CriticalSection.Leave(); return(MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle)); } currentThread.MutexAddress = mutexAddress; currentThread.ThreadHandleForUserMutex = requesterHandle; mutexOwner.AddMutexWaiter(currentThread); currentThread.Reschedule(ThreadSchedState.Paused); _system.CriticalSection.Leave(); _system.CriticalSection.Enter(); if (currentThread.MutexOwner != null) { currentThread.MutexOwner.RemoveMutexWaiter(currentThread); } _system.CriticalSection.Leave(); return((uint)currentThread.ObjSyncResult); }
public static void NotifyAll(Horizon System, LinkedList <KThread> ThreadList) { System.CriticalSection.Enter(); LinkedListNode <KThread> Node = ThreadList.First; for (; Node != null; Node = ThreadList.First) { KThread Thread = Node.Value; ThreadList.Remove(Thread.WithholderNode); Thread.Withholder = null; Thread.Reschedule(ThreadSchedState.Running); } System.CriticalSection.Leave(); }
public static void NotifyAll(Horizon system, LinkedList <KThread> threadList) { system.CriticalSection.Enter(); LinkedListNode <KThread> node = threadList.First; for (; node != null; node = threadList.First) { KThread thread = node.Value; threadList.Remove(thread.WithholderNode); thread.Withholder = null; thread.Reschedule(ThreadSchedState.Running); } system.CriticalSection.Leave(); }
private void SendSyncRequest(AThreadState ThreadState, long MessagePtr, long Size, int Handle) { KThread CurrThread = Process.GetThread(ThreadState.Tpidr); byte[] MessageData = Memory.ReadBytes(MessagePtr, Size); KSession Session = Process.HandleTable.GetObject <KSession>(Handle); if (Session != null) { //Process.Scheduler.Suspend(CurrThread); System.CriticalSectionLock.Lock(); KThread CurrentThread = System.Scheduler.GetCurrentThread(); CurrentThread.SignaledObj = null; CurrentThread.ObjSyncResult = 0; CurrentThread.Reschedule(ThreadSchedState.Paused); IpcMessage Message = new IpcMessage(MessageData, MessagePtr); ThreadPool.QueueUserWorkItem(ProcessIpcRequest, new HleIpcMessage( CurrentThread, Session, Message, MessagePtr)); System.CriticalSectionLock.Unlock(); ThreadState.X0 = (ulong)CurrentThread.ObjSyncResult; } else { Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid session handle 0x{Handle:x8}!"); ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); } }
private void SendSyncRequest(CpuThreadState threadState, long messagePtr, long size, int handle) { byte[] messageData = _memory.ReadBytes(messagePtr, size); KSession session = _process.HandleTable.GetObject <KSession>(handle); if (session != null) { _system.CriticalSection.Enter(); KThread currentThread = _system.Scheduler.GetCurrentThread(); currentThread.SignaledObj = null; currentThread.ObjSyncResult = 0; currentThread.Reschedule(ThreadSchedState.Paused); IpcMessage message = new IpcMessage(messageData, messagePtr); ThreadPool.QueueUserWorkItem(ProcessIpcRequest, new HleIpcMessage( currentThread, session, message, messagePtr)); _system.ThreadCounter.AddCount(); _system.CriticalSection.Leave(); threadState.X0 = (ulong)currentThread.ObjSyncResult; } else { Logger.PrintWarning(LogClass.KernelSvc, $"Invalid session handle 0x{handle:x8}!"); threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); } }
public long WaitProcessWideKeyAtomic( long MutexAddress, long CondVarAddress, int ThreadHandle, long Timeout) { System.CriticalSection.Enter(); KThread CurrentThread = System.Scheduler.GetCurrentThread(); CurrentThread.SignaledObj = null; CurrentThread.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.Timeout); if (CurrentThread.ShallBeTerminated || CurrentThread.SchedFlags == ThreadSchedState.TerminationPending) { System.CriticalSection.Leave(); return(MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating)); } (long Result, _) = MutexUnlock(CurrentThread, MutexAddress); if (Result != 0) { System.CriticalSection.Leave(); return(Result); } CurrentThread.MutexAddress = MutexAddress; CurrentThread.ThreadHandleForUserMutex = ThreadHandle; CurrentThread.CondVarAddress = CondVarAddress; CondVarThreads.Add(CurrentThread); if (Timeout != 0) { CurrentThread.Reschedule(ThreadSchedState.Paused); if (Timeout > 0) { System.TimeManager.ScheduleFutureInvocation(CurrentThread, Timeout); } } System.CriticalSection.Leave(); if (Timeout > 0) { System.TimeManager.UnscheduleFutureInvocation(CurrentThread); } System.CriticalSection.Enter(); if (CurrentThread.MutexOwner != null) { CurrentThread.MutexOwner.RemoveMutexWaiter(CurrentThread); } CondVarThreads.Remove(CurrentThread); System.CriticalSection.Leave(); return((uint)CurrentThread.ObjSyncResult); }
public long WaitForAddressIfLessThan(long Address, int Value, bool ShouldDecrement, long Timeout) { KThread CurrentThread = System.Scheduler.GetCurrentThread(); System.CriticalSection.Enter(); if (CurrentThread.ShallBeTerminated || CurrentThread.SchedFlags == ThreadSchedState.TerminationPending) { System.CriticalSection.Leave(); return(MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating)); } CurrentThread.SignaledObj = null; CurrentThread.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.Timeout); KProcess CurrentProcess = System.Scheduler.GetCurrentProcess(); //If ShouldDecrement is true, do atomic decrement of the value at Address. CurrentProcess.CpuMemory.SetExclusive(0, Address); if (!KernelTransfer.UserToKernelInt32(System, Address, out int CurrentValue)) { System.CriticalSection.Leave(); return(MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm)); } if (ShouldDecrement) { while (CurrentValue < Value) { if (CurrentProcess.CpuMemory.TestExclusive(0, Address)) { CurrentProcess.CpuMemory.WriteInt32(Address, CurrentValue - 1); CurrentProcess.CpuMemory.ClearExclusiveForStore(0); break; } CurrentProcess.CpuMemory.SetExclusive(0, Address); CurrentValue = CurrentProcess.CpuMemory.ReadInt32(Address); } } CurrentProcess.CpuMemory.ClearExclusive(0); if (CurrentValue < Value) { if (Timeout == 0) { System.CriticalSection.Leave(); return(MakeError(ErrorModule.Kernel, KernelErr.Timeout)); } CurrentThread.MutexAddress = Address; CurrentThread.WaitingInArbitration = true; InsertSortedByPriority(ArbiterThreads, CurrentThread); CurrentThread.Reschedule(ThreadSchedState.Paused); if (Timeout > 0) { System.TimeManager.ScheduleFutureInvocation(CurrentThread, Timeout); } System.CriticalSection.Leave(); if (Timeout > 0) { System.TimeManager.UnscheduleFutureInvocation(CurrentThread); } System.CriticalSection.Enter(); if (CurrentThread.WaitingInArbitration) { ArbiterThreads.Remove(CurrentThread); CurrentThread.WaitingInArbitration = false; } System.CriticalSection.Leave(); return(CurrentThread.ObjSyncResult); } System.CriticalSection.Leave(); return(MakeError(ErrorModule.Kernel, KernelErr.InvalidState)); }
public long WaitForAddressIfEqual(long Address, int Value, long Timeout) { KThread CurrentThread = System.Scheduler.GetCurrentThread(); System.CriticalSection.Enter(); if (CurrentThread.ShallBeTerminated || CurrentThread.SchedFlags == ThreadSchedState.TerminationPending) { System.CriticalSection.Leave(); return(MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating)); } CurrentThread.SignaledObj = null; CurrentThread.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.Timeout); if (!KernelTransfer.UserToKernelInt32(System, Address, out int CurrentValue)) { System.CriticalSection.Leave(); return(MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm)); } if (CurrentValue == Value) { if (Timeout == 0) { System.CriticalSection.Leave(); return(MakeError(ErrorModule.Kernel, KernelErr.Timeout)); } CurrentThread.MutexAddress = Address; CurrentThread.WaitingInArbitration = true; InsertSortedByPriority(ArbiterThreads, CurrentThread); CurrentThread.Reschedule(ThreadSchedState.Paused); if (Timeout > 0) { System.TimeManager.ScheduleFutureInvocation(CurrentThread, Timeout); } System.CriticalSection.Leave(); if (Timeout > 0) { System.TimeManager.UnscheduleFutureInvocation(CurrentThread); } System.CriticalSection.Enter(); if (CurrentThread.WaitingInArbitration) { ArbiterThreads.Remove(CurrentThread); CurrentThread.WaitingInArbitration = false; } System.CriticalSection.Leave(); return(CurrentThread.ObjSyncResult); } System.CriticalSection.Leave(); return(MakeError(ErrorModule.Kernel, KernelErr.InvalidState)); }
public long WaitFor(KSynchronizationObject[] SyncObjs, long Timeout, ref int HndIndex) { long Result = MakeError(ErrorModule.Kernel, KernelErr.Timeout); System.CriticalSection.Enter(); //Check if objects are already signaled before waiting. for (int Index = 0; Index < SyncObjs.Length; Index++) { if (!SyncObjs[Index].IsSignaled()) { continue; } HndIndex = Index; System.CriticalSection.Leave(); return(0); } if (Timeout == 0) { System.CriticalSection.Leave(); return(Result); } KThread CurrentThread = System.Scheduler.GetCurrentThread(); if (CurrentThread.ShallBeTerminated || CurrentThread.SchedFlags == ThreadSchedState.TerminationPending) { Result = MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating); } else if (CurrentThread.SyncCancelled) { CurrentThread.SyncCancelled = false; Result = MakeError(ErrorModule.Kernel, KernelErr.Cancelled); } else { LinkedListNode <KThread>[] SyncNodes = new LinkedListNode <KThread> [SyncObjs.Length]; for (int Index = 0; Index < SyncObjs.Length; Index++) { SyncNodes[Index] = SyncObjs[Index].AddWaitingThread(CurrentThread); } CurrentThread.WaitingSync = true; CurrentThread.SignaledObj = null; CurrentThread.ObjSyncResult = (int)Result; CurrentThread.Reschedule(ThreadSchedState.Paused); if (Timeout > 0) { System.TimeManager.ScheduleFutureInvocation(CurrentThread, Timeout); } System.CriticalSection.Leave(); CurrentThread.WaitingSync = false; if (Timeout > 0) { System.TimeManager.UnscheduleFutureInvocation(CurrentThread); } System.CriticalSection.Enter(); Result = (uint)CurrentThread.ObjSyncResult; HndIndex = -1; for (int Index = 0; Index < SyncObjs.Length; Index++) { SyncObjs[Index].RemoveWaitingThread(SyncNodes[Index]); if (SyncObjs[Index] == CurrentThread.SignaledObj) { HndIndex = Index; } } } System.CriticalSection.Leave(); return(Result); }
public long WaitFor(KSynchronizationObject[] syncObjs, long timeout, ref int hndIndex) { long result = MakeError(ErrorModule.Kernel, KernelErr.Timeout); _system.CriticalSection.Enter(); //Check if objects are already signaled before waiting. for (int index = 0; index < syncObjs.Length; index++) { if (!syncObjs[index].IsSignaled()) { continue; } hndIndex = index; _system.CriticalSection.Leave(); return(0); } if (timeout == 0) { _system.CriticalSection.Leave(); return(result); } KThread currentThread = _system.Scheduler.GetCurrentThread(); if (currentThread.ShallBeTerminated || currentThread.SchedFlags == ThreadSchedState.TerminationPending) { result = MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating); } else if (currentThread.SyncCancelled) { currentThread.SyncCancelled = false; result = MakeError(ErrorModule.Kernel, KernelErr.Cancelled); } else { LinkedListNode <KThread>[] syncNodes = new LinkedListNode <KThread> [syncObjs.Length]; for (int index = 0; index < syncObjs.Length; index++) { syncNodes[index] = syncObjs[index].AddWaitingThread(currentThread); } currentThread.WaitingSync = true; currentThread.SignaledObj = null; currentThread.ObjSyncResult = (int)result; currentThread.Reschedule(ThreadSchedState.Paused); if (timeout > 0) { _system.TimeManager.ScheduleFutureInvocation(currentThread, timeout); } _system.CriticalSection.Leave(); currentThread.WaitingSync = false; if (timeout > 0) { _system.TimeManager.UnscheduleFutureInvocation(currentThread); } _system.CriticalSection.Enter(); result = (uint)currentThread.ObjSyncResult; hndIndex = -1; for (int index = 0; index < syncObjs.Length; index++) { syncObjs[index].RemoveWaitingThread(syncNodes[index]); if (syncObjs[index] == currentThread.SignaledObj) { hndIndex = index; } } } _system.CriticalSection.Leave(); return(result); }
public long WaitProcessWideKeyAtomic( long mutexAddress, long condVarAddress, int threadHandle, long timeout) { _system.CriticalSection.Enter(); KThread currentThread = _system.Scheduler.GetCurrentThread(); currentThread.SignaledObj = null; currentThread.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.Timeout); if (currentThread.ShallBeTerminated || currentThread.SchedFlags == ThreadSchedState.TerminationPending) { _system.CriticalSection.Leave(); return(MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating)); } (long result, _) = MutexUnlock(currentThread, mutexAddress); if (result != 0) { _system.CriticalSection.Leave(); return(result); } currentThread.MutexAddress = mutexAddress; currentThread.ThreadHandleForUserMutex = threadHandle; currentThread.CondVarAddress = condVarAddress; CondVarThreads.Add(currentThread); if (timeout != 0) { currentThread.Reschedule(ThreadSchedState.Paused); if (timeout > 0) { _system.TimeManager.ScheduleFutureInvocation(currentThread, timeout); } } _system.CriticalSection.Leave(); if (timeout > 0) { _system.TimeManager.UnscheduleFutureInvocation(currentThread); } _system.CriticalSection.Enter(); if (currentThread.MutexOwner != null) { currentThread.MutexOwner.RemoveMutexWaiter(currentThread); } CondVarThreads.Remove(currentThread); _system.CriticalSection.Leave(); return((uint)currentThread.ObjSyncResult); }
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); } }