aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Core/OsHle/Handles
diff options
context:
space:
mode:
authoremmauss <emmausssss@gmail.com>2018-02-20 22:09:23 +0200
committergdkchan <gab.dark.100@gmail.com>2018-02-20 17:09:23 -0300
commit62b827f474f0aa2152dd339fcc7cf31084e16a0b (patch)
tree0e5c55b341aee4db0ccb841a084f253ec5e05657 /Ryujinx.Core/OsHle/Handles
parentcb665bb715834526d73c9469d16114b287faaecd (diff)
Split main project into core,graphics and chocolarm4 subproject (#29)
Diffstat (limited to 'Ryujinx.Core/OsHle/Handles')
-rw-r--r--Ryujinx.Core/OsHle/Handles/HDomain.cs58
-rw-r--r--Ryujinx.Core/OsHle/Handles/HEvent.cs7
-rw-r--r--Ryujinx.Core/OsHle/Handles/HNvMap.cs18
-rw-r--r--Ryujinx.Core/OsHle/Handles/HSession.cs27
-rw-r--r--Ryujinx.Core/OsHle/Handles/HSessionObj.cs30
-rw-r--r--Ryujinx.Core/OsHle/Handles/HSharedMem.cs70
-rw-r--r--Ryujinx.Core/OsHle/Handles/HThread.cs21
-rw-r--r--Ryujinx.Core/OsHle/Handles/HTransferMem.cs21
-rw-r--r--Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs334
9 files changed, 586 insertions, 0 deletions
diff --git a/Ryujinx.Core/OsHle/Handles/HDomain.cs b/Ryujinx.Core/OsHle/Handles/HDomain.cs
new file mode 100644
index 00000000..ca287a5f
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Handles/HDomain.cs
@@ -0,0 +1,58 @@
+using Ryujinx.Core.OsHle.Utilities;
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.Core.OsHle.Handles
+{
+ class HDomain : HSession
+ {
+ private Dictionary<int, object> Objects;
+
+ private IdPool ObjIds;
+
+ public HDomain(HSession Session) : base(Session)
+ {
+ Objects = new Dictionary<int, object>();
+
+ ObjIds = new IdPool();
+ }
+
+ public int GenerateObjectId(object Obj)
+ {
+ int Id = ObjIds.GenerateId();
+
+ if (Id == -1)
+ {
+ throw new InvalidOperationException();
+ }
+
+ Objects.Add(Id, Obj);
+
+ return Id;
+ }
+
+ public void DeleteObject(int Id)
+ {
+ if (Objects.TryGetValue(Id, out object Obj))
+ {
+ if (Obj is IDisposable DisposableObj)
+ {
+ DisposableObj.Dispose();
+ }
+
+ ObjIds.DeleteId(Id);
+ Objects.Remove(Id);
+ }
+ }
+
+ public object GetObject(int Id)
+ {
+ if (Objects.TryGetValue(Id, out object Obj))
+ {
+ return Obj;
+ }
+
+ return null;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Handles/HEvent.cs b/Ryujinx.Core/OsHle/Handles/HEvent.cs
new file mode 100644
index 00000000..4e881ca2
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Handles/HEvent.cs
@@ -0,0 +1,7 @@
+namespace Ryujinx.Core.OsHle.Handles
+{
+ class HEvent
+ {
+
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Handles/HNvMap.cs b/Ryujinx.Core/OsHle/Handles/HNvMap.cs
new file mode 100644
index 00000000..09173730
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Handles/HNvMap.cs
@@ -0,0 +1,18 @@
+namespace Ryujinx.Core.OsHle.Handles
+{
+ class HNvMap
+ {
+ public int Id { get; private set; }
+ public int Size { get; private set; }
+
+ public int Align { get; set; }
+ public int Kind { get; set; }
+ public long Address { get; set; }
+
+ public HNvMap(int Id, int Size)
+ {
+ this.Id = Id;
+ this.Size = Size;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Handles/HSession.cs b/Ryujinx.Core/OsHle/Handles/HSession.cs
new file mode 100644
index 00000000..8aa1c06b
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Handles/HSession.cs
@@ -0,0 +1,27 @@
+namespace Ryujinx.Core.OsHle.Handles
+{
+ class HSession
+ {
+ public string ServiceName { get; private set; }
+
+ public bool IsInitialized { get; private set; }
+
+ public int State { get; set; }
+
+ public HSession(string ServiceName)
+ {
+ this.ServiceName = ServiceName;
+ }
+
+ public HSession(HSession Session)
+ {
+ ServiceName = Session.ServiceName;
+ IsInitialized = Session.IsInitialized;
+ }
+
+ public void Initialize()
+ {
+ IsInitialized = true;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Handles/HSessionObj.cs b/Ryujinx.Core/OsHle/Handles/HSessionObj.cs
new file mode 100644
index 00000000..ed0530f7
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Handles/HSessionObj.cs
@@ -0,0 +1,30 @@
+using System;
+
+namespace Ryujinx.Core.OsHle.Handles
+{
+ class HSessionObj : HSession, IDisposable
+ {
+ public object Obj { get; private set; }
+
+ public HSessionObj(HSession Session, object Obj) : base(Session)
+ {
+ this.Obj = Obj;
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool Disposing)
+ {
+ if (Disposing && Obj != null)
+ {
+ if (Obj is IDisposable DisposableObj)
+ {
+ DisposableObj.Dispose();
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Handles/HSharedMem.cs b/Ryujinx.Core/OsHle/Handles/HSharedMem.cs
new file mode 100644
index 00000000..3d56ff92
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Handles/HSharedMem.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.Core.OsHle.Handles
+{
+ class HSharedMem
+ {
+ private List<long> Positions;
+
+ public int PositionsCount => Positions.Count;
+
+ public EventHandler<EventArgs> MemoryMapped;
+ public EventHandler<EventArgs> MemoryUnmapped;
+
+ public HSharedMem(long PhysPos)
+ {
+ Positions = new List<long>();
+ }
+
+ public void AddVirtualPosition(long Position)
+ {
+ lock (Positions)
+ {
+ Positions.Add(Position);
+
+ MemoryMapped?.Invoke(this, EventArgs.Empty);
+ }
+ }
+
+ public void RemoveVirtualPosition(long Position)
+ {
+ lock (Positions)
+ {
+ Positions.Remove(Position);
+
+ MemoryUnmapped?.Invoke(this, EventArgs.Empty);
+ }
+ }
+
+ public long GetVirtualPosition(int Index)
+ {
+ lock (Positions)
+ {
+ if (Index < 0 || Index >= Positions.Count)
+ {
+ throw new ArgumentOutOfRangeException(nameof(Index));
+ }
+
+ return Positions[Index];
+ }
+ }
+
+ public bool TryGetLastVirtualPosition(out long Position)
+ {
+ lock (Positions)
+ {
+ if (Positions.Count > 0)
+ {
+ Position = Positions[Positions.Count - 1];
+
+ return true;
+ }
+
+ Position = 0;
+
+ return false;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Handles/HThread.cs b/Ryujinx.Core/OsHle/Handles/HThread.cs
new file mode 100644
index 00000000..8bb276fa
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Handles/HThread.cs
@@ -0,0 +1,21 @@
+using ChocolArm64;
+
+namespace Ryujinx.Core.OsHle.Handles
+{
+ public class HThread
+ {
+ public AThread Thread { get; private set; }
+
+ public int ProcessorId { get; private set; }
+ public int Priority { get; private set; }
+
+ public int ThreadId => Thread.ThreadId;
+
+ public HThread(AThread Thread, int ProcessorId, int Priority)
+ {
+ this.Thread = Thread;
+ this.ProcessorId = ProcessorId;
+ this.Priority = Priority;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Handles/HTransferMem.cs b/Ryujinx.Core/OsHle/Handles/HTransferMem.cs
new file mode 100644
index 00000000..701fc451
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Handles/HTransferMem.cs
@@ -0,0 +1,21 @@
+using ChocolArm64.Memory;
+
+namespace Ryujinx.Core.OsHle.Handles
+{
+ class HTransferMem
+ {
+ public AMemory Memory { get; private set; }
+ public AMemoryPerm Perm { get; private set; }
+
+ public long Position { get; private set; }
+ public long Size { get; private set; }
+
+ public HTransferMem(AMemory Memory, AMemoryPerm Perm, long Position, long Size)
+ {
+ this.Memory = Memory;
+ this.Perm = Perm;
+ this.Position = Position;
+ this.Size = Size;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs b/Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs
new file mode 100644
index 00000000..2045f8a1
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs
@@ -0,0 +1,334 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace Ryujinx.Core.OsHle.Handles
+{
+ public class KProcessScheduler : IDisposable
+ {
+ private class SchedulerThread : IDisposable
+ {
+ public HThread Thread { get; private set; }
+
+ public AutoResetEvent WaitEvent { get; private set; }
+
+ public SchedulerThread(HThread Thread)
+ {
+ this.Thread = Thread;
+
+ WaitEvent = new AutoResetEvent(false);
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool Disposing)
+ {
+ if (Disposing)
+ {
+ WaitEvent.Dispose();
+ }
+ }
+ }
+
+ private class ThreadQueue
+ {
+ private List<SchedulerThread> Threads;
+
+ public ThreadQueue()
+ {
+ Threads = new List<SchedulerThread>();
+ }
+
+ public void Push(SchedulerThread Thread)
+ {
+ lock (Threads)
+ {
+ Threads.Add(Thread);
+ }
+ }
+
+ public SchedulerThread Pop(int MinPriority = 0x40)
+ {
+ lock (Threads)
+ {
+ SchedulerThread SchedThread;
+
+ int HighestPriority = MinPriority;
+
+ int HighestPrioIndex = -1;
+
+ for (int Index = 0; Index < Threads.Count; Index++)
+ {
+ SchedThread = Threads[Index];
+
+ if (HighestPriority > SchedThread.Thread.Priority)
+ {
+ HighestPriority = SchedThread.Thread.Priority;
+
+ HighestPrioIndex = Index;
+ }
+ }
+
+ if (HighestPrioIndex == -1)
+ {
+ return null;
+ }
+
+ SchedThread = Threads[HighestPrioIndex];
+
+ Threads.RemoveAt(HighestPrioIndex);
+
+ return SchedThread;
+ }
+ }
+
+ public bool HasThread(SchedulerThread SchedThread)
+ {
+ lock (Threads)
+ {
+ return Threads.Contains(SchedThread);
+ }
+ }
+ }
+
+ private ConcurrentDictionary<HThread, SchedulerThread> AllThreads;
+
+ private ThreadQueue[] WaitingToRun;
+
+ private HashSet<int> ActiveProcessors;
+
+ private object SchedLock;
+
+ public KProcessScheduler()
+ {
+ AllThreads = new ConcurrentDictionary<HThread, SchedulerThread>();
+
+ WaitingToRun = new ThreadQueue[4];
+
+ for (int Index = 0; Index < 4; Index++)
+ {
+ WaitingToRun[Index] = new ThreadQueue();
+ }
+
+ ActiveProcessors = new HashSet<int>();
+
+ SchedLock = new object();
+ }
+
+ public void StartThread(HThread Thread)
+ {
+ lock (SchedLock)
+ {
+ SchedulerThread SchedThread = new SchedulerThread(Thread);
+
+ if (!AllThreads.TryAdd(Thread, SchedThread))
+ {
+ return;
+ }
+
+ if (!ActiveProcessors.Contains(Thread.ProcessorId))
+ {
+ ActiveProcessors.Add(Thread.ProcessorId);
+
+ Thread.Thread.Execute();
+
+ Logging.Debug($"{GetDbgThreadInfo(Thread)} running.");
+ }
+ else
+ {
+ WaitingToRun[Thread.ProcessorId].Push(SchedThread);
+
+ Logging.Debug($"{GetDbgThreadInfo(SchedThread.Thread)} waiting to run.");
+ }
+ }
+ }
+
+ public void Suspend(int ProcessorId)
+ {
+ lock (SchedLock)
+ {
+ SchedulerThread SchedThread = WaitingToRun[ProcessorId].Pop();
+
+ if (SchedThread != null)
+ {
+ RunThread(SchedThread);
+ }
+ else
+ {
+ ActiveProcessors.Remove(ProcessorId);
+ }
+ }
+ }
+
+ public void Resume(HThread CurrThread)
+ {
+ SchedulerThread SchedThread;
+
+ Logging.Debug($"{GetDbgThreadInfo(CurrThread)} entering ipc delay wait state.");
+
+ lock (SchedLock)
+ {
+ if (!AllThreads.TryGetValue(CurrThread, out SchedThread))
+ {
+ Logging.Error($"{GetDbgThreadInfo(CurrThread)} was not found on the scheduler queue!");
+
+ return;
+ }
+ }
+
+ TryResumingExecution(SchedThread);
+ }
+
+ public void WaitForSignal(HThread Thread, int Timeout = -1)
+ {
+ SchedulerThread SchedThread;
+
+ Logging.Debug($"{GetDbgThreadInfo(Thread)} entering signal wait state.");
+
+ lock (SchedLock)
+ {
+ SchedThread = WaitingToRun[Thread.ProcessorId].Pop();
+
+ if (SchedThread != null)
+ {
+ RunThread(SchedThread);
+ }
+ else
+ {
+ ActiveProcessors.Remove(Thread.ProcessorId);
+ }
+
+ if (!AllThreads.TryGetValue(Thread, out SchedThread))
+ {
+ Logging.Error($"{GetDbgThreadInfo(Thread)} was not found on the scheduler queue!");
+
+ return;
+ }
+ }
+
+ if (Timeout >= 0)
+ {
+ Logging.Debug($"{GetDbgThreadInfo(Thread)} has wait timeout of {Timeout}ms.");
+
+ SchedThread.WaitEvent.WaitOne(Timeout);
+ }
+ else
+ {
+ SchedThread.WaitEvent.WaitOne();
+ }
+
+ TryResumingExecution(SchedThread);
+ }
+
+ private void TryResumingExecution(SchedulerThread SchedThread)
+ {
+ HThread Thread = SchedThread.Thread;
+
+ lock (SchedLock)
+ {
+ if (ActiveProcessors.Add(Thread.ProcessorId))
+ {
+ Logging.Debug($"{GetDbgThreadInfo(Thread)} resuming execution...");
+
+ return;
+ }
+
+ WaitingToRun[Thread.ProcessorId].Push(SchedThread);
+ }
+
+ SchedThread.WaitEvent.WaitOne();
+
+ Logging.Debug($"{GetDbgThreadInfo(Thread)} resuming execution...");
+ }
+
+ public void Yield(HThread Thread)
+ {
+ SchedulerThread SchedThread;
+
+ Logging.Debug($"{GetDbgThreadInfo(Thread)} yielded execution.");
+
+ lock (SchedLock)
+ {
+ SchedThread = WaitingToRun[Thread.ProcessorId].Pop(Thread.Priority);
+
+ if (SchedThread == null)
+ {
+ Logging.Debug($"{GetDbgThreadInfo(Thread)} resumed because theres nothing better to run.");
+
+ return;
+ }
+
+ RunThread(SchedThread);
+
+ if (!AllThreads.TryGetValue(Thread, out SchedThread))
+ {
+ Logging.Error($"{GetDbgThreadInfo(Thread)} was not found on the scheduler queue!");
+
+ return;
+ }
+
+ WaitingToRun[Thread.ProcessorId].Push(SchedThread);
+ }
+
+ SchedThread.WaitEvent.WaitOne();
+
+ Logging.Debug($"{GetDbgThreadInfo(Thread)} resuming execution...");
+ }
+
+ private void RunThread(SchedulerThread SchedThread)
+ {
+ if (!SchedThread.Thread.Thread.Execute())
+ {
+ SchedThread.WaitEvent.Set();
+ }
+ else
+ {
+ Logging.Debug($"{GetDbgThreadInfo(SchedThread.Thread)} running.");
+ }
+ }
+
+ public void Signal(params HThread[] Threads)
+ {
+ lock (SchedLock)
+ {
+ foreach (HThread Thread in Threads)
+ {
+ if (AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread))
+ {
+ if (!WaitingToRun[Thread.ProcessorId].HasThread(SchedThread))
+ {
+ Logging.Debug($"{GetDbgThreadInfo(Thread)} signaled.");
+
+ SchedThread.WaitEvent.Set();
+ }
+ }
+ }
+ }
+ }
+
+ private string GetDbgThreadInfo(HThread Thread)
+ {
+ return $"Thread {Thread.ThreadId} (core {Thread.ProcessorId}) prio {Thread.Priority}";
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool Disposing)
+ {
+ if (Disposing)
+ {
+ foreach (SchedulerThread SchedThread in AllThreads.Values)
+ {
+ SchedThread.Dispose();
+ }
+ }
+ }
+ }
+} \ No newline at end of file