public long SignalAndIncrementIfEqual(AMemory Memory, long Address, int Value, int Count) { System.CriticalSectionLock.Lock(); Memory.SetExclusive(0, Address); if (!UserToKernelInt32(Memory, Address, out int CurrentValue)) { System.CriticalSectionLock.Unlock(); return(MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm)); } while (CurrentValue == Value) { if (Memory.TestExclusive(0, Address)) { Memory.WriteInt32(Address, CurrentValue + 1); Memory.ClearExclusiveForStore(0); break; } Memory.SetExclusive(0, Address); CurrentValue = Memory.ReadInt32(Address); } Memory.ClearExclusive(0); if (CurrentValue != Value) { System.CriticalSectionLock.Unlock(); return(MakeError(ErrorModule.Kernel, KernelErr.InvalidState)); } WakeArbiterThreads(Address, Count); System.CriticalSectionLock.Unlock(); return(0); }
public long SignalAndModifyIfEqual(AMemory Memory, long Address, int Value, int Count) { System.CriticalSectionLock.Lock(); int Offset; //The value is decremented if the number of threads waiting is less //or equal to the Count of threads to be signaled, or Count is zero //or negative. It is incremented if there are no threads waiting. int WaitingCount = 0; foreach (KThread Thread in ArbiterThreads.Where(x => x.MutexAddress == Address)) { if (++WaitingCount > Count) { break; } } if (WaitingCount > 0) { Offset = WaitingCount <= Count || Count <= 0 ? -1 : 0; } else { Offset = 1; } Memory.SetExclusive(0, Address); if (!UserToKernelInt32(Memory, Address, out int CurrentValue)) { System.CriticalSectionLock.Unlock(); return(MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm)); } while (CurrentValue == Value) { if (Memory.TestExclusive(0, Address)) { Memory.WriteInt32(Address, CurrentValue + Offset); Memory.ClearExclusiveForStore(0); break; } Memory.SetExclusive(0, Address); CurrentValue = Memory.ReadInt32(Address); } Memory.ClearExclusive(0); if (CurrentValue != Value) { System.CriticalSectionLock.Unlock(); return(MakeError(ErrorModule.Kernel, KernelErr.InvalidState)); } WakeArbiterThreads(Address, Count); System.CriticalSectionLock.Unlock(); return(0); }
public long WaitForAddressIfLessThan( AMemory Memory, long Address, int Value, bool ShouldDecrement, long Timeout) { KThread CurrentThread = System.Scheduler.GetCurrentThread(); System.CriticalSectionLock.Lock(); if (CurrentThread.ShallBeTerminated || CurrentThread.SchedFlags == ThreadSchedState.TerminationPending) { System.CriticalSectionLock.Unlock(); return(MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating)); } CurrentThread.SignaledObj = null; CurrentThread.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.Timeout); //If ShouldDecrement is true, do atomic decrement of the value at Address. Memory.SetExclusive(0, Address); if (!UserToKernelInt32(Memory, Address, out int CurrentValue)) { System.CriticalSectionLock.Unlock(); return(MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm)); } if (ShouldDecrement) { while (CurrentValue < Value) { if (Memory.TestExclusive(0, Address)) { Memory.WriteInt32(Address, CurrentValue - 1); Memory.ClearExclusiveForStore(0); break; } Memory.SetExclusive(0, Address); CurrentValue = Memory.ReadInt32(Address); } } Memory.ClearExclusive(0); if (CurrentValue < Value) { if (Timeout == 0) { System.CriticalSectionLock.Unlock(); 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.CriticalSectionLock.Unlock(); if (Timeout > 0) { System.TimeManager.UnscheduleFutureInvocation(CurrentThread); } System.CriticalSectionLock.Lock(); if (CurrentThread.WaitingInArbitration) { ArbiterThreads.Remove(CurrentThread); CurrentThread.WaitingInArbitration = false; } System.CriticalSectionLock.Unlock(); return(CurrentThread.ObjSyncResult); } System.CriticalSectionLock.Unlock(); return(MakeError(ErrorModule.Kernel, KernelErr.InvalidState)); }
private KThread TryAcquireMutex(Process Process, AMemory Memory, KThread Requester) { long Address = Requester.MutexAddress; Memory.SetExclusive(0, Address); if (!UserToKernelInt32(Memory, Address, out int MutexValue)) { //Invalid address. Memory.ClearExclusive(0); Requester.SignaledObj = null; Requester.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); return(null); } while (true) { if (Memory.TestExclusive(0, Address)) { if (MutexValue != 0) { //Update value to indicate there is a mutex waiter now. Memory.WriteInt32(Address, MutexValue | HasListenersMask); } else { //No thread owning the mutex, assign to requesting thread. Memory.WriteInt32(Address, Requester.ThreadHandleForUserMutex); } Memory.ClearExclusiveForStore(0); break; } Memory.SetExclusive(0, Address); MutexValue = Memory.ReadInt32(Address); } if (MutexValue == 0) { //We now own the mutex. Requester.SignaledObj = null; Requester.ObjSyncResult = 0; Requester.ReleaseAndResume(); return(null); } MutexValue &= ~HasListenersMask; KThread MutexOwner = Process.HandleTable.GetObject <KThread>(MutexValue); if (MutexOwner != null) { //Mutex already belongs to another thread, wait for it. MutexOwner.AddMutexWaiter(Requester); } else { //Invalid mutex owner. Requester.SignaledObj = null; Requester.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); Requester.ReleaseAndResume(); } return(MutexOwner); }