From 2e04bcad941f441e82583a5d021761aff5d48ae3 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Mon, 16 May 2022 10:20:32 -0700 Subject: [PATCH] Add a SharedLock struct --- src/LibHac/Os/ReaderWriterLock.cs | 6 +- src/LibHac/Os/ScopedLock.cs | 1 + src/LibHac/Os/SharedLock.cs | 223 ++++++++++++++++++++++++++++++ src/LibHac/Os/UniqueLock.cs | 27 +++- 4 files changed, 250 insertions(+), 7 deletions(-) create mode 100644 src/LibHac/Os/SharedLock.cs diff --git a/src/LibHac/Os/ReaderWriterLock.cs b/src/LibHac/Os/ReaderWriterLock.cs index 965b3ccd..5261d9a0 100644 --- a/src/LibHac/Os/ReaderWriterLock.cs +++ b/src/LibHac/Os/ReaderWriterLock.cs @@ -9,9 +9,9 @@ public static class ReaderWriterLockApi public static void InitializeReaderWriterLock(this OsState os, ref ReaderWriterLockType rwLock) { // Create objects. - ReaderWriterLockImpl.GetLockCount(ref rwLock).Cs.Initialize(); - rwLock.CvReadLockWaiter.Initialize(); - rwLock.CvWriteLockWaiter.Initialize(); + ReaderWriterLockImpl.GetLockCount(ref rwLock).Cs = new InternalCriticalSection(); + rwLock.CvReadLockWaiter = new InternalConditionVariable(); + rwLock.CvWriteLockWaiter = new InternalConditionVariable(); // Set member variables. ReaderWriterLockImpl.ClearReadLockCount(ref ReaderWriterLockImpl.GetLockCount(ref rwLock)); diff --git a/src/LibHac/Os/ScopedLock.cs b/src/LibHac/Os/ScopedLock.cs index cec7b25a..15e490d4 100644 --- a/src/LibHac/Os/ScopedLock.cs +++ b/src/LibHac/Os/ScopedLock.cs @@ -12,6 +12,7 @@ public static class ScopedLock } } +[NonCopyableDisposable] public ref struct ScopedLock where TMutex : IBasicLockable { private Ref _mutex; diff --git a/src/LibHac/Os/SharedLock.cs b/src/LibHac/Os/SharedLock.cs new file mode 100644 index 00000000..62a82383 --- /dev/null +++ b/src/LibHac/Os/SharedLock.cs @@ -0,0 +1,223 @@ +using System; +using System.Runtime.CompilerServices; +using System.Threading; +using LibHac.Common; + +namespace LibHac.Os; + +public static class SharedLock +{ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static SharedLockRef Lock(ref TMutex lockable) where TMutex : struct, ISharedMutex + { + return new SharedLockRef(ref lockable); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static SharedLock Lock(TMutex lockable) where TMutex : class, ISharedMutex + { + return new SharedLock(lockable); + } + +#pragma warning disable LH0001 // DoNotCopyValue +#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type + public static unsafe ref SharedLockRef Ref(this scoped in SharedLockRef value) where T : struct, ISharedMutex + { + fixed (SharedLockRef* p = &value) + { + return ref *p; + } + } +#pragma warning restore CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type +#pragma warning restore LH0001 // DoNotCopyValue + + public static ref SharedLock Ref(this in SharedLock value) where T : class, ISharedMutex + { + return ref Unsafe.AsRef(in value); + } +} + +[NonCopyableDisposable] +public ref struct SharedLockRef where TMutex : struct, ISharedMutex +{ + private Ref _mutex; + private bool _ownsLock; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public SharedLockRef(ref TMutex mutex) + { + _mutex = new Ref(ref mutex); + mutex.LockShared(); + _ownsLock = true; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public SharedLockRef(ref TMutex mutex, DeferLock tag) + { + _mutex = new Ref(ref mutex); + _ownsLock = false; + } + + public SharedLockRef(ref SharedLockRef other) + { + _mutex = other._mutex; + _ownsLock = other._ownsLock; + + other = default; + } + + public void Set(ref SharedLockRef other) + { + if (_ownsLock) + _mutex.Value.UnlockShared(); + + _mutex = default; + _ownsLock = false; + + _mutex = other._mutex; + _ownsLock = other._ownsLock; + + other = default; + } + + public void Lock() + { + if (_mutex.IsNull) + throw new SynchronizationLockException("SharedLock.Lock: References null mutex"); + + if (_ownsLock) + throw new SynchronizationLockException("SharedLock.Lock: Already locked"); + + _mutex.Value.LockShared(); + _ownsLock = true; + } + + public bool TryLock() + { + if (_mutex.IsNull) + throw new SynchronizationLockException("SharedLock.TryLock: References null mutex"); + + if (_ownsLock) + throw new SynchronizationLockException("SharedLock.TryLock: Already locked"); + + _ownsLock = _mutex.Value.TryLockShared(); + return _ownsLock; + } + + public void Unlock() + { + if (_ownsLock) + throw new SynchronizationLockException("SharedLock.Unlock: Not locked"); + + _mutex.Value.UnlockShared(); + _ownsLock = false; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_ownsLock) + _mutex.Value.UnlockShared(); + + this = default; + } +} + +[NonCopyableDisposable] +public struct SharedLock : IDisposable where TMutex : class, ISharedMutex +{ + private TMutex _mutex; + private bool _ownsLock; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public SharedLock(TMutex mutex) + { + _mutex = mutex; + mutex.LockShared(); + _ownsLock = true; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public SharedLock(TMutex mutex, DeferLock tag) + { + _mutex = mutex; + _ownsLock = false; + } + + public SharedLock(ref SharedLock other) + { + _mutex = other._mutex; + _ownsLock = other._ownsLock; + + other = default; + } + + public void Set(ref SharedLock other) + { + if (_ownsLock) + _mutex.UnlockShared(); + + _mutex = null; + _ownsLock = false; + + _mutex = other._mutex; + _ownsLock = other._ownsLock; + + other = default; + } + + public void Reset(TMutex mutex) + { + if (_ownsLock) + _mutex.UnlockShared(); + + _mutex = null; + _ownsLock = false; + + _mutex = mutex; + mutex.LockShared(); + _ownsLock = true; + } + + public void Lock() + { + if (_mutex is null) + throw new SynchronizationLockException("SharedLock.Lock: References null mutex"); + + if (_ownsLock) + throw new SynchronizationLockException("SharedLock.Lock: Already locked"); + + _mutex.LockShared(); + _ownsLock = true; + } + + public bool TryLock() + { + if (_mutex is null) + throw new SynchronizationLockException("SharedLock.TryLock: References null mutex"); + + if (_ownsLock) + throw new SynchronizationLockException("SharedLock.TryLock: Already locked"); + + _ownsLock = _mutex.TryLockShared(); + return _ownsLock; + } + + public void Unlock() + { + if (_ownsLock) + throw new SynchronizationLockException("SharedLock.Unlock: Not locked"); + + _mutex.UnlockShared(); + _ownsLock = false; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_ownsLock) + _mutex.UnlockShared(); + + this = default; + } +} \ No newline at end of file diff --git a/src/LibHac/Os/UniqueLock.cs b/src/LibHac/Os/UniqueLock.cs index 8ae04959..2b5e94ea 100644 --- a/src/LibHac/Os/UniqueLock.cs +++ b/src/LibHac/Os/UniqueLock.cs @@ -41,6 +41,7 @@ public static class UniqueLock } } +[NonCopyableDisposable] public ref struct UniqueLockRef where TMutex : struct, ILockable { private Ref _mutex; @@ -63,7 +64,9 @@ public ref struct UniqueLockRef where TMutex : struct, ILockable public UniqueLockRef(ref UniqueLockRef other) { - this = other; + _mutex = other._mutex; + _ownsLock = other._ownsLock; + other = default; } @@ -72,7 +75,12 @@ public ref struct UniqueLockRef where TMutex : struct, ILockable if (_ownsLock) _mutex.Value.Unlock(); - this = other; + _mutex = default; + _ownsLock = false; + + _mutex = other._mutex; + _ownsLock = other._ownsLock; + other = default; } @@ -119,6 +127,7 @@ public ref struct UniqueLockRef where TMutex : struct, ILockable } } +[NonCopyableDisposable] public struct UniqueLock : IDisposable where TMutex : class, ILockable { private TMutex _mutex; @@ -141,7 +150,9 @@ public struct UniqueLock : IDisposable where TMutex : class, ILockable public UniqueLock(ref UniqueLock other) { - this = other; + _mutex = other._mutex; + _ownsLock = other._ownsLock; + other = default; } @@ -150,7 +161,12 @@ public struct UniqueLock : IDisposable where TMutex : class, ILockable if (_ownsLock) _mutex.Unlock(); - this = other; + _mutex = null; + _ownsLock = false; + + _mutex = other._mutex; + _ownsLock = other._ownsLock; + other = default; } @@ -159,6 +175,9 @@ public struct UniqueLock : IDisposable where TMutex : class, ILockable if (_ownsLock) _mutex.Unlock(); + _mutex = null; + _ownsLock = false; + _mutex = mutex; mutex.Lock(); _ownsLock = true;