diff --git a/IPA.Loader/IPA.Loader.csproj b/IPA.Loader/IPA.Loader.csproj
index b689ce82..da6512b1 100644
--- a/IPA.Loader/IPA.Loader.csproj
+++ b/IPA.Loader/IPA.Loader.csproj
@@ -87,6 +87,7 @@
+
@@ -138,6 +139,7 @@
+
@@ -172,5 +174,8 @@
+
+
+
\ No newline at end of file
diff --git a/IPA.Loader/Utilities/Synchronization.cs b/IPA.Loader/Utilities/Synchronization.cs
new file mode 100644
index 00000000..f321b6bc
--- /dev/null
+++ b/IPA.Loader/Utilities/Synchronization.cs
@@ -0,0 +1,173 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace IPA.Utilities
+{
+ ///
+ /// Utilities for inter-thread synchronization. All Locker method acquire their object immediately.
+ ///
+ public static class Synchronization
+ {
+ #region Public types
+ ///
+ /// A synchronization state locker that releases its state when its
+ /// method is called. ALWAYS use with a block or statement. Otherwise, the locker
+ /// may not release the object be released properly.
+ ///
+ public interface ISyncStateLocker : IDisposable { }
+
+ ///
+ /// A locker type for locks.
+ /// ALWAYS use with a block or statement. Otherwise, the locker
+ /// may not release the object be released properly.
+ ///
+ public interface IReadWriteLocker : ISyncStateLocker { }
+
+ ///
+ /// An upgradable locker type for .
+ /// ALWAYS use with a block or statement. Otherwise, the locker
+ /// may not release the object be released properly.
+ ///
+ public interface IUpgradableLocker : IReadWriteLocker
+ {
+ ///
+ /// Upgrades the locker and gives a new locker to manage the upgraded lock.
+ ///
+ /// the locker to use with to manage the write lock
+ IReadWriteLocker Upgrade();
+ }
+ #endregion
+
+ #region Implementations
+ private sealed class MutexLocker : ISyncStateLocker
+ {
+ private readonly Mutex mutex;
+
+ public MutexLocker(Mutex mutex)
+ {
+ this.mutex = mutex;
+ mutex.WaitOne(); // wait and acquire mutex
+ }
+
+ public void Dispose() => mutex.ReleaseMutex(); // release mutex
+ }
+
+ private sealed class SemaphoreLocker : ISyncStateLocker
+ {
+ private readonly Semaphore sem;
+
+ public SemaphoreLocker(Semaphore sem)
+ {
+ this.sem = sem;
+ sem.WaitOne();
+ }
+
+ public void Dispose() => sem.Release();
+ }
+
+ private sealed class SemaphoreSlimLocker : ISyncStateLocker
+ {
+ private readonly SemaphoreSlim sem;
+
+ public SemaphoreSlimLocker(SemaphoreSlim sem)
+ {
+ this.sem = sem;
+ sem.Wait();
+ }
+
+ public void Dispose() => sem.Release();
+ }
+
+ private sealed class ReaderWriterLockSlimWriteLocker : IReadWriteLocker
+ {
+ private readonly ReaderWriterLockSlim rwl;
+
+ public ReaderWriterLockSlimWriteLocker(ReaderWriterLockSlim lck)
+ {
+ rwl = lck;
+ rwl.EnterWriteLock();
+ }
+
+ public void Dispose() => rwl.ExitWriteLock();
+ }
+
+ private sealed class ReaderWriterLockSlimReadLocker : IReadWriteLocker
+ {
+ private readonly ReaderWriterLockSlim rwl;
+
+ public ReaderWriterLockSlimReadLocker(ReaderWriterLockSlim lck)
+ {
+ rwl = lck;
+ rwl.EnterReadLock();
+ }
+
+ public void Dispose() => rwl.ExitReadLock();
+ }
+
+ private sealed class ReaderWriterLockSlimUpgradableReadLocker : IUpgradableLocker
+ {
+ private readonly ReaderWriterLockSlim rwl;
+
+ public ReaderWriterLockSlimUpgradableReadLocker(ReaderWriterLockSlim lck)
+ {
+ rwl = lck;
+ rwl.EnterUpgradeableReadLock();
+ }
+
+ public IReadWriteLocker Upgrade() => new ReaderWriterLockSlimWriteLocker(rwl);
+
+ public void Dispose() => rwl.ExitUpgradeableReadLock();
+ }
+ #endregion
+
+ #region Accessors
+ // TODO: add async fun stuff to this
+
+ ///
+ /// Creates an for a mutex.
+ ///
+ /// the mutex to acquire
+ /// the locker to use with
+ public static ISyncStateLocker Locker(Mutex mut) => new MutexLocker(mut);
+
+ ///
+ /// Creates an for a semaphore.
+ ///
+ /// the semaphore to acquire
+ /// the locker to use with
+ public static ISyncStateLocker Locker(Semaphore sem) => new SemaphoreLocker(sem);
+
+ ///
+ /// Creates an for a slim semaphore.
+ ///
+ /// the slim semaphore to acquire
+ /// the locker to use with
+ public static ISyncStateLocker Locker(SemaphoreSlim sem) => new SemaphoreSlimLocker(sem);
+
+ ///
+ /// Creates an for a .
+ ///
+ /// the lock to acquire in write mode
+ /// the locker to use with
+ public static IReadWriteLocker LockWrite(ReaderWriterLockSlim rwl) => new ReaderWriterLockSlimWriteLocker(rwl);
+
+ ///
+ /// Creates an for a .
+ ///
+ /// the lock to acquire in read mode
+ /// the locker to use with
+ public static IReadWriteLocker LockRead(ReaderWriterLockSlim rwl) => new ReaderWriterLockSlimReadLocker(rwl);
+
+ ///
+ /// Creates an for a .
+ ///
+ /// the lock to acquire in upgradable read mode
+ /// the locker to use with
+ public static IUpgradableLocker LockReadUpgradable(ReaderWriterLockSlim rwl) => new ReaderWriterLockSlimUpgradableReadLocker(rwl);
+ #endregion
+ }
+}