コード例 #1
0
        public static ulong WaitForAddressIfLessThan(Process Process,
                                                     AThreadState ThreadState,
                                                     AMemory Memory,
                                                     long Address,
                                                     int Value,
                                                     ulong Timeout,
                                                     bool ShouldDecrement)
        {
            Memory.SetExclusive(ThreadState, Address);

            int CurrentValue = Memory.ReadInt32(Address);

            while (true)
            {
                if (Memory.TestExclusive(ThreadState, Address))
                {
                    if (CurrentValue < Value)
                    {
                        if (ShouldDecrement)
                        {
                            Memory.WriteInt32(Address, CurrentValue - 1);
                        }

                        Memory.ClearExclusiveForStore(ThreadState);
                    }
                    else
                    {
                        Memory.ClearExclusiveForStore(ThreadState);

                        return(MakeError(ErrorModule.Kernel, KernelErr.InvalidState));
                    }

                    break;
                }

                Memory.SetExclusive(ThreadState, Address);

                CurrentValue = Memory.ReadInt32(Address);
            }

            if (Timeout == 0)
            {
                return(MakeError(ErrorModule.Kernel, KernelErr.Timeout));
            }

            return(WaitForAddress(Process, ThreadState, Address, Timeout));
        }
コード例 #2
0
ファイル: KAddressArbiter.cs プロジェクト: simontime/Ryujinx
        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);
        }
コード例 #3
0
        private KThread TryAcquireMutex(Process Process, AMemory Memory, KThread Requester)
        {
            int Core = Requester.CurrentCore;

            long Address = Requester.MutexAddress;

            Memory.SetExclusive(Core, Address);

            int MutexValue = Memory.ReadInt32(Address);

            while (MutexValue != 0)
            {
                if (Memory.TestExclusive(Core, 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(Core);

                    break;
                }

                Memory.SetExclusive(Core, 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.GetData <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);
        }
コード例 #4
0
ファイル: KAddressArbiter.cs プロジェクト: simontime/Ryujinx
        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);
        }
コード例 #5
0
ファイル: KAddressArbiter.cs プロジェクト: simontime/Ryujinx
        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));
        }