Esempio n. 1
0
        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);
        }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
        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);
        }
Esempio n. 4
0
        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);
        }
Esempio n. 5
0
        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);
        }
Esempio n. 6
0
        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();
        }
Esempio n. 7
0
        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);
        }
Esempio n. 8
0
        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);
        }
Esempio n. 9
0
        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);
        }
Esempio n. 10
0
        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);
        }
Esempio n. 11
0
        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);
        }
Esempio n. 12
0
        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);
        }
Esempio n. 13
0
        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);
        }
Esempio n. 14
0
        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);
        }
Esempio n. 15
0
        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);
        }