예제 #1
0
        private bool CondVarWait(
            KThread WaitThread,
            int WaitThreadHandle,
            long MutexAddress,
            long CondVarAddress,
            ulong Timeout)
        {
            WaitThread.WaitHandle     = WaitThreadHandle;
            WaitThread.MutexAddress   = MutexAddress;
            WaitThread.CondVarAddress = CondVarAddress;

            lock (CondVarLock)
            {
                KThread CurrThread = Process.ThreadArbiterList;

                if (CurrThread != null)
                {
                    bool DoInsert = CurrThread != WaitThread;

                    while (CurrThread.NextCondVarThread != null)
                    {
                        if (CurrThread.NextCondVarThread.ActualPriority < WaitThread.ActualPriority)
                        {
                            break;
                        }

                        CurrThread = CurrThread.NextCondVarThread;

                        DoInsert &= CurrThread != WaitThread;
                    }

                    //Only insert if the node doesn't already exist in the list.
                    //This prevents circular references.
                    if (DoInsert)
                    {
                        if (WaitThread.NextCondVarThread != null)
                        {
                            throw new InvalidOperationException();
                        }

                        WaitThread.NextCondVarThread = CurrThread.NextCondVarThread;
                        CurrThread.NextCondVarThread = WaitThread;
                    }
                }
                else
                {
                    Process.ThreadArbiterList = WaitThread;
                }
            }

            if (Timeout != ulong.MaxValue)
            {
                return(Process.Scheduler.EnterWait(WaitThread, NsTimeConverter.GetTimeMs(Timeout)));
            }
            else
            {
                return(Process.Scheduler.EnterWait(WaitThread));
            }
        }
예제 #2
0
        private void SvcWaitSynchronization(AThreadState ThreadState)
        {
            long  HandlesPtr   = (long)ThreadState.X1;
            int   HandlesCount = (int)ThreadState.X2;
            ulong Timeout      = ThreadState.X3;

            KThread CurrThread = Process.GetThread(ThreadState.Tpidr);

            WaitHandle[] Handles = new WaitHandle[HandlesCount];

            for (int Index = 0; Index < HandlesCount; Index++)
            {
                int Handle = Memory.ReadInt32(HandlesPtr + Index * 4);

                KSynchronizationObject SyncObj = Process.HandleTable.GetData <KSynchronizationObject>(Handle);

                if (SyncObj == null)
                {
                    Logging.Warn(LogClass.KernelSvc, $"Tried to WaitSynchronization on invalid handle 0x{Handle:x8}!");

                    ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);

                    return;
                }

                Handles[Index] = SyncObj.WaitEvent;
            }

            Process.Scheduler.Suspend(CurrThread.ProcessorId);

            int HandleIndex;

            ulong Result = 0;

            if (Timeout != ulong.MaxValue)
            {
                HandleIndex = WaitHandle.WaitAny(Handles, NsTimeConverter.GetTimeMs(Timeout));

                if (HandleIndex == WaitHandle.WaitTimeout)
                {
                    Result = MakeError(ErrorModule.Kernel, KernelErr.Timeout);
                }
            }
            else
            {
                HandleIndex = WaitHandle.WaitAny(Handles);
            }

            Process.Scheduler.Resume(CurrThread);

            ThreadState.X0 = Result;

            if (Result == 0)
            {
                ThreadState.X1 = (ulong)HandleIndex;
            }
        }
예제 #3
0
        private void SvcSleepThread(AThreadState ThreadState)
        {
            ulong Ns = ThreadState.X0;

            KThread CurrThread = Process.GetThread(ThreadState.Tpidr);

            if (Ns == 0)
            {
                Process.Scheduler.Yield(CurrThread);
            }
            else
            {
                Process.Scheduler.Suspend(CurrThread.ProcessorId);

                Thread.Sleep(NsTimeConverter.GetTimeMs(Ns));

                Process.Scheduler.Resume(CurrThread);
            }
        }
예제 #4
0
        private void SvcSleepThread(AThreadState ThreadState)
        {
            ulong TimeoutNs = ThreadState.X0;

            KThread CurrThread = Process.GetThread(ThreadState.Tpidr);

            if (TimeoutNs == 0)
            {
                Process.Scheduler.SetReschedule(CurrThread.ActualCore);
            }
            else
            {
                Process.Scheduler.Suspend(CurrThread);

                Thread.Sleep(NsTimeConverter.GetTimeMs(TimeoutNs));

                Process.Scheduler.Resume(CurrThread);
            }
        }
예제 #5
0
        private bool CondVarWait(
            KThread WaitThread,
            int WaitThreadHandle,
            long MutexAddress,
            long CondVarAddress,
            ulong Timeout)
        {
            WaitThread.WaitHandle     = WaitThreadHandle;
            WaitThread.MutexAddress   = MutexAddress;
            WaitThread.CondVarAddress = CondVarAddress;

            lock (Process.ThreadArbiterList)
            {
                WaitThread.CondVarSignaled = false;

                Process.ThreadArbiterList.Add(WaitThread);
            }

            Ns.Log.PrintDebug(LogClass.KernelSvc, "Entering wait state...");

            if (Timeout != ulong.MaxValue)
            {
                Process.Scheduler.EnterWait(WaitThread, NsTimeConverter.GetTimeMs(Timeout));

                lock (Process.ThreadArbiterList)
                {
                    if (!WaitThread.CondVarSignaled)
                    {
                        Process.ThreadArbiterList.Remove(WaitThread);

                        return(false);
                    }
                }
            }
            else
            {
                Process.Scheduler.EnterWait(WaitThread);
            }

            return(true);
        }
예제 #6
0
        private void SvcWaitSynchronization(AThreadState ThreadState)
        {
            long  HandlesPtr   = (long)ThreadState.X1;
            int   HandlesCount = (int)ThreadState.X2;
            ulong Timeout      = ThreadState.X3;

            Ns.Log.PrintDebug(LogClass.KernelSvc,
                              "HandlesPtr = " + HandlesPtr.ToString("x16") + ", " +
                              "HandlesCount = " + HandlesCount.ToString("x8") + ", " +
                              "Timeout = " + Timeout.ToString("x16"));

            if ((uint)HandlesCount > 0x40)
            {
                ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.CountOutOfRange);

                return;
            }

            KThread CurrThread = Process.GetThread(ThreadState.Tpidr);

            WaitHandle[] Handles = new WaitHandle[HandlesCount + 1];

            for (int Index = 0; Index < HandlesCount; Index++)
            {
                int Handle = Memory.ReadInt32(HandlesPtr + Index * 4);

                KSynchronizationObject SyncObj = Process.HandleTable.GetData <KSynchronizationObject>(Handle);

                if (SyncObj == null)
                {
                    Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid handle 0x{Handle:x8}!");

                    ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);

                    return;
                }

                Handles[Index] = SyncObj.WaitEvent;
            }

            using (AutoResetEvent WaitEvent = new AutoResetEvent(false))
            {
                if (!SyncWaits.TryAdd(CurrThread, WaitEvent))
                {
                    throw new InvalidOperationException();
                }

                Handles[HandlesCount] = WaitEvent;

                Process.Scheduler.Suspend(CurrThread);

                int HandleIndex;

                ulong Result = 0;

                if (Timeout != ulong.MaxValue)
                {
                    HandleIndex = WaitHandle.WaitAny(Handles, NsTimeConverter.GetTimeMs(Timeout));
                }
                else
                {
                    HandleIndex = WaitHandle.WaitAny(Handles);
                }

                if (HandleIndex == WaitHandle.WaitTimeout)
                {
                    Result = MakeError(ErrorModule.Kernel, KernelErr.Timeout);
                }
                else if (HandleIndex == HandlesCount)
                {
                    Result = MakeError(ErrorModule.Kernel, KernelErr.Canceled);
                }

                SyncWaits.TryRemove(CurrThread, out _);

                Process.Scheduler.Resume(CurrThread);

                ThreadState.X0 = Result;

                if (Result == 0)
                {
                    ThreadState.X1 = (ulong)HandleIndex;
                }
            }
        }