// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Threading; using EpicGames.Core; namespace UnrealBuildBase { /// /// System-wide mutex allowing only one instance of the program to run at a time /// public class GlobalSingleInstanceMutex : IDisposable { /// /// The global mutex instance /// Mutex? GlobalMutex; /// /// Constructor. Attempts to acquire the global mutex /// /// Name of the mutex to acquire /// Allow waiting for the mutex to be acquired public GlobalSingleInstanceMutex(string mutexName, bool bWaitMutex) { // Try to create the mutex, with it initially locked bool bCreatedMutex; GlobalMutex = new Mutex(true, mutexName, out bCreatedMutex); // If we didn't create the mutex, we can wait for it or fail immediately if (!bCreatedMutex) { if (bWaitMutex) { try { GlobalMutex.WaitOne(); } catch (AbandonedMutexException) { } } else { throw new BuildLogEventException(new CompilationResultException(CompilationResult.ConflictingInstance), "A conflicting instance of {Mutex} is already running.", mutexName); } } } /// /// Gets the name of a mutex unique for the given path /// /// Base name of the mutex /// Path to identify a unique mutex public static string GetUniqueMutexForPath(string name, string uniquePath) { // generate an IoHash of the path, as GetHashCode is not guaranteed to generate a stable hash return $"Global\\{name}_{IoHash.Compute(uniquePath.ToUpperInvariant())}"; } /// /// Gets the name of a mutex unique for the given path /// /// Base name of the mutex /// Path to identify a unique mutex public static string GetUniqueMutexForPath(string name, FileSystemReference? uniquePath) => GetUniqueMutexForPath(name, uniquePath?.FullName ?? String.Empty); /// /// Release the mutex and dispose of the object /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// Overridable dispose method /// /// Whether the object should be disposed protected virtual void Dispose(bool disposing) { if (disposing) { GlobalMutex?.ReleaseMutex(); GlobalMutex?.Dispose(); GlobalMutex = null; } } } }