// ==++== // // 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 } }