public static Semaphore GetNamedSemaphore(string name, int maximumCount = 10, int initialCount = -1)
{
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentNullException("name", "Argument cannot be empty, null or white space.");
Semaphore namedSemaphore = null;
bool doesNotExist = false;
bool unauthorized = false;
if (initialCount < 0)
initialCount = maximumCount;
// Create a semaphore name that is specific to an object (e.g., a path and file name).
string semaphoreName = Cipher.GetPasswordHash(name.ToLower(), SemaphoreHash).Replace('\\', '-');
// Attempt to open the named semaphore
try
{
namedSemaphore = Semaphore.OpenExisting(semaphoreName);
}
catch (WaitHandleCannotBeOpenedException)
{
doesNotExist = true;
}
catch (UnauthorizedAccessException)
{
unauthorized = true;
}
// Mono Semaphore implementations do not include ability to change access rules
#if MONO
// If semaphore does not exist we create it
if (doesNotExist || unauthorized)
{
try
{
bool semaphoreWasCreated;
namedSemaphore = new Semaphore(initialCount, maximumCount, semaphoreName, out semaphoreWasCreated);
if (!semaphoreWasCreated)
throw new InvalidOperationException("Failed to create semaphore.");
}
catch (UnauthorizedAccessException ex)
{
throw new InvalidOperationException("Failed to create semaphore: " + ex.Message);
}
}
#else
// If semaphore does not exist we create it
if (doesNotExist)
{
try
{
SemaphoreSecurity security = new SemaphoreSecurity();
bool semaphoreWasCreated;
security.AddAccessRule(new SemaphoreAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), SemaphoreRights.FullControl, AccessControlType.Allow));
namedSemaphore = new Semaphore(initialCount, maximumCount, semaphoreName, out semaphoreWasCreated, security);
if (!semaphoreWasCreated)
throw new InvalidOperationException("Failed to create semaphore.");
}
catch (UnauthorizedAccessException)
{
SemaphoreSecurity security = new SemaphoreSecurity();
bool semaphoreWasCreated;
security.AddAccessRule(new SemaphoreAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), SemaphoreRights.Synchronize | SemaphoreRights.Modify, AccessControlType.Allow));
namedSemaphore = new Semaphore(initialCount, maximumCount, semaphoreName, out semaphoreWasCreated, security);
if (!semaphoreWasCreated)
throw new InvalidOperationException("Failed to create semaphore.");
}
}
else if (unauthorized)
{
namedSemaphore = Semaphore.OpenExisting(semaphoreName, SemaphoreRights.ReadPermissions | SemaphoreRights.ChangePermissions);
// Get the current ACL. This requires MutexRights.ReadPermission
SemaphoreSecurity security = new SemaphoreSecurity();
SemaphoreAccessRule rule = new SemaphoreAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), SemaphoreRights.FullControl, AccessControlType.Allow);
security.RemoveAccessRule(rule);
// Now grant specific user rights for less than full access
rule = new SemaphoreAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), SemaphoreRights.Synchronize | SemaphoreRights.Modify, AccessControlType.Allow);
security.AddAccessRule(rule);
// Update the ACL. This requires MutexRighs.ChangePermission.
namedSemaphore.SetAccessControl(security);
namedSemaphore = Semaphore.OpenExisting(semaphoreName);
}
#endif
return namedSemaphore;
}