Align C# locking with rust

This commit is contained in:
Caelan Sayler
2024-11-02 17:42:28 +00:00
committed by Caelan
parent 4ee99ce4e0
commit d8943faf37
2 changed files with 44 additions and 14 deletions

View File

@@ -458,21 +458,13 @@ namespace Velopack
/// <summary>
/// Acquires a globally unique mutex/lock for the current application, to avoid concurrent install/uninstall/update operations.
/// </summary>
protected virtual Mutex AcquireUpdateLock()
protected virtual async Task<IDisposable> AcquireUpdateLock()
{
var mutexId = $"velopack-{AppId}";
bool created = false;
Mutex? mutex = null;
try {
mutex = new Mutex(false, mutexId, out created);
} catch (Exception ex) {
Log.Warn(ex, "Unable to acquire global mutex/lock.");
created = false;
}
if (mutex == null || !created) {
throw new Exception("Cannot perform this operation while another install/unistall operation is in progress.");
}
return mutex;
var dir = Directory.CreateDirectory(Locator.PackagesDir!);
var lockPath = Path.Combine(dir.FullName, ".velopack_lock");
var fsLock = new FileLock(lockPath);
await fsLock.LockAsync().ConfigureAwait(false);
return fsLock;
}
private static IUpdateSource CreateSimpleSource(string urlOrPath)

View File

@@ -0,0 +1,38 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace Velopack.Util
{
internal class FileLock : IDisposable
{
private readonly string _filePath;
private FileStream? _fileStream;
private bool _locked;
public FileLock(string path)
{
_filePath = path;
}
public async Task LockAsync()
{
if (_locked) {
return;
}
await IoUtil.RetryAsync(
() => {
_fileStream = new FileStream(_filePath, FileMode.Create, FileAccess.Read, FileShare.None, bufferSize: 1, FileOptions.DeleteOnClose);
_locked = true;
return Task.CompletedTask;
});
}
public void Dispose()
{
Interlocked.Exchange(ref this._fileStream, null)?.Dispose();
}
}
}