public KernelResult ArbitrateUnlock(ulong mutexAddress) { _context.CriticalSection.Enter(); KThread currentThread = KernelStatic.GetCurrentThread(); (int mutexValue, KThread newOwnerThread) = MutexUnlock(currentThread, mutexAddress); KernelResult result = KernelResult.Success; if (!KernelTransfer.KernelToUserInt32(_context, mutexAddress, mutexValue)) { result = KernelResult.InvalidMemState; } if (result != KernelResult.Success && newOwnerThread != null) { newOwnerThread.SignaledObj = null; newOwnerThread.ObjSyncResult = result; } _context.CriticalSection.Leave(); return(result); }
private (KernelResult, KThread) MutexUnlock(KThread currentThread, ulong mutexAddress) { KThread newOwnerThread = currentThread.RelinquishMutex(mutexAddress, out int count); int mutexValue = 0; if (newOwnerThread != null) { mutexValue = newOwnerThread.ThreadHandleForUserMutex; if (count >= 2) { mutexValue |= HasListenersMask; } newOwnerThread.SignaledObj = null; newOwnerThread.ObjSyncResult = KernelResult.Success; newOwnerThread.ReleaseAndResume(); } KernelResult result = KernelResult.Success; if (!KernelTransfer.KernelToUserInt32(_context, mutexAddress, mutexValue)) { result = KernelResult.InvalidMemState; } return(result, newOwnerThread); }
public KernelResult SignalAndIncrementIfEqual(ulong address, int value, int count) { _system.CriticalSection.Enter(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); int currentValue; do { if (!KernelTransfer.UserToKernelInt32(_system, address, out currentValue)) { _system.CriticalSection.Leave(); return(KernelResult.InvalidMemState); } if (currentValue != value) { _system.CriticalSection.Leave(); return(KernelResult.InvalidState); } }while (!currentProcess.CpuMemory.AtomicCompareExchangeInt32((long)address, currentValue, currentValue + 1)); WakeArbiterThreads(address, count); _system.CriticalSection.Leave(); return(KernelResult.Success); }
public KernelResult SignalAndModifyIfEqual(ulong address, int value, int count) { _system.CriticalSection.Enter(); 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; } KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); int currentValue; do { if (!KernelTransfer.UserToKernelInt32(_system, address, out currentValue)) { _system.CriticalSection.Leave(); return(KernelResult.InvalidMemState); } if (currentValue != value) { _system.CriticalSection.Leave(); return(KernelResult.InvalidState); } }while (!currentProcess.CpuMemory.AtomicCompareExchangeInt32((long)address, currentValue, currentValue + offset)); WakeArbiterThreads(address, count); _system.CriticalSection.Leave(); return(KernelResult.Success); }
public KernelResult ArbitrateLock(int ownerHandle, ulong mutexAddress, int requesterHandle) { KThread currentThread = KernelStatic.GetCurrentThread(); _context.CriticalSection.Enter(); currentThread.SignaledObj = null; currentThread.ObjSyncResult = KernelResult.Success; KProcess currentProcess = KernelStatic.GetCurrentProcess(); if (!KernelTransfer.UserToKernelInt32(_context, mutexAddress, out int mutexValue)) { _context.CriticalSection.Leave(); return(KernelResult.InvalidMemState); } if (mutexValue != (ownerHandle | HasListenersMask)) { _context.CriticalSection.Leave(); return(0); } KThread mutexOwner = currentProcess.HandleTable.GetObject <KThread>(ownerHandle); if (mutexOwner == null) { _context.CriticalSection.Leave(); return(KernelResult.InvalidHandle); } currentThread.MutexAddress = mutexAddress; currentThread.ThreadHandleForUserMutex = requesterHandle; mutexOwner.AddMutexWaiter(currentThread); currentThread.Reschedule(ThreadSchedState.Paused); _context.CriticalSection.Leave(); _context.CriticalSection.Enter(); if (currentThread.MutexOwner != null) { currentThread.MutexOwner.RemoveMutexWaiter(currentThread); } _context.CriticalSection.Leave(); return(currentThread.ObjSyncResult); }
public void SignalProcessWideKey(ulong address, int count) { _context.CriticalSection.Enter(); WakeThreads(_condVarThreads, count, TryAcquireMutex, x => x.CondVarAddress == address); if (!_condVarThreads.Any(x => x.CondVarAddress == address)) { KernelTransfer.KernelToUserInt32(_context, address, 0); } _context.CriticalSection.Leave(); }
private KernelResult GetProcessList(ulong address, int maxCount, out int count) { count = 0; if ((maxCount >> 28) != 0) { return(KernelResult.MaximumExceeded); } if (maxCount != 0) { KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); ulong copySize = (ulong)maxCount * 8; if (address + copySize <= address) { return(KernelResult.InvalidMemState); } if (currentProcess.MemoryManager.OutsideAddrSpace(address, copySize)) { return(KernelResult.InvalidMemState); } } int copyCount = 0; lock (_system.Processes) { foreach (KProcess process in _system.Processes.Values) { if (copyCount < maxCount) { if (!KernelTransfer.KernelToUserInt64(_system, address + (ulong)copyCount * 8, process.Pid)) { return(KernelResult.UserCopyFailed); } } copyCount++; } } count = copyCount; return(KernelResult.Success); }
public KernelResult SignalAndIncrementIfEqual(ulong address, int value, int count) { _system.CriticalSection.Enter(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); currentProcess.CpuMemory.SetExclusive(0, (long)address); if (!KernelTransfer.UserToKernelInt32(_system, address, out int currentValue)) { _system.CriticalSection.Leave(); return(KernelResult.InvalidMemState); } while (currentValue == value) { if (currentProcess.CpuMemory.TestExclusive(0, (long)address)) { currentProcess.CpuMemory.WriteInt32((long)address, currentValue + 1); currentProcess.CpuMemory.ClearExclusiveForStore(0); break; } currentProcess.CpuMemory.SetExclusive(0, (long)address); currentValue = currentProcess.CpuMemory.ReadInt32((long)address); } currentProcess.CpuMemory.ClearExclusive(0); if (currentValue != value) { _system.CriticalSection.Leave(); return(KernelResult.InvalidState); } WakeArbiterThreads(address, count); _system.CriticalSection.Leave(); return(KernelResult.Success); }
private KernelResult ConnectToNamedPort(ulong namePtr, out int handle) { handle = 0; if (!KernelTransfer.UserToKernelString(_system, namePtr, 12, out string name)) { return(KernelResult.UserCopyFailed); } if (name.Length > 11) { return(KernelResult.MaximumExceeded); } KAutoObject autoObj = KAutoObject.FindNamedObject(_system, name); if (!(autoObj is KClientPort clientPort)) { return(KernelResult.NotFound); } KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KernelResult result = currentProcess.HandleTable.ReserveHandle(out handle); if (result != KernelResult.Success) { return(result); } result = clientPort.Connect(out KClientSession clientSession); if (result != KernelResult.Success) { currentProcess.HandleTable.CancelHandleReservation(handle); return(result); } currentProcess.HandleTable.SetReservedHandleObj(handle, clientSession); clientSession.DecrementReferenceCount(); return(result); }
private KernelResult ManageNamedPort(ulong namePtr, int maxSessions, out int handle) { handle = 0; if (!KernelTransfer.UserToKernelString(_system, namePtr, 12, out string name)) { return(KernelResult.UserCopyFailed); } if (maxSessions < 0 || name.Length > 11) { return(KernelResult.MaximumExceeded); } if (maxSessions == 0) { return(KClientPort.RemoveName(_system, name)); } KPort port = new KPort(_system); KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KernelResult result = currentProcess.HandleTable.GenerateHandle(port.ServerPort, out handle); if (result != KernelResult.Success) { return(result); } port.Initialize(maxSessions, false, 0); result = port.SetName(name); if (result != KernelResult.Success) { currentProcess.HandleTable.CloseHandle(handle); } return(result); }
public KernelResult ReplyAndReceive64( ulong handlesPtr, int handlesCount, int replyTargetHandle, long timeout, out int handleIndex) { handleIndex = 0; if ((uint)handlesCount > 0x40) { return(KernelResult.MaximumExceeded); } KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); ulong copySize = (ulong)((long)handlesCount * 4); if (!currentProcess.MemoryManager.InsideAddrSpace(handlesPtr, copySize)) { return(KernelResult.UserCopyFailed); } if (handlesPtr + copySize < handlesPtr) { return(KernelResult.UserCopyFailed); } int[] handles = new int[handlesCount]; if (!KernelTransfer.UserToKernelInt32Array(_system, handlesPtr, handles)) { return(KernelResult.UserCopyFailed); } KSynchronizationObject[] syncObjs = new KSynchronizationObject[handlesCount]; for (int index = 0; index < handlesCount; index++) { KSynchronizationObject obj = currentProcess.HandleTable.GetObject <KSynchronizationObject>(handles[index]); if (obj == null) { return(KernelResult.InvalidHandle); } syncObjs[index] = obj; } KernelResult result; if (replyTargetHandle != 0) { KServerSession replyTarget = currentProcess.HandleTable.GetObject <KServerSession>(replyTargetHandle); if (replyTarget == null) { return(KernelResult.InvalidHandle); } result = replyTarget.Reply(); if (result != KernelResult.Success) { return(result); } } while ((result = _system.Synchronization.WaitFor(syncObjs, timeout, out handleIndex)) == KernelResult.Success) { KServerSession session = currentProcess.HandleTable.GetObject <KServerSession>(handles[handleIndex]); if (session == null) { break; } if ((result = session.Receive()) != KernelResult.NotFound) { break; } } return(result); }
public KernelResult WaitForAddressIfLessThan( ulong 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(KernelResult.ThreadTerminating); } currentThread.SignaledObj = null; currentThread.ObjSyncResult = KernelResult.TimedOut; KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); if (!KernelTransfer.UserToKernelInt32(_system, address, out int currentValue)) { _system.CriticalSection.Leave(); return(KernelResult.InvalidMemState); } if (shouldDecrement) { currentValue = currentProcess.CpuMemory.AtomicDecrementInt32((long)address) + 1; } if (currentValue < value) { if (timeout == 0) { _system.CriticalSection.Leave(); return(KernelResult.TimedOut); } 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((KernelResult)currentThread.ObjSyncResult); } _system.CriticalSection.Leave(); return(KernelResult.InvalidState); }
private KThread TryAcquireMutex(KThread requester) { ulong address = requester.MutexAddress; KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); int mutexValue, newMutexValue; do { if (!KernelTransfer.UserToKernelInt32(_system, address, out mutexValue)) { // Invalid address. requester.SignaledObj = null; requester.ObjSyncResult = KernelResult.InvalidMemState; return(null); } if (mutexValue != 0) { // Update value to indicate there is a mutex waiter now. newMutexValue = mutexValue | HasListenersMask; } else { // No thread owning the mutex, assign to requesting thread. newMutexValue = requester.ThreadHandleForUserMutex; } }while (!currentProcess.CpuMemory.AtomicCompareExchangeInt32((long)address, mutexValue, newMutexValue)); if (mutexValue == 0) { // We now own the mutex. requester.SignaledObj = null; requester.ObjSyncResult = KernelResult.Success; requester.ReleaseAndResume(); return(null); } mutexValue &= ~HasListenersMask; KThread mutexOwner = currentProcess.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 = KernelResult.InvalidHandle; requester.ReleaseAndResume(); } return(mutexOwner); }
public KernelResult WaitProcessWideKeyAtomic(ulong mutexAddress, ulong condVarAddress, int threadHandle, long timeout) { _context.CriticalSection.Enter(); KThread currentThread = KernelStatic.GetCurrentThread(); currentThread.SignaledObj = null; currentThread.ObjSyncResult = KernelResult.TimedOut; if (currentThread.ShallBeTerminated || currentThread.SchedFlags == ThreadSchedState.TerminationPending) { _context.CriticalSection.Leave(); return(KernelResult.ThreadTerminating); } (int mutexValue, _) = MutexUnlock(currentThread, mutexAddress); KernelTransfer.KernelToUserInt32(_context, condVarAddress, 1); if (!KernelTransfer.KernelToUserInt32(_context, mutexAddress, mutexValue)) { _context.CriticalSection.Leave(); return(KernelResult.InvalidMemState); } currentThread.MutexAddress = mutexAddress; currentThread.ThreadHandleForUserMutex = threadHandle; currentThread.CondVarAddress = condVarAddress; _condVarThreads.Add(currentThread); if (timeout != 0) { currentThread.Reschedule(ThreadSchedState.Paused); if (timeout > 0) { _context.TimeManager.ScheduleFutureInvocation(currentThread, timeout); } } _context.CriticalSection.Leave(); if (timeout > 0) { _context.TimeManager.UnscheduleFutureInvocation(currentThread); } _context.CriticalSection.Enter(); if (currentThread.MutexOwner != null) { currentThread.MutexOwner.RemoveMutexWaiter(currentThread); } _condVarThreads.Remove(currentThread); _context.CriticalSection.Leave(); return(currentThread.ObjSyncResult); }
private KThread TryAcquireMutex(KThread requester) { ulong address = requester.MutexAddress; KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); currentProcess.CpuMemory.SetExclusive(0, (long)address); if (!KernelTransfer.UserToKernelInt32(_system, address, out int mutexValue)) { //Invalid address. currentProcess.CpuMemory.ClearExclusive(0); requester.SignaledObj = null; requester.ObjSyncResult = KernelResult.InvalidMemState; return(null); } while (true) { if (currentProcess.CpuMemory.TestExclusive(0, (long)address)) { if (mutexValue != 0) { //Update value to indicate there is a mutex waiter now. currentProcess.CpuMemory.WriteInt32((long)address, mutexValue | HasListenersMask); } else { //No thread owning the mutex, assign to requesting thread. currentProcess.CpuMemory.WriteInt32((long)address, requester.ThreadHandleForUserMutex); } currentProcess.CpuMemory.ClearExclusiveForStore(0); break; } currentProcess.CpuMemory.SetExclusive(0, (long)address); mutexValue = currentProcess.CpuMemory.ReadInt32((long)address); } if (mutexValue == 0) { //We now own the mutex. requester.SignaledObj = null; requester.ObjSyncResult = KernelResult.Success; requester.ReleaseAndResume(); return(null); } mutexValue &= ~HasListenersMask; KThread mutexOwner = currentProcess.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 = KernelResult.InvalidHandle; requester.ReleaseAndResume(); } return(mutexOwner); }