aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Kernel/KTimeManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel/KTimeManager.cs')
-rw-r--r--Ryujinx.HLE/HOS/Kernel/KTimeManager.cs134
1 files changed, 134 insertions, 0 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/KTimeManager.cs b/Ryujinx.HLE/HOS/Kernel/KTimeManager.cs
new file mode 100644
index 00000000..47a3c86c
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Kernel/KTimeManager.cs
@@ -0,0 +1,134 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading;
+
+namespace Ryujinx.HLE.HOS.Kernel
+{
+ class KTimeManager : IDisposable
+ {
+ private class WaitingObject
+ {
+ public IKFutureSchedulerObject Object { get; private set; }
+
+ public long TimePoint { get; private set; }
+
+ public WaitingObject(IKFutureSchedulerObject Object, long TimePoint)
+ {
+ this.Object = Object;
+ this.TimePoint = TimePoint;
+ }
+ }
+
+ private List<WaitingObject> WaitingObjects;
+
+ private AutoResetEvent WaitEvent;
+
+ private Stopwatch Counter;
+
+ private bool KeepRunning;
+
+ public KTimeManager()
+ {
+ WaitingObjects = new List<WaitingObject>();
+
+ Counter = new Stopwatch();
+
+ Counter.Start();
+
+ KeepRunning = true;
+
+ Thread Work = new Thread(WaitAndCheckScheduledObjects);
+
+ Work.Start();
+ }
+
+ public void ScheduleFutureInvocation(IKFutureSchedulerObject Object, long Timeout)
+ {
+ lock (WaitingObjects)
+ {
+ long TimePoint = Counter.ElapsedMilliseconds + ConvertNanosecondsToMilliseconds(Timeout);
+
+ WaitingObjects.Add(new WaitingObject(Object, TimePoint));
+ }
+
+ WaitEvent.Set();
+ }
+
+ private long ConvertNanosecondsToMilliseconds(long Timeout)
+ {
+ Timeout /= 1000000;
+
+ if ((ulong)Timeout > int.MaxValue)
+ {
+ return int.MaxValue;
+ }
+
+ return Timeout;
+ }
+
+ public void UnscheduleFutureInvocation(IKFutureSchedulerObject Object)
+ {
+ lock (WaitingObjects)
+ {
+ WaitingObjects.RemoveAll(x => x.Object == Object);
+ }
+ }
+
+ private void WaitAndCheckScheduledObjects()
+ {
+ using (WaitEvent = new AutoResetEvent(false))
+ {
+ while (KeepRunning)
+ {
+ Monitor.Enter(WaitingObjects);
+
+ WaitingObject Next = WaitingObjects.OrderBy(x => x.TimePoint).FirstOrDefault();
+
+ Monitor.Exit(WaitingObjects);
+
+ if (Next != null)
+ {
+ long TimePoint = Counter.ElapsedMilliseconds;
+
+ if (Next.TimePoint > TimePoint)
+ {
+ WaitEvent.WaitOne((int)(Next.TimePoint - TimePoint));
+ }
+
+ Monitor.Enter(WaitingObjects);
+
+ bool TimeUp = Counter.ElapsedMilliseconds >= Next.TimePoint && WaitingObjects.Remove(Next);
+
+ Monitor.Exit(WaitingObjects);
+
+ if (TimeUp)
+ {
+ Next.Object.TimeUp();
+ }
+ }
+ else
+ {
+ WaitEvent.WaitOne();
+ }
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool Disposing)
+ {
+ if (Disposing)
+ {
+ KeepRunning = false;
+
+ WaitEvent?.Set();
+ }
+ }
+ }
+} \ No newline at end of file