| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- using Ryujinx.Core.OsHle.Handles;
- using System.Collections.Generic;
- using System.Threading;
- namespace Ryujinx.Core.OsHle.Kernel
- {
- class ConditionVariable
- {
- private Process Process;
- private long CondVarAddress;
- private bool OwnsCondVarValue;
- private List<(KThread Thread, AutoResetEvent WaitEvent)> WaitingThreads;
- public ConditionVariable(Process Process, long CondVarAddress)
- {
- this.Process = Process;
- this.CondVarAddress = CondVarAddress;
- WaitingThreads = new List<(KThread, AutoResetEvent)>();
- }
- public bool WaitForSignal(KThread Thread, ulong Timeout)
- {
- bool Result = true;
- int Count = Process.Memory.ReadInt32(CondVarAddress);
- if (Count <= 0)
- {
- using (AutoResetEvent WaitEvent = new AutoResetEvent(false))
- {
- lock (WaitingThreads)
- {
- WaitingThreads.Add((Thread, WaitEvent));
- }
- if (Timeout == ulong.MaxValue)
- {
- Result = WaitEvent.WaitOne();
- }
- else
- {
- Result = WaitEvent.WaitOne(NsTimeConverter.GetTimeMs(Timeout));
- lock (WaitingThreads)
- {
- WaitingThreads.Remove((Thread, WaitEvent));
- }
- }
- }
- }
- AcquireCondVarValue();
- Count = Process.Memory.ReadInt32(CondVarAddress);
- if (Result && Count > 0)
- {
- Process.Memory.WriteInt32(CondVarAddress, Count - 1);
- }
- ReleaseCondVarValue();
- return Result;
- }
- public void SetSignal(KThread Thread, int Count)
- {
- lock (WaitingThreads)
- {
- if (Count < 0)
- {
- foreach ((_, AutoResetEvent WaitEvent) in WaitingThreads)
- {
- IncrementCondVarValue();
- WaitEvent.Set();
- }
- WaitingThreads.Clear();
- }
- else
- {
- while (WaitingThreads.Count > 0 && Count-- > 0)
- {
- int HighestPriority = WaitingThreads[0].Thread.Priority;
- int HighestPrioIndex = 0;
- for (int Index = 1; Index < WaitingThreads.Count; Index++)
- {
- if (HighestPriority > WaitingThreads[Index].Thread.Priority)
- {
- HighestPriority = WaitingThreads[Index].Thread.Priority;
- HighestPrioIndex = Index;
- }
- }
- IncrementCondVarValue();
- WaitingThreads[HighestPrioIndex].WaitEvent.Set();
- WaitingThreads.RemoveAt(HighestPrioIndex);
- }
- }
- }
- Process.Scheduler.Yield(Thread);
- }
- private void IncrementCondVarValue()
- {
- AcquireCondVarValue();
- int Count = Process.Memory.ReadInt32(CondVarAddress);
- Process.Memory.WriteInt32(CondVarAddress, Count + 1);
- ReleaseCondVarValue();
- }
- private void AcquireCondVarValue()
- {
- if (!OwnsCondVarValue)
- {
- while (!Process.Memory.AcquireAddress(CondVarAddress))
- {
- Thread.Yield();
- }
- OwnsCondVarValue = true;
- }
- }
- private void ReleaseCondVarValue()
- {
- if (OwnsCondVarValue)
- {
- OwnsCondVarValue = false;
- Process.Memory.ReleaseAddress(CondVarAddress);
- }
- }
- }
- }
|