diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2023-01-04 19:15:45 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-01-04 23:15:45 +0100 |
| commit | 08831eecf77cedd3c4192ebab5a9c485fb15d51e (patch) | |
| tree | 6d95b921a18e9cfa477579fcecb9d041e03d682e /Ryujinx.Horizon/Sdk/OsTypes | |
| parent | c6a139a6e7e3ffe1591bc14dafafed60b9bef0dc (diff) | |
IPC refactor part 3+4: New server HIPC message processor (#4188)
* IPC refactor part 3 + 4: New server HIPC message processor with source generator based serialization
* Make types match on calls to AlignUp/AlignDown
* Formatting
* Address some PR feedback
* Move BitfieldExtensions to Ryujinx.Common.Utilities and consolidate implementations
* Rename Reader/Writer to SpanReader/SpanWriter and move to Ryujinx.Common.Memory
* Implement EventType
* Address more PR feedback
* Log request processing errors since they are not normal
* Rename waitable to multiwait and add missing lock
* PR feedback
* Ac_K PR feedback
Diffstat (limited to 'Ryujinx.Horizon/Sdk/OsTypes')
21 files changed, 1056 insertions, 0 deletions
diff --git a/Ryujinx.Horizon/Sdk/OsTypes/Event.cs b/Ryujinx.Horizon/Sdk/OsTypes/Event.cs new file mode 100644 index 00000000..79d7408e --- /dev/null +++ b/Ryujinx.Horizon/Sdk/OsTypes/Event.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; + +namespace Ryujinx.Horizon.Sdk.OsTypes +{ + class Event : IDisposable + { + private EventType _event; + + public object EventLock => _event.Lock; + public LinkedList<MultiWaitHolderBase> MultiWaitHolders => _event.MultiWaitHolders; + + public Event(EventClearMode clearMode) + { + Os.InitializeEvent(out _event, signaled: false, clearMode); + } + + public TriBool IsSignaledThreadUnsafe() + { + return _event.Signaled ? TriBool.True : TriBool.False; + } + + public void Wait() + { + Os.WaitEvent(ref _event); + } + + public bool TryWait() + { + return Os.TryWaitEvent(ref _event); + } + + public bool TimedWait(TimeSpan timeout) + { + return Os.TimedWaitEvent(ref _event, timeout); + } + + public void Signal() + { + Os.SignalEvent(ref _event); + } + + public void Clear() + { + Os.ClearEvent(ref _event); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + Os.FinalizeEvent(ref _event); + } + } + + public void Dispose() + { + Dispose(true); + } + } +} diff --git a/Ryujinx.Horizon/Sdk/OsTypes/EventClearMode.cs b/Ryujinx.Horizon/Sdk/OsTypes/EventClearMode.cs new file mode 100644 index 00000000..b500e6b3 --- /dev/null +++ b/Ryujinx.Horizon/Sdk/OsTypes/EventClearMode.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Horizon.Sdk.OsTypes +{ + enum EventClearMode + { + ManualClear, + AutoClear + } +} diff --git a/Ryujinx.Horizon/Sdk/OsTypes/EventType.cs b/Ryujinx.Horizon/Sdk/OsTypes/EventType.cs new file mode 100644 index 00000000..b4b1a275 --- /dev/null +++ b/Ryujinx.Horizon/Sdk/OsTypes/EventType.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace Ryujinx.Horizon.Sdk.OsTypes +{ + struct EventType + { + public LinkedList<MultiWaitHolderBase> MultiWaitHolders; + public bool Signaled; + public bool InitiallySignaled; + public EventClearMode ClearMode; + public InitializationState State; + public ulong BroadcastCounter; + public object Lock; + } +} diff --git a/Ryujinx.Horizon/Sdk/OsTypes/Impl/InterProcessEvent.cs b/Ryujinx.Horizon/Sdk/OsTypes/Impl/InterProcessEvent.cs new file mode 100644 index 00000000..62b5bf06 --- /dev/null +++ b/Ryujinx.Horizon/Sdk/OsTypes/Impl/InterProcessEvent.cs @@ -0,0 +1,89 @@ +using Ryujinx.Horizon.Common; + +namespace Ryujinx.Horizon.Sdk.OsTypes.Impl +{ + static class InterProcessEvent + { + public static Result Create(ref InterProcessEventType ipEvent, EventClearMode clearMode) + { + Result result = InterProcessEventImpl.Create(out int writableHandle, out int readableHandle); + + if (result != Result.Success) + { + return result; + } + + ipEvent = new InterProcessEventType( + clearMode == EventClearMode.AutoClear, + true, + true, + readableHandle, + writableHandle); + + return Result.Success; + } + + public static void Destroy(ref InterProcessEventType ipEvent) + { + ipEvent.State = InitializationState.NotInitialized; + + if (ipEvent.ReadableHandleManaged) + { + if (ipEvent.ReadableHandle != 0) + { + InterProcessEventImpl.Close(ipEvent.ReadableHandle); + } + ipEvent.ReadableHandleManaged = false; + } + + if (ipEvent.WritableHandleManaged) + { + if (ipEvent.WritableHandle != 0) + { + InterProcessEventImpl.Close(ipEvent.WritableHandle); + } + ipEvent.WritableHandleManaged = false; + } + } + + public static int DetachReadableHandle(ref InterProcessEventType ipEvent) + { + int handle = ipEvent.ReadableHandle; + + ipEvent.ReadableHandle = 0; + ipEvent.ReadableHandleManaged = false; + + return handle; + } + + public static int DetachWritableHandle(ref InterProcessEventType ipEvent) + { + int handle = ipEvent.WritableHandle; + + ipEvent.WritableHandle = 0; + ipEvent.WritableHandleManaged = false; + + return handle; + } + + public static int GetReadableHandle(ref InterProcessEventType ipEvent) + { + return ipEvent.ReadableHandle; + } + + public static int GetWritableHandle(ref InterProcessEventType ipEvent) + { + return ipEvent.WritableHandle; + } + + public static void Signal(ref InterProcessEventType ipEvent) + { + InterProcessEventImpl.Signal(ipEvent.WritableHandle); + } + + public static void Clear(ref InterProcessEventType ipEvent) + { + InterProcessEventImpl.Clear(ipEvent.ReadableHandle == 0 ? ipEvent.WritableHandle : ipEvent.ReadableHandle); + } + } +} diff --git a/Ryujinx.Horizon/Sdk/OsTypes/Impl/InterProcessEventImpl.cs b/Ryujinx.Horizon/Sdk/OsTypes/Impl/InterProcessEventImpl.cs new file mode 100644 index 00000000..a8aeacc9 --- /dev/null +++ b/Ryujinx.Horizon/Sdk/OsTypes/Impl/InterProcessEventImpl.cs @@ -0,0 +1,136 @@ +using Ryujinx.Horizon.Common; +using System; + +namespace Ryujinx.Horizon.Sdk.OsTypes.Impl +{ + static class InterProcessEventImpl + { + public static Result Create(out int writableHandle, out int readableHandle) + { + Result result = HorizonStatic.Syscall.CreateEvent(out writableHandle, out readableHandle); + + if (result == KernelResult.OutOfResource) + { + return OsResult.OutOfResource; + } + + result.AbortOnFailure(); + + return Result.Success; + } + + public static void Close(int handle) + { + if (handle != 0) + { + HorizonStatic.Syscall.CloseHandle(handle).AbortOnFailure(); + } + } + + public static void Signal(int handle) + { + HorizonStatic.Syscall.SignalEvent(handle).AbortOnFailure(); + } + + public static void Clear(int handle) + { + HorizonStatic.Syscall.ClearEvent(handle).AbortOnFailure(); + } + + public static void Wait(int handle, bool autoClear) + { + Span<int> handles = stackalloc int[1]; + + handles[0] = handle; + + while (true) + { + Result result = HorizonStatic.Syscall.WaitSynchronization(out _, handles, -1L); + + if (result == Result.Success) + { + if (autoClear) + { + result = HorizonStatic.Syscall.ResetSignal(handle); + + if (result == KernelResult.InvalidState) + { + continue; + } + + result.AbortOnFailure(); + } + + return; + } + + result.AbortUnless(KernelResult.Cancelled); + } + } + + public static bool TryWait(int handle, bool autoClear) + { + if (autoClear) + { + return HorizonStatic.Syscall.ResetSignal(handle) == Result.Success; + } + + Span<int> handles = stackalloc int[1]; + + handles[0] = handle; + + while (true) + { + Result result = HorizonStatic.Syscall.WaitSynchronization(out _, handles, 0); + + if (result == Result.Success) + { + return true; + } + else if (result == KernelResult.TimedOut) + { + return false; + } + + result.AbortUnless(KernelResult.Cancelled); + } + } + + public static bool TimedWait(int handle, bool autoClear, TimeSpan timeout) + { + Span<int> handles = stackalloc int[1]; + + handles[0] = handle; + + long timeoutNs = timeout.Milliseconds * 1000000L; + + while (true) + { + Result result = HorizonStatic.Syscall.WaitSynchronization(out _, handles, timeoutNs); + + if (result == Result.Success) + { + if (autoClear) + { + result = HorizonStatic.Syscall.ResetSignal(handle); + + if (result == KernelResult.InvalidState) + { + continue; + } + + result.AbortOnFailure(); + } + + return true; + } + else if (result == KernelResult.TimedOut) + { + return false; + } + + result.AbortUnless(KernelResult.Cancelled); + } + } + } +} diff --git a/Ryujinx.Horizon/Sdk/OsTypes/Impl/MultiWaitImpl.cs b/Ryujinx.Horizon/Sdk/OsTypes/Impl/MultiWaitImpl.cs new file mode 100644 index 00000000..fd45792d --- /dev/null +++ b/Ryujinx.Horizon/Sdk/OsTypes/Impl/MultiWaitImpl.cs @@ -0,0 +1,250 @@ +using Ryujinx.Common; +using Ryujinx.Horizon.Common; +using System.Collections.Generic; +using System; + +namespace Ryujinx.Horizon.Sdk.OsTypes.Impl +{ + class MultiWaitImpl + { + private const int WaitTimedOut = -1; + private const int WaitCancelled = -2; + private const int WaitInvalid = -3; + + private readonly List<MultiWaitHolderBase> _multiWaits; + + private object _lock; + + private int _waitingThreadHandle; + + private MultiWaitHolderBase _signaledHolder; + + public long CurrentTime { get; private set; } + + public MultiWaitImpl() + { + _multiWaits = new List<MultiWaitHolderBase>(); + + _lock = new object(); + } + + public void LinkMultiWaitHolder(MultiWaitHolderBase multiWaitHolder) + { + _multiWaits.Add(multiWaitHolder); + } + + public void UnlinkMultiWaitHolder(MultiWaitHolderBase multiWaitHolder) + { + _multiWaits.Remove(multiWaitHolder); + } + + public void MoveAllFrom(MultiWaitImpl other) + { + foreach (MultiWaitHolderBase multiWait in other._multiWaits) + { + multiWait.SetMultiWait(this); + } + + _multiWaits.AddRange(other._multiWaits); + + other._multiWaits.Clear(); + } + + public MultiWaitHolderBase WaitAnyImpl(bool infinite, long timeout) + { + _signaledHolder = null; + _waitingThreadHandle = Os.GetCurrentThreadHandle(); + + MultiWaitHolderBase result = LinkHoldersToObjectList(); + + lock (_lock) + { + if (_signaledHolder != null) + { + result = _signaledHolder; + } + } + + if (result == null) + { + result = WaitAnyHandleImpl(infinite, timeout); + } + + UnlinkHoldersFromObjectsList(); + _waitingThreadHandle = 0; + + return result; + } + + private MultiWaitHolderBase WaitAnyHandleImpl(bool infinite, long timeout) + { + Span<int> objectHandles = new int[64]; + + Span<MultiWaitHolderBase> objects = new MultiWaitHolderBase[64]; + + int count = FillObjectsArray(objectHandles, objects); + + long endTime = infinite ? long.MaxValue : PerformanceCounter.ElapsedMilliseconds * 1000000; + + while (true) + { + CurrentTime = PerformanceCounter.ElapsedMilliseconds * 1000000; + + MultiWaitHolderBase minTimeoutObject = RecalcMultiWaitTimeout(endTime, out long minTimeout); + + int index; + + if (count == 0 && minTimeout == 0) + { + index = WaitTimedOut; + } + else + { + index = WaitSynchronization(objectHandles.Slice(0, count), minTimeout); + + DebugUtil.Assert(index != WaitInvalid); + } + + switch (index) + { + case WaitTimedOut: + if (minTimeoutObject != null) + { + CurrentTime = PerformanceCounter.ElapsedMilliseconds * 1000000; + + if (minTimeoutObject.Signaled == TriBool.True) + { + lock (_lock) + { + _signaledHolder = minTimeoutObject; + + return _signaledHolder; + } + } + } + else + { + return null; + } + break; + case WaitCancelled: + lock (_lock) + { + if (_signaledHolder != null) + { + return _signaledHolder; + } + } + break; + default: + lock (_lock) + { + _signaledHolder = objects[index]; + + return _signaledHolder; + } + } + } + } + + private int FillObjectsArray(Span<int> handles, Span<MultiWaitHolderBase> objects) + { + int count = 0; + + foreach (MultiWaitHolderBase holder in _multiWaits) + { + int handle = holder.Handle; + + if (handle != 0) + { + handles[count] = handle; + objects[count] = holder; + + count++; + } + } + + return count; + } + + private MultiWaitHolderBase RecalcMultiWaitTimeout(long endTime, out long minTimeout) + { + MultiWaitHolderBase minTimeHolder = null; + + long minTime = endTime; + + foreach (MultiWaitHolder holder in _multiWaits) + { + long currentTime = holder.GetAbsoluteTimeToWakeup(); + + if ((ulong)currentTime < (ulong)minTime) + { + minTimeHolder = holder; + + minTime = currentTime; + } + } + + minTimeout = (ulong)minTime < (ulong)CurrentTime ? 0 : minTime - CurrentTime; + + return minTimeHolder; + } + + private static int WaitSynchronization(ReadOnlySpan<int> handles, long timeout) + { + Result result = HorizonStatic.Syscall.WaitSynchronization(out int index, handles, timeout); + + if (result == KernelResult.TimedOut) + { + return WaitTimedOut; + } + else if (result == KernelResult.Cancelled) + { + return WaitCancelled; + } + else + { + result.AbortOnFailure(); + } + + return index; + } + + public void NotifyAndWakeUpThread(MultiWaitHolderBase holder) + { + lock (_lock) + { + if (_signaledHolder == null) + { + _signaledHolder = holder; + HorizonStatic.Syscall.CancelSynchronization(_waitingThreadHandle).AbortOnFailure(); + } + } + } + + private MultiWaitHolderBase LinkHoldersToObjectList() + { + MultiWaitHolderBase signaledHolder = null; + + foreach (MultiWaitHolderBase holder in _multiWaits) + { + TriBool isSignaled = holder.LinkToObjectList(); + + if (signaledHolder == null && isSignaled == TriBool.True) + { + signaledHolder = holder; + } + } + + return signaledHolder; + } + + private void UnlinkHoldersFromObjectsList() + { + foreach (MultiWaitHolderBase holder in _multiWaits) + { + holder.UnlinkFromObjectList(); + } + } + } +} diff --git a/Ryujinx.Horizon/Sdk/OsTypes/InitializationState.cs b/Ryujinx.Horizon/Sdk/OsTypes/InitializationState.cs new file mode 100644 index 00000000..45ffd258 --- /dev/null +++ b/Ryujinx.Horizon/Sdk/OsTypes/InitializationState.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Horizon.Sdk.OsTypes +{ + enum InitializationState : byte + { + NotInitialized, + Initialized + } +}
\ No newline at end of file diff --git a/Ryujinx.Horizon/Sdk/OsTypes/InterProcessEventType.cs b/Ryujinx.Horizon/Sdk/OsTypes/InterProcessEventType.cs new file mode 100644 index 00000000..5f6824fe --- /dev/null +++ b/Ryujinx.Horizon/Sdk/OsTypes/InterProcessEventType.cs @@ -0,0 +1,27 @@ +namespace Ryujinx.Horizon.Sdk.OsTypes +{ + struct InterProcessEventType + { + public readonly bool AutoClear; + public InitializationState State; + public bool ReadableHandleManaged; + public bool WritableHandleManaged; + public int ReadableHandle; + public int WritableHandle; + + public InterProcessEventType( + bool autoClear, + bool readableHandleManaged, + bool writableHandleManaged, + int readableHandle, + int writableHandle) + { + AutoClear = autoClear; + State = InitializationState.Initialized; + ReadableHandleManaged = readableHandleManaged; + WritableHandleManaged = writableHandleManaged; + ReadableHandle = readableHandle; + WritableHandle = writableHandle; + } + } +} diff --git a/Ryujinx.Horizon/Sdk/OsTypes/MultiWait.cs b/Ryujinx.Horizon/Sdk/OsTypes/MultiWait.cs new file mode 100644 index 00000000..5a91f6c3 --- /dev/null +++ b/Ryujinx.Horizon/Sdk/OsTypes/MultiWait.cs @@ -0,0 +1,43 @@ +using Ryujinx.Horizon.Sdk.OsTypes.Impl; + +namespace Ryujinx.Horizon.Sdk.OsTypes +{ + class MultiWait + { + private readonly MultiWaitImpl _impl; + + public MultiWait() + { + _impl = new MultiWaitImpl(); + } + + public void LinkMultiWaitHolder(MultiWaitHolderBase multiWaitHolder) + { + DebugUtil.Assert(!multiWaitHolder.IsLinked); + + _impl.LinkMultiWaitHolder(multiWaitHolder); + + multiWaitHolder.SetMultiWait(_impl); + } + + public void MoveAllFrom(MultiWait other) + { + _impl.MoveAllFrom(other._impl); + } + + public MultiWaitHolder WaitAny() + { + return (MultiWaitHolder)_impl.WaitAnyImpl(true, -1L); + } + + public MultiWaitHolder TryWaitAny() + { + return (MultiWaitHolder)_impl.WaitAnyImpl(false, 0); + } + + public MultiWaitHolder TimedWaitAny(long timeout) + { + return (MultiWaitHolder)_impl.WaitAnyImpl(false, timeout); + } + } +} diff --git a/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolder.cs b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolder.cs new file mode 100644 index 00000000..a24b1906 --- /dev/null +++ b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolder.cs @@ -0,0 +1,16 @@ +namespace Ryujinx.Horizon.Sdk.OsTypes +{ + class MultiWaitHolder : MultiWaitHolderBase + { + public object UserData { get; set; } + + public void UnlinkFromMultiWaitHolder() + { + DebugUtil.Assert(IsLinked); + + MultiWait.UnlinkMultiWaitHolder(this); + + SetMultiWait(null); + } + } +} diff --git a/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderBase.cs b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderBase.cs new file mode 100644 index 00000000..018305ba --- /dev/null +++ b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderBase.cs @@ -0,0 +1,39 @@ +using Ryujinx.Horizon.Sdk.OsTypes.Impl; + +namespace Ryujinx.Horizon.Sdk.OsTypes +{ + class MultiWaitHolderBase + { + protected MultiWaitImpl MultiWait; + + public bool IsLinked => MultiWait != null; + + public virtual TriBool Signaled => TriBool.False; + + public virtual int Handle => 0; + + public void SetMultiWait(MultiWaitImpl multiWait) + { + MultiWait = multiWait; + } + + public MultiWaitImpl GetMultiWait() + { + return MultiWait; + } + + public virtual TriBool LinkToObjectList() + { + return TriBool.Undefined; + } + + public virtual void UnlinkFromObjectList() + { + } + + public virtual long GetAbsoluteTimeToWakeup() + { + return long.MaxValue; + } + } +} diff --git a/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderOfEvent.cs b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderOfEvent.cs new file mode 100644 index 00000000..37ac22f0 --- /dev/null +++ b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderOfEvent.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; + +namespace Ryujinx.Horizon.Sdk.OsTypes +{ + class MultiWaitHolderOfEvent : MultiWaitHolder + { + private Event _event; + private LinkedListNode<MultiWaitHolderBase> _node; + + public override TriBool Signaled + { + get + { + lock (_event.EventLock) + { + return _event.IsSignaledThreadUnsafe(); + } + } + } + + public MultiWaitHolderOfEvent(Event evnt) + { + _event = evnt; + } + + public override TriBool LinkToObjectList() + { + lock (_event.EventLock) + { + _node = _event.MultiWaitHolders.AddLast(this); + + return _event.IsSignaledThreadUnsafe(); + } + } + + public override void UnlinkFromObjectList() + { + lock (_event.EventLock) + { + _event.MultiWaitHolders.Remove(_node); + _node = null; + } + } + } +} diff --git a/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderOfHandle.cs b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderOfHandle.cs new file mode 100644 index 00000000..6fc5c75b --- /dev/null +++ b/Ryujinx.Horizon/Sdk/OsTypes/MultiWaitHolderOfHandle.cs @@ -0,0 +1,14 @@ +namespace Ryujinx.Horizon.Sdk.OsTypes +{ + class MultiWaitHolderOfHandle : MultiWaitHolder + { + private int _handle; + + public override int Handle => _handle; + + public MultiWaitHolderOfHandle(int handle) + { + _handle = handle; + } + } +} diff --git a/Ryujinx.Horizon/Sdk/OsTypes/OsEvent.cs b/Ryujinx.Horizon/Sdk/OsTypes/OsEvent.cs new file mode 100644 index 00000000..cc7e8483 --- /dev/null +++ b/Ryujinx.Horizon/Sdk/OsTypes/OsEvent.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.Threading; + +namespace Ryujinx.Horizon.Sdk.OsTypes +{ + static partial class Os + { + public static void InitializeEvent(out EventType evnt, bool signaled, EventClearMode clearMode) + { + evnt = new EventType + { + MultiWaitHolders = new LinkedList<MultiWaitHolderBase>(), + Signaled = signaled, + InitiallySignaled = signaled, + ClearMode = clearMode, + State = InitializationState.Initialized, + Lock = new object() + }; + } + + public static void FinalizeEvent(ref EventType evnt) + { + evnt.State = InitializationState.NotInitialized; + } + + public static void WaitEvent(ref EventType evnt) + { + lock (evnt.Lock) + { + ulong currentCounter = evnt.BroadcastCounter; + + while (!evnt.Signaled) + { + if (currentCounter != evnt.BroadcastCounter) + { + break; + } + + Monitor.Wait(evnt.Lock); + } + + if (evnt.ClearMode == EventClearMode.AutoClear) + { + evnt.Signaled = false; + } + } + } + + public static bool TryWaitEvent(ref EventType evnt) + { + lock (evnt.Lock) + { + bool signaled = evnt.Signaled; + + if (evnt.ClearMode == EventClearMode.AutoClear) + { + evnt.Signaled = false; + } + + return signaled; + } + } + + public static bool TimedWaitEvent(ref EventType evnt, TimeSpan timeout) + { + lock (evnt.Lock) + { + ulong currentCounter = evnt.BroadcastCounter; + + while (!evnt.Signaled) + { + if (currentCounter != evnt.BroadcastCounter) + { + break; + } + + bool wasSignaledInTime = Monitor.Wait(evnt.Lock, timeout); + if (!wasSignaledInTime) + { + return false; + } + } + + if (evnt.ClearMode == EventClearMode.AutoClear) + { + evnt.Signaled = false; + } + } + + return true; + } + + public static void SignalEvent(ref EventType evnt) + { + lock (evnt.Lock) + { + if (evnt.Signaled) + { + return; + } + + evnt.Signaled = true; + + if (evnt.ClearMode == EventClearMode.ManualClear) + { + evnt.BroadcastCounter++; + Monitor.PulseAll(evnt.Lock); + } + else + { + Monitor.Pulse(evnt.Lock); + } + + foreach (MultiWaitHolderBase holder in evnt.MultiWaitHolders) + { + holder.GetMultiWait().NotifyAndWakeUpThread(holder); + } + } + } + + public static void ClearEvent(ref EventType evnt) + { + lock (evnt.Lock) + { + evnt.Signaled = false; + } + } + } +} diff --git a/Ryujinx.Horizon/Sdk/OsTypes/OsMultiWait.cs b/Ryujinx.Horizon/Sdk/OsTypes/OsMultiWait.cs new file mode 100644 index 00000000..827de231 --- /dev/null +++ b/Ryujinx.Horizon/Sdk/OsTypes/OsMultiWait.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.Horizon.Sdk.OsTypes +{ + static partial class Os + { + public static void FinalizeMultiWaitHolder(MultiWaitHolderBase holder) + { + DebugUtil.Assert(!holder.IsLinked); + } + } +} diff --git a/Ryujinx.Horizon/Sdk/OsTypes/OsProcessHandle.cs b/Ryujinx.Horizon/Sdk/OsTypes/OsProcessHandle.cs new file mode 100644 index 00000000..6a6d9bf2 --- /dev/null +++ b/Ryujinx.Horizon/Sdk/OsTypes/OsProcessHandle.cs @@ -0,0 +1,33 @@ +using Ryujinx.Horizon.Common; + +namespace Ryujinx.Horizon.Sdk.OsTypes +{ + static partial class Os + { + private const int SelfProcessHandle = (0x1ffff << 15) | 1; + + public static int GetCurrentProcessHandle() + { + return SelfProcessHandle; + } + + public static ulong GetCurrentProcessId() + { + return GetProcessId(GetCurrentProcessHandle()); + } + + private static ulong GetProcessId(int handle) + { + Result result = TryGetProcessId(handle, out ulong pid); + + result.AbortOnFailure(); + + return pid; + } + + private static Result TryGetProcessId(int handle, out ulong pid) + { + return HorizonStatic.Syscall.GetProcessId(out pid, handle); + } + } +} diff --git a/Ryujinx.Horizon/Sdk/OsTypes/OsResult.cs b/Ryujinx.Horizon/Sdk/OsTypes/OsResult.cs new file mode 100644 index 00000000..86dcd1fa --- /dev/null +++ b/Ryujinx.Horizon/Sdk/OsTypes/OsResult.cs @@ -0,0 +1,11 @@ +using Ryujinx.Horizon.Common; + +namespace Ryujinx.Horizon.Sdk.OsTypes +{ + static class OsResult + { + private const int ModuleId = 3; + + public static Result OutOfResource => new Result(ModuleId, 9); + } +} diff --git a/Ryujinx.Horizon/Sdk/OsTypes/OsSystemEvent.cs b/Ryujinx.Horizon/Sdk/OsTypes/OsSystemEvent.cs new file mode 100644 index 00000000..061d7a3c --- /dev/null +++ b/Ryujinx.Horizon/Sdk/OsTypes/OsSystemEvent.cs @@ -0,0 +1,85 @@ +using Ryujinx.Horizon.Sdk.OsTypes.Impl; +using Ryujinx.Horizon.Common; +using System; + +namespace Ryujinx.Horizon.Sdk.OsTypes +{ + static partial class Os + { + public static Result CreateSystemEvent(out SystemEventType sysEvent, EventClearMode clearMode, bool interProcess) + { + sysEvent = new SystemEventType(); + + if (interProcess) + { + Result result = InterProcessEvent.Create(ref sysEvent.InterProcessEvent, clearMode); + + if (result != Result.Success) + { + return result; + } + + sysEvent.State = SystemEventType.InitializationState.InitializedAsInterProcess; + } + else + { + throw new NotImplementedException(); + } + + return Result.Success; + } + + public static void DestroySystemEvent(ref SystemEventType sysEvent) + { + var oldState = sysEvent.State; + sysEvent.State = SystemEventType.InitializationState.NotInitialized; + + switch (oldState) + { + case SystemEventType.InitializationState.InitializedAsInterProcess: + InterProcessEvent.Destroy(ref sysEvent.InterProcessEvent); + break; + } + } + + public static int DetachReadableHandleOfSystemEvent(ref SystemEventType sysEvent) + { + return InterProcessEvent.DetachReadableHandle(ref sysEvent.InterProcessEvent); + } + + public static int DetachWritableHandleOfSystemEvent(ref SystemEventType sysEvent) + { + return InterProcessEvent.DetachWritableHandle(ref sysEvent.InterProcessEvent); + } + + public static int GetReadableHandleOfSystemEvent(ref SystemEventType sysEvent) + { + return InterProcessEvent.GetReadableHandle(ref sysEvent.InterProcessEvent); + } + + public static int GetWritableHandleOfSystemEvent(ref SystemEventType sysEvent) + { + return InterProcessEvent.GetWritableHandle(ref sysEvent.InterProcessEvent); + } + + public static void SignalSystemEvent(ref SystemEventType sysEvent) + { + switch (sysEvent.State) + { + case SystemEventType.InitializationState.InitializedAsInterProcess: + InterProcessEvent.Signal(ref sysEvent.InterProcessEvent); + break; + } + } + + public static void ClearSystemEvent(ref SystemEventType sysEvent) + { + switch (sysEvent.State) + { + case SystemEventType.InitializationState.InitializedAsInterProcess: + InterProcessEvent.Clear(ref sysEvent.InterProcessEvent); + break; + } + } + } +} diff --git a/Ryujinx.Horizon/Sdk/OsTypes/OsThreadManager.cs b/Ryujinx.Horizon/Sdk/OsTypes/OsThreadManager.cs new file mode 100644 index 00000000..2037cd7f --- /dev/null +++ b/Ryujinx.Horizon/Sdk/OsTypes/OsThreadManager.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.Horizon.Sdk.OsTypes +{ + static partial class Os + { + public static int GetCurrentThreadHandle() + { + return HorizonStatic.CurrentThreadHandle; + } + } +} diff --git a/Ryujinx.Horizon/Sdk/OsTypes/SystemEventType.cs b/Ryujinx.Horizon/Sdk/OsTypes/SystemEventType.cs new file mode 100644 index 00000000..338493d2 --- /dev/null +++ b/Ryujinx.Horizon/Sdk/OsTypes/SystemEventType.cs @@ -0,0 +1,17 @@ +namespace Ryujinx.Horizon.Sdk.OsTypes +{ + struct SystemEventType + { + public enum InitializationState : byte + { + NotInitialized, + InitializedAsEvent, + InitializedAsInterProcess + } + + public InterProcessEventType InterProcessEvent; + public InitializationState State; + + public bool NotInitialized => State == InitializationState.NotInitialized; + } +} diff --git a/Ryujinx.Horizon/Sdk/OsTypes/TriBool.cs b/Ryujinx.Horizon/Sdk/OsTypes/TriBool.cs new file mode 100644 index 00000000..7debd9e2 --- /dev/null +++ b/Ryujinx.Horizon/Sdk/OsTypes/TriBool.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Horizon.Sdk.OsTypes +{ + enum TriBool + { + False, + True, + Undefined + } +} |
