aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Core/OsHle/Mutex.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Core/OsHle/Mutex.cs')
-rw-r--r--Ryujinx.Core/OsHle/Mutex.cs122
1 files changed, 122 insertions, 0 deletions
diff --git a/Ryujinx.Core/OsHle/Mutex.cs b/Ryujinx.Core/OsHle/Mutex.cs
new file mode 100644
index 00000000..c95ed771
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Mutex.cs
@@ -0,0 +1,122 @@
+using Ryujinx.Core.OsHle.Handles;
+using System.Collections.Concurrent;
+using System.Threading;
+
+namespace Ryujinx.Core.OsHle
+{
+ public class Mutex
+ {
+ private const int MutexHasListenersMask = 0x40000000;
+
+ private Process Process;
+
+ private long MutexAddress;
+
+ private bool OwnsMutexValue;
+
+ private object EnterWaitLock;
+
+ private ConcurrentQueue<HThread> WaitingThreads;
+
+ public Mutex(Process Process, long MutexAddress, int OwnerThreadHandle)
+ {
+ this.Process = Process;
+ this.MutexAddress = MutexAddress;
+
+ //Process.Memory.WriteInt32(MutexAddress, OwnerThreadHandle);
+
+ EnterWaitLock = new object();
+
+ WaitingThreads = new ConcurrentQueue<HThread>();
+ }
+
+ public void WaitForLock(HThread RequestingThread, int RequestingThreadHandle)
+ {
+ AcquireMutexValue();
+
+ lock (EnterWaitLock)
+ {
+ int CurrentThreadHandle = Process.Memory.ReadInt32(MutexAddress) & ~MutexHasListenersMask;
+
+ if (CurrentThreadHandle == RequestingThreadHandle ||
+ CurrentThreadHandle == 0)
+ {
+ return;
+ }
+
+ Process.Memory.WriteInt32(MutexAddress, CurrentThreadHandle | MutexHasListenersMask);
+
+ ReleaseMutexValue();
+
+ WaitingThreads.Enqueue(RequestingThread);
+ }
+
+ Process.Scheduler.WaitForSignal(RequestingThread);
+ }
+
+ public void GiveUpLock(int ThreadHandle)
+ {
+ AcquireMutexValue();
+
+ lock (EnterWaitLock)
+ {
+ int CurrentThread = Process.Memory.ReadInt32(MutexAddress) & ~MutexHasListenersMask;
+
+ if (CurrentThread == ThreadHandle)
+ {
+ Unlock();
+ }
+ }
+
+ ReleaseMutexValue();
+ }
+
+ public void Unlock()
+ {
+ AcquireMutexValue();
+
+ lock (EnterWaitLock)
+ {
+ int HasListeners = WaitingThreads.Count > 1 ? MutexHasListenersMask : 0;
+
+ Process.Memory.WriteInt32(MutexAddress, HasListeners);
+
+ ReleaseMutexValue();
+
+ HThread[] UnlockedThreads = new HThread[WaitingThreads.Count];
+
+ int Index = 0;
+
+ while (WaitingThreads.TryDequeue(out HThread Thread))
+ {
+ UnlockedThreads[Index++] = Thread;
+ }
+
+ Process.Scheduler.Signal(UnlockedThreads);
+ }
+ }
+
+ private void AcquireMutexValue()
+ {
+ if (!OwnsMutexValue)
+ {
+ while (!Process.Memory.AcquireAddress(MutexAddress))
+ {
+ Thread.Yield();
+ }
+
+ OwnsMutexValue = true;
+ }
+ }
+
+ private void ReleaseMutexValue()
+ {
+ if (OwnsMutexValue)
+ {
+ OwnsMutexValue = false;
+
+ Process.Memory.ReleaseAddress(MutexAddress);
+ }
+ }
+ }
+} \ No newline at end of file