Add a SharedLock struct

This commit is contained in:
Alex Barney 2022-05-16 10:20:32 -07:00
parent c11a1f4eca
commit 2e04bcad94
4 changed files with 250 additions and 7 deletions

View file

@ -9,9 +9,9 @@ public static class ReaderWriterLockApi
public static void InitializeReaderWriterLock(this OsState os, ref ReaderWriterLockType rwLock) public static void InitializeReaderWriterLock(this OsState os, ref ReaderWriterLockType rwLock)
{ {
// Create objects. // Create objects.
ReaderWriterLockImpl.GetLockCount(ref rwLock).Cs.Initialize(); ReaderWriterLockImpl.GetLockCount(ref rwLock).Cs = new InternalCriticalSection();
rwLock.CvReadLockWaiter.Initialize(); rwLock.CvReadLockWaiter = new InternalConditionVariable();
rwLock.CvWriteLockWaiter.Initialize(); rwLock.CvWriteLockWaiter = new InternalConditionVariable();
// Set member variables. // Set member variables.
ReaderWriterLockImpl.ClearReadLockCount(ref ReaderWriterLockImpl.GetLockCount(ref rwLock)); ReaderWriterLockImpl.ClearReadLockCount(ref ReaderWriterLockImpl.GetLockCount(ref rwLock));

View file

@ -12,6 +12,7 @@ public static class ScopedLock
} }
} }
[NonCopyableDisposable]
public ref struct ScopedLock<TMutex> where TMutex : IBasicLockable public ref struct ScopedLock<TMutex> where TMutex : IBasicLockable
{ {
private Ref<TMutex> _mutex; private Ref<TMutex> _mutex;

223
src/LibHac/Os/SharedLock.cs Normal file
View file

@ -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<TMutex> Lock<TMutex>(ref TMutex lockable) where TMutex : struct, ISharedMutex
{
return new SharedLockRef<TMutex>(ref lockable);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static SharedLock<TMutex> Lock<TMutex>(TMutex lockable) where TMutex : class, ISharedMutex
{
return new SharedLock<TMutex>(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<T> Ref<T>(this scoped in SharedLockRef<T> value) where T : struct, ISharedMutex
{
fixed (SharedLockRef<T>* 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<T> Ref<T>(this in SharedLock<T> value) where T : class, ISharedMutex
{
return ref Unsafe.AsRef(in value);
}
}
[NonCopyableDisposable]
public ref struct SharedLockRef<TMutex> where TMutex : struct, ISharedMutex
{
private Ref<TMutex> _mutex;
private bool _ownsLock;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public SharedLockRef(ref TMutex mutex)
{
_mutex = new Ref<TMutex>(ref mutex);
mutex.LockShared();
_ownsLock = true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public SharedLockRef(ref TMutex mutex, DeferLock tag)
{
_mutex = new Ref<TMutex>(ref mutex);
_ownsLock = false;
}
public SharedLockRef(ref SharedLockRef<TMutex> other)
{
_mutex = other._mutex;
_ownsLock = other._ownsLock;
other = default;
}
public void Set(ref SharedLockRef<TMutex> 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<TMutex> : 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<TMutex> other)
{
_mutex = other._mutex;
_ownsLock = other._ownsLock;
other = default;
}
public void Set(ref SharedLock<TMutex> 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;
}
}

View file

@ -41,6 +41,7 @@ public static class UniqueLock
} }
} }
[NonCopyableDisposable]
public ref struct UniqueLockRef<TMutex> where TMutex : struct, ILockable public ref struct UniqueLockRef<TMutex> where TMutex : struct, ILockable
{ {
private Ref<TMutex> _mutex; private Ref<TMutex> _mutex;
@ -63,7 +64,9 @@ public ref struct UniqueLockRef<TMutex> where TMutex : struct, ILockable
public UniqueLockRef(ref UniqueLockRef<TMutex> other) public UniqueLockRef(ref UniqueLockRef<TMutex> other)
{ {
this = other; _mutex = other._mutex;
_ownsLock = other._ownsLock;
other = default; other = default;
} }
@ -72,7 +75,12 @@ public ref struct UniqueLockRef<TMutex> where TMutex : struct, ILockable
if (_ownsLock) if (_ownsLock)
_mutex.Value.Unlock(); _mutex.Value.Unlock();
this = other; _mutex = default;
_ownsLock = false;
_mutex = other._mutex;
_ownsLock = other._ownsLock;
other = default; other = default;
} }
@ -119,6 +127,7 @@ public ref struct UniqueLockRef<TMutex> where TMutex : struct, ILockable
} }
} }
[NonCopyableDisposable]
public struct UniqueLock<TMutex> : IDisposable where TMutex : class, ILockable public struct UniqueLock<TMutex> : IDisposable where TMutex : class, ILockable
{ {
private TMutex _mutex; private TMutex _mutex;
@ -141,7 +150,9 @@ public struct UniqueLock<TMutex> : IDisposable where TMutex : class, ILockable
public UniqueLock(ref UniqueLock<TMutex> other) public UniqueLock(ref UniqueLock<TMutex> other)
{ {
this = other; _mutex = other._mutex;
_ownsLock = other._ownsLock;
other = default; other = default;
} }
@ -150,7 +161,12 @@ public struct UniqueLock<TMutex> : IDisposable where TMutex : class, ILockable
if (_ownsLock) if (_ownsLock)
_mutex.Unlock(); _mutex.Unlock();
this = other; _mutex = null;
_ownsLock = false;
_mutex = other._mutex;
_ownsLock = other._ownsLock;
other = default; other = default;
} }
@ -159,6 +175,9 @@ public struct UniqueLock<TMutex> : IDisposable where TMutex : class, ILockable
if (_ownsLock) if (_ownsLock)
_mutex.Unlock(); _mutex.Unlock();
_mutex = null;
_ownsLock = false;
_mutex = mutex; _mutex = mutex;
mutex.Lock(); mutex.Lock();
_ownsLock = true; _ownsLock = true;