6 // Copyright (c) Microsoft Corporation. All rights reserved.
10 namespace System.Threading
13 using System.IO.Ports; // For InternalResources class
14 using Microsoft.Win32;
15 using Microsoft.Win32.SafeHandles;
16 // CoreSys build problem - we're using mscorlib's implementation assembly instead of one from asmmeta. There's a conflicting NativeMethods type.
17 using Marshal = System.Runtime.InteropServices.Marshal;
18 using ComVisibleAttribute = System.Runtime.InteropServices.ComVisibleAttribute;
19 using System.Threading;
20 using System.Security;
21 using System.Security.Permissions;
22 #if !FEATURE_PAL && !FEATURE_NETCORE
23 using System.Security.AccessControl;
25 using System.Runtime.Versioning;
26 using System.Runtime.ConstrainedExecution;
27 using System.Runtime.CompilerServices;
30 [HostProtection(Synchronization=true, ExternalThreading=true)]
31 [ComVisibleAttribute(false)]
32 public sealed class Semaphore: WaitHandle
34 private const int MAX_PATH = 260;
36 // creates a nameless semaphore object
37 // Win32 only takes maximum count of Int32.MaxValue
38 [SecuritySafeCritical]
40 [ResourceExposure(ResourceScope.None)]
41 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
42 #endif // !FEATURE_NETCORE
43 public Semaphore(int initialCount, int maximumCount) : this(initialCount,maximumCount,null){}
48 [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
49 [ResourceExposure(ResourceScope.Machine)]
50 [ResourceConsumption(ResourceScope.Machine)]
52 public Semaphore(int initialCount, int maximumCount, string name)
56 throw new ArgumentOutOfRangeException("initialCount", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNumRequired));
61 throw new ArgumentOutOfRangeException("maximumCount", SR.GetString(SR.ArgumentOutOfRange_NeedPosNum));
64 if (initialCount > maximumCount)
66 throw new ArgumentException(SR.GetString(SR.Argument_SemaphoreInitialMaximum));
69 if(null != name && MAX_PATH < name.Length)
71 throw new ArgumentException(SR.GetString(SR.Argument_WaitHandleNameTooLong));
76 var myHandle = new SafeWaitHandle (CreateSemaphore_internal (initialCount, maximumCount, name, out errorCode), true);
78 SafeWaitHandle myHandle = SafeNativeMethods.CreateSemaphore(null, initialCount, maximumCount, name);
81 if (myHandle.IsInvalid)
84 int errorCode = Marshal.GetLastWin32Error();
87 if(null != name && 0 != name.Length && NativeMethods.ERROR_INVALID_HANDLE == errorCode)
88 throw new WaitHandleCannotBeOpenedException(SR.GetString(SR.WaitHandleCannotBeOpenedException_InvalidHandle,name));
90 InternalResources.WinIOError();
92 this.SafeWaitHandle = myHandle;
98 [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
99 [ResourceExposure(ResourceScope.Machine)]
100 [ResourceConsumption(ResourceScope.Machine)]
102 public Semaphore(int initialCount, int maximumCount, string name, out bool createdNew)
103 #if !FEATURE_PAL && !FEATURE_NETCORE
104 : this(initialCount, maximumCount, name, out createdNew, null)
108 [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
109 [ResourceExposure(ResourceScope.Machine)]
110 [ResourceConsumption(ResourceScope.Machine)]
111 public unsafe Semaphore(int initialCount, int maximumCount, string name, out bool createdNew, SemaphoreSecurity semaphoreSecurity)
114 if (initialCount < 0)
116 throw new ArgumentOutOfRangeException("initialCount", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNumRequired));
119 if (maximumCount < 1)
121 throw new ArgumentOutOfRangeException("maximumCount", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNumRequired));
124 if (initialCount > maximumCount)
126 throw new ArgumentException(SR.GetString(SR.Argument_SemaphoreInitialMaximum));
129 if(null != name && MAX_PATH < name.Length)
131 throw new ArgumentException(SR.GetString(SR.Argument_WaitHandleNameTooLong));
133 SafeWaitHandle myHandle;
137 myHandle = new SafeWaitHandle (CreateSemaphore_internal (initialCount, maximumCount, name, out errorCode), true);
139 #if !FEATURE_PAL && !FEATURE_NETCORE
140 // For ACL's, get the security descriptor from the SemaphoreSecurity.
141 if (semaphoreSecurity != null) {
142 NativeMethods.SECURITY_ATTRIBUTES secAttrs = null;
143 secAttrs = new NativeMethods.SECURITY_ATTRIBUTES();
144 secAttrs.nLength = (int)Marshal.SizeOf(secAttrs);
145 byte[] sd = semaphoreSecurity.GetSecurityDescriptorBinaryForm();
146 fixed(byte* pSecDescriptor = sd) {
147 secAttrs.lpSecurityDescriptor = new SafeLocalMemHandle((IntPtr) pSecDescriptor, false);
148 myHandle = SafeNativeMethods.CreateSemaphore(secAttrs, initialCount, maximumCount, name);
153 myHandle = SafeNativeMethods.CreateSemaphore(null, initialCount, maximumCount, name);
154 #if !FEATURE_PAL && !FEATURE_NETCORE
158 int errorCode = Marshal.GetLastWin32Error();
160 if (myHandle.IsInvalid)
162 if(null != name && 0 != name.Length && NativeMethods.ERROR_INVALID_HANDLE == errorCode)
163 throw new WaitHandleCannotBeOpenedException(SR.GetString(SR.WaitHandleCannotBeOpenedException_InvalidHandle,name));
164 InternalResources.WinIOError();
166 createdNew = errorCode != NativeMethods.ERROR_ALREADY_EXISTS;
167 this.SafeWaitHandle = myHandle;
173 [ResourceExposure(ResourceScope.Machine)]
174 [ResourceConsumption(ResourceScope.Machine)]
176 private Semaphore(SafeWaitHandle handle)
178 this.SafeWaitHandle = handle;
184 [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
185 [ResourceExposure(ResourceScope.Machine)]
186 [ResourceConsumption(ResourceScope.Machine)]
188 public static Semaphore OpenExisting(string name)
190 #if !FEATURE_PAL && !FEATURE_NETCORE
191 return OpenExisting(name, SemaphoreRights.Modify | SemaphoreRights.Synchronize);
194 [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
195 [ResourceExposure(ResourceScope.Machine)]
196 [ResourceConsumption(ResourceScope.Machine)]
197 public static Semaphore OpenExisting(string name, SemaphoreRights rights)
200 switch (OpenExistingWorker(name, rights, out result))
201 #else //FEATURE_PAL || FEATURE_NETCORE
203 switch (OpenExistingWorker(name, out result))
204 #endif //FEATURE_PAL || FEATURE_NETCORE
206 case OpenExistingResult.NameNotFound:
207 throw new WaitHandleCannotBeOpenedException();
208 case OpenExistingResult.NameInvalid:
209 throw new WaitHandleCannotBeOpenedException(SR.GetString(SR.WaitHandleCannotBeOpenedException_InvalidHandle, name));
210 case OpenExistingResult.PathNotFound:
211 InternalResources.WinIOError(NativeMethods.ERROR_PATH_NOT_FOUND, string.Empty);
212 return result; //never executes
221 [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
222 [ResourceExposure(ResourceScope.Machine)]
223 [ResourceConsumption(ResourceScope.Machine)]
225 public static bool TryOpenExisting(string name, out Semaphore result)
227 #if !FEATURE_PAL && !FEATURE_NETCORE
228 return OpenExistingWorker(name, SemaphoreRights.Modify | SemaphoreRights.Synchronize, out result) == OpenExistingResult.Success;
230 return OpenExistingWorker(name, out result) == OpenExistingResult.Success;
234 #if !FEATURE_PAL && !FEATURE_NETCORE
235 [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
236 [ResourceExposure(ResourceScope.Machine)]
237 [ResourceConsumption(ResourceScope.Machine)]
238 public static bool TryOpenExisting(string name, SemaphoreRights rights, out Semaphore result)
240 return OpenExistingWorker(name, rights, out result) == OpenExistingResult.Success;
244 // This exists in WaitHandle, but is oddly ifdefed for some reason...
245 private enum OpenExistingResult
256 [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
257 [ResourceExposure(ResourceScope.Machine)]
258 [ResourceConsumption(ResourceScope.Machine)]
260 private static OpenExistingResult OpenExistingWorker(
262 #if !FEATURE_PAL && !FEATURE_NETCORE
263 SemaphoreRights rights,
265 out Semaphore result)
269 throw new ArgumentNullException("name");
273 throw new ArgumentException(SR.GetString(SR.InvalidNullEmptyArgument, "name"), "name");
275 if(null != name && MAX_PATH < name.Length)
277 throw new ArgumentException(SR.GetString(SR.Argument_WaitHandleNameTooLong));
282 throw new NotSupportedException ();
287 var myHandle = new SafeWaitHandle (OpenSemaphore_internal (name, rights, out errorCode), true);
289 //Pass false to OpenSemaphore to prevent inheritedHandles
290 #if FEATURE_PAL || FEATURE_NETCORE
291 const int SYNCHRONIZE = 0x00100000;
292 const int SEMAPHORE_MODIFY_STATE = 0x00000002;
294 SafeWaitHandle myHandle = SafeNativeMethods.OpenSemaphore(SEMAPHORE_MODIFY_STATE | SYNCHRONIZE, false, name);
296 SafeWaitHandle myHandle = SafeNativeMethods.OpenSemaphore((int) rights, false, name);
300 if (myHandle.IsInvalid)
303 int errorCode = Marshal.GetLastWin32Error();
306 if (NativeMethods.ERROR_FILE_NOT_FOUND == errorCode || NativeMethods.ERROR_INVALID_NAME == errorCode)
307 return OpenExistingResult.NameNotFound;
308 if (NativeMethods.ERROR_PATH_NOT_FOUND == errorCode)
309 return OpenExistingResult.PathNotFound;
310 if (null != name && 0 != name.Length && NativeMethods.ERROR_INVALID_HANDLE == errorCode)
311 return OpenExistingResult.NameInvalid;
312 //this is for passed through NativeMethods Errors
313 InternalResources.WinIOError();
315 result = new Semaphore(myHandle);
316 return OpenExistingResult.Success;
321 // increase the count on a semaphore, returns previous count
323 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
331 // increase the count on a semaphore, returns previous count
333 [SecuritySafeCritical]
335 [ResourceExposure(ResourceScope.None)]
336 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
337 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
339 public int Release(int releaseCount)
341 if (releaseCount < 1)
343 throw new ArgumentOutOfRangeException("releaseCount", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNumRequired));
347 //If ReleaseSempahore returns false when the specified value would cause
348 // the semaphore's count to exceed the maximum count set when Semaphore was created
352 if (!ReleaseSemaphore_internal(Handle, releaseCount, out previousCount))
354 if (!SafeNativeMethods.ReleaseSemaphore(SafeWaitHandle, releaseCount, out previousCount))
357 throw new SemaphoreFullException();
360 return previousCount;
363 #if !FEATURE_PAL && !FEATURE_NETCORE
364 [ResourceExposure(ResourceScope.None)]
365 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
366 public SemaphoreSecurity GetAccessControl() {
367 return new SemaphoreSecurity(SafeWaitHandle, AccessControlSections.Access | AccessControlSections.Owner | AccessControlSections.Group);
370 [ResourceExposure(ResourceScope.Machine)]
371 [ResourceConsumption(ResourceScope.Machine)]
372 public void SetAccessControl(SemaphoreSecurity semaphoreSecurity) {
373 if (semaphoreSecurity == null)
374 throw new ArgumentNullException("semaphoreSecurity");
376 semaphoreSecurity.Persist(SafeWaitHandle);
381 [MethodImplAttribute(MethodImplOptions.InternalCall)]
382 internal static extern IntPtr CreateSemaphore_internal (
383 int initialCount, int maximumCount, string name, out int errorCode);
385 [MethodImplAttribute(MethodImplOptions.InternalCall)]
386 internal static extern bool ReleaseSemaphore_internal (
387 IntPtr handle, int releaseCount, out int previousCount);
389 [MethodImplAttribute (MethodImplOptions.InternalCall)]
390 private static extern IntPtr OpenSemaphore_internal (string name, SemaphoreRights rights, out int errorCode);