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); }
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); }
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); }