diff options
| author | emmauss <emmausssss@gmail.com> | 2018-02-20 22:09:23 +0200 |
|---|---|---|
| committer | gdkchan <gab.dark.100@gmail.com> | 2018-02-20 17:09:23 -0300 |
| commit | 62b827f474f0aa2152dd339fcc7cf31084e16a0b (patch) | |
| tree | 0e5c55b341aee4db0ccb841a084f253ec5e05657 /Ryujinx.Core/OsHle/Handles | |
| parent | cb665bb715834526d73c9469d16114b287faaecd (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.cs | 58 | ||||
| -rw-r--r-- | Ryujinx.Core/OsHle/Handles/HEvent.cs | 7 | ||||
| -rw-r--r-- | Ryujinx.Core/OsHle/Handles/HNvMap.cs | 18 | ||||
| -rw-r--r-- | Ryujinx.Core/OsHle/Handles/HSession.cs | 27 | ||||
| -rw-r--r-- | Ryujinx.Core/OsHle/Handles/HSessionObj.cs | 30 | ||||
| -rw-r--r-- | Ryujinx.Core/OsHle/Handles/HSharedMem.cs | 70 | ||||
| -rw-r--r-- | Ryujinx.Core/OsHle/Handles/HThread.cs | 21 | ||||
| -rw-r--r-- | Ryujinx.Core/OsHle/Handles/HTransferMem.cs | 21 | ||||
| -rw-r--r-- | Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs | 334 |
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 |
