AsyncMutex add lock.
MODIFY
WalletWasabi/Stores/AsyncMutex.cs
WalletWasabi/Stores/AsyncMutex.cs
@@ -14,9 +14,11 @@ namespace WalletWasabi.Stores
private string ShortName { get; set; }
private int PollInterval { get; }
private string FullName { get; set; }
+
private Semaphore Semaphore { get; set; }
+ private int _isSemaphoreInitialized;
- public AsyncMutex(string name, int pollInterval = 1000)
+ public AsyncMutex(string name, int pollInterval = 100)
{
// https://docs.microsoft.com/en-us/dotnet/api/system.threading.mutex?view=netframework-4.8
// On a server that is running Terminal Services, a named system mutex can have two levels of visibility.
@@ -30,9 +32,35 @@ namespace WalletWasabi.Stores
ShortName = name;
PollInterval = pollInterval;
FullName = $"Global\\4AA0E5A2-A94F-4B92-B962-F2BBC7A68323-{name}";
+ _isSemaphoreInitialized = 0;
+ }
+
+ private async Task<bool> TryGetLockAsync(CancellationToken cancellationToken)
+ {
+ try
+ {
+ var start = DateTime.Now;
+ while (DateTime.Now - start < TimeSpan.FromSeconds(90))
+ {
+ var res = Interlocked.CompareExchange(ref _isSemaphoreInitialized, 1, 0);
+ if (res == 0)
+ {
+ // We have the local lock.
+ return true;
+ }
+ await Task.Delay(PollInterval, cancellationToken);
+ }
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+ return false;
}
public async Task<IDisposable> LockAsync(CancellationToken cancellationToken = default)
+ {
+ if (await TryGetLockAsync(cancellationToken))
{
try
{
@@ -70,13 +98,15 @@ namespace WalletWasabi.Stores
}
Semaphore?.Dispose();
-
+ Interlocked.Exchange(ref _isSemaphoreInitialized, 0);
+ }
throw new IOException($"Couldn't acquire system wide mutex on {ShortName}");
}
private void ReleaseLock()
{
Semaphore?.Dispose();
+ Interlocked.Exchange(ref _isSemaphoreInitialized, 0);
}
/// <summary>

AsyncMutex add lock.