|
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
namespace System.Threading
{
using System.IO;
using System.IO.Ports; // For InternalResources class
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
// CoreSys build problem - we're using mscorlib's implementation assembly instead of one from asmmeta. There's a conflicting NativeMethods type.
using Marshal = System.Runtime.InteropServices.Marshal;
using ComVisibleAttribute = System.Runtime.InteropServices.ComVisibleAttribute;
using System.Threading;
using System.Security;
using System.Security.Permissions;
#if !FEATURE_PAL && !FEATURE_NETCORE
using System.Security.AccessControl;
#endif
using System.Runtime.Versioning;
using System.Runtime.ConstrainedExecution;
[HostProtection(Synchronization=true, ExternalThreading=true)]
[ComVisibleAttribute(false)]
public sealed class Semaphore: WaitHandle
{
private const int MAX_PATH = 260;
// creates a nameless semaphore object
// Win32 only takes maximum count of Int32.MaxValue
[SecuritySafeCritical]
#if !FEATURE_NETCORE
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
#endif // !FEATURE_NETCORE
public Semaphore(int initialCount, int maximumCount) : this(initialCount,maximumCount,null){}
#if FEATURE_NETCORE
[SecurityCritical]
#else
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
#endif
public Semaphore(int initialCount, int maximumCount, string name)
{
if (initialCount < 0)
{
throw new ArgumentOutOfRangeException("initialCount", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNumRequired));
}
if (maximumCount < 1)
{
throw new ArgumentOutOfRangeException("maximumCount", SR.GetString(SR.ArgumentOutOfRange_NeedPosNum));
}
if (initialCount > maximumCount)
{
throw new ArgumentException(SR.GetString(SR.Argument_SemaphoreInitialMaximum));
}
if(null != name && MAX_PATH < name.Length)
{
throw new ArgumentException(SR.GetString(SR.Argument_WaitHandleNameTooLong));
}
SafeWaitHandle myHandle = SafeNativeMethods.CreateSemaphore(null, initialCount, maximumCount, name);
if (myHandle.IsInvalid)
{
int errorCode = Marshal.GetLastWin32Error();
if(null != name && 0 != name.Length && NativeMethods.ERROR_INVALID_HANDLE == errorCode)
throw new WaitHandleCannotBeOpenedException(SR.GetString(SR.WaitHandleCannotBeOpenedException_InvalidHandle,name));
InternalResources.WinIOError();
}
this.SafeWaitHandle = myHandle;
}
#if FEATURE_NETCORE
[SecurityCritical]
#else
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
#endif
public Semaphore(int initialCount, int maximumCount, string name, out bool createdNew)
#if !FEATURE_PAL && !FEATURE_NETCORE
: this(initialCount, maximumCount, name, out createdNew, null)
{
}
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
public unsafe Semaphore(int initialCount, int maximumCount, string name, out bool createdNew, SemaphoreSecurity semaphoreSecurity)
#endif
{
if (initialCount < 0)
{
throw new ArgumentOutOfRangeException("initialCount", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNumRequired));
}
if (maximumCount < 1)
{
throw new ArgumentOutOfRangeException("maximumCount", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNumRequired));
}
if (initialCount > maximumCount)
{
throw new ArgumentException(SR.GetString(SR.Argument_SemaphoreInitialMaximum));
}
if(null != name && MAX_PATH < name.Length)
{
throw new ArgumentException(SR.GetString(SR.Argument_WaitHandleNameTooLong));
}
SafeWaitHandle myHandle;
#if !FEATURE_PAL && !FEATURE_NETCORE
// For ACL's, get the security descriptor from the SemaphoreSecurity.
if (semaphoreSecurity != null) {
NativeMethods.SECURITY_ATTRIBUTES secAttrs = null;
secAttrs = new NativeMethods.SECURITY_ATTRIBUTES();
secAttrs.nLength = (int)Marshal.SizeOf(secAttrs);
byte[] sd = semaphoreSecurity.GetSecurityDescriptorBinaryForm();
fixed(byte* pSecDescriptor = sd) {
secAttrs.lpSecurityDescriptor = new SafeLocalMemHandle((IntPtr) pSecDescriptor, false);
myHandle = SafeNativeMethods.CreateSemaphore(secAttrs, initialCount, maximumCount, name);
}
}
else {
#endif
myHandle = SafeNativeMethods.CreateSemaphore(null, initialCount, maximumCount, name);
#if !FEATURE_PAL && !FEATURE_NETCORE
}
#endif
int errorCode = Marshal.GetLastWin32Error();
if (myHandle.IsInvalid)
{
if(null != name && 0 != name.Length && NativeMethods.ERROR_INVALID_HANDLE == errorCode)
throw new WaitHandleCannotBeOpenedException(SR.GetString(SR.WaitHandleCannotBeOpenedException_InvalidHandle,name));
InternalResources.WinIOError();
}
createdNew = errorCode != NativeMethods.ERROR_ALREADY_EXISTS;
this.SafeWaitHandle = myHandle;
}
#if FEATURE_NETCORE
[SecurityCritical]
#else
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
#endif
private Semaphore(SafeWaitHandle handle)
{
this.SafeWaitHandle = handle;
}
#if FEATURE_NETCORE
[SecurityCritical]
#else
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
#endif
public static Semaphore OpenExisting(string name)
{
#if !FEATURE_PAL && !FEATURE_NETCORE
return OpenExisting(name, SemaphoreRights.Modify | SemaphoreRights.Synchronize);
}
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
public static Semaphore OpenExisting(string name, SemaphoreRights rights)
{
Semaphore result;
switch (OpenExistingWorker(name, rights, out result))
#else //FEATURE_PAL || FEATURE_NETCORE
Semaphore result;
switch (OpenExistingWorker(name, out result))
#endif //FEATURE_PAL || FEATURE_NETCORE
{
case OpenExistingResult.NameNotFound:
throw new WaitHandleCannotBeOpenedException();
case OpenExistingResult.NameInvalid:
throw new WaitHandleCannotBeOpenedException(SR.GetString(SR.WaitHandleCannotBeOpenedException_InvalidHandle, name));
case OpenExistingResult.PathNotFound:
InternalResources.WinIOError(NativeMethods.ERROR_PATH_NOT_FOUND, string.Empty);
return result; //never executes
default:
return result;
}
}
#if FEATURE_NETCORE
[SecurityCritical]
#else
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
#endif
public static bool TryOpenExisting(string name, out Semaphore result)
{
#if !FEATURE_PAL && !FEATURE_NETCORE
return OpenExistingWorker(name, SemaphoreRights.Modify | SemaphoreRights.Synchronize, out result) == OpenExistingResult.Success;
#else
return OpenExistingWorker(name, out result) == OpenExistingResult.Success;
#endif
}
#if !FEATURE_PAL && !FEATURE_NETCORE
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
public static bool TryOpenExisting(string name, SemaphoreRights rights, out Semaphore result)
{
return OpenExistingWorker(name, rights, out result) == OpenExistingResult.Success;
}
#endif
// This exists in WaitHandle, but is oddly ifdefed for some reason...
private enum OpenExistingResult
{
Success,
NameNotFound,
PathNotFound,
NameInvalid
}
#if FEATURE_NETCORE
[SecurityCritical]
#else
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
#endif
private static OpenExistingResult OpenExistingWorker(
string name,
#if !FEATURE_PAL && !FEATURE_NETCORE
SemaphoreRights rights,
#endif
out Semaphore result)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
if(name.Length == 0)
{
throw new ArgumentException(SR.GetString(SR.InvalidNullEmptyArgument, "name"), "name");
}
if(null != name && MAX_PATH < name.Length)
{
throw new ArgumentException(SR.GetString(SR.Argument_WaitHandleNameTooLong));
}
result = null;
//Pass false to OpenSemaphore to prevent inheritedHandles
#if FEATURE_PAL || FEATURE_NETCORE
const int SYNCHRONIZE = 0x00100000;
const int SEMAPHORE_MODIFY_STATE = 0x00000002;
SafeWaitHandle myHandle = SafeNativeMethods.OpenSemaphore(SEMAPHORE_MODIFY_STATE | SYNCHRONIZE, false, name);
#else
SafeWaitHandle myHandle = SafeNativeMethods.OpenSemaphore((int) rights, false, name);
#endif
if (myHandle.IsInvalid)
{
int errorCode = Marshal.GetLastWin32Error();
if (NativeMethods.ERROR_FILE_NOT_FOUND == errorCode || NativeMethods.ERROR_INVALID_NAME == errorCode)
return OpenExistingResult.NameNotFound;
if (NativeMethods.ERROR_PATH_NOT_FOUND == errorCode)
return OpenExistingResult.PathNotFound;
if (null != name && 0 != name.Length && NativeMethods.ERROR_INVALID_HANDLE == errorCode)
return OpenExistingResult.NameInvalid;
//this is for passed through NativeMethods Errors
InternalResources.WinIOError();
}
result = new Semaphore(myHandle);
return OpenExistingResult.Success;
}
// increase the count on a semaphore, returns previous count
#if !FEATURE_NETCORE
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[PrePrepareMethod]
#endif
public int Release()
{
return Release(1);
}
// increase the count on a semaphore, returns previous count
#if FEATURE_NETCORE
[SecuritySafeCritical]
#else
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
#endif
public int Release(int releaseCount)
{
if (releaseCount < 1)
{
throw new ArgumentOutOfRangeException("releaseCount", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNumRequired));
}
int previousCount;
//If ReleaseSempahore returns false when the specified value would cause
// the semaphore's count to exceed the maximum count set when Semaphore was created
//Non-Zero return
if (!SafeNativeMethods.ReleaseSemaphore(SafeWaitHandle, releaseCount, out previousCount))
{
throw new SemaphoreFullException();
}
return previousCount;
}
#if !FEATURE_PAL && !FEATURE_NETCORE
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
public SemaphoreSecurity GetAccessControl() {
return new SemaphoreSecurity(SafeWaitHandle, AccessControlSections.Access | AccessControlSections.Owner | AccessControlSections.Group);
}
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
public void SetAccessControl(SemaphoreSecurity semaphoreSecurity) {
if (semaphoreSecurity == null)
throw new ArgumentNullException("semaphoreSecurity");
semaphoreSecurity.Persist(SafeWaitHandle);
}
#endif
}
}
|