[sgen] Make sure we don't sweep a block if we're not supposed to
[mono.git] / mcs / class / referencesource / System / sys / system / threading / semaphore.cs
1 #if MONO
2 #undef FEATURE_PAL
3 #endif
4 // ==++==
5 // 
6 //   Copyright (c) Microsoft Corporation.  All rights reserved.
7 // 
8 // ==--==
9
10 namespace System.Threading
11 {
12     using System.IO;
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;
24 #endif
25     using System.Runtime.Versioning;
26     using System.Runtime.ConstrainedExecution;
27     using System.Runtime.CompilerServices;
28
29
30     [HostProtection(Synchronization=true, ExternalThreading=true)]
31     [ComVisibleAttribute(false)]
32     public sealed class Semaphore: WaitHandle
33     {
34         private const int MAX_PATH = 260;
35
36         // creates a nameless semaphore object
37         // Win32 only takes maximum count of Int32.MaxValue
38         [SecuritySafeCritical]
39 #if !FEATURE_NETCORE
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){}
44
45 #if FEATURE_NETCORE
46         [SecurityCritical]
47 #else
48         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
49         [ResourceExposure(ResourceScope.Machine)]
50         [ResourceConsumption(ResourceScope.Machine)]
51 #endif
52         public Semaphore(int initialCount, int maximumCount, string name)
53         {
54             if (initialCount < 0)
55             {
56                 throw new ArgumentOutOfRangeException("initialCount", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNumRequired));
57             }
58
59             if (maximumCount < 1)
60             {
61                 throw new ArgumentOutOfRangeException("maximumCount", SR.GetString(SR.ArgumentOutOfRange_NeedPosNum));
62             }
63
64             if (initialCount > maximumCount)
65             {
66                 throw new ArgumentException(SR.GetString(SR.Argument_SemaphoreInitialMaximum));
67             }
68
69             if(null != name && MAX_PATH < name.Length)
70             {
71                 throw new ArgumentException(SR.GetString(SR.Argument_WaitHandleNameTooLong));
72             }
73
74 #if MONO
75             int errorCode;
76             var myHandle = new SafeWaitHandle (CreateSemaphore_internal (initialCount, maximumCount, name, out errorCode), true);
77 #else
78             SafeWaitHandle   myHandle = SafeNativeMethods.CreateSemaphore(null, initialCount, maximumCount, name);
79 #endif
80             
81             if (myHandle.IsInvalid)
82             {
83 #if !MONO
84                 int errorCode = Marshal.GetLastWin32Error(); 
85 #endif
86
87                 if(null != name && 0 != name.Length && NativeMethods.ERROR_INVALID_HANDLE == errorCode)
88                     throw new WaitHandleCannotBeOpenedException(SR.GetString(SR.WaitHandleCannotBeOpenedException_InvalidHandle,name));
89                
90                 InternalResources.WinIOError();
91             }
92             this.SafeWaitHandle = myHandle;
93         }
94
95 #if FEATURE_NETCORE
96         [SecurityCritical]
97 #else
98         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
99         [ResourceExposure(ResourceScope.Machine)]
100         [ResourceConsumption(ResourceScope.Machine)]
101 #endif
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)
105         {
106         }
107             
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)
112 #endif
113         {
114             if (initialCount < 0)
115             {
116                 throw new ArgumentOutOfRangeException("initialCount", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNumRequired));
117             }
118
119             if (maximumCount < 1)
120             {
121                 throw new ArgumentOutOfRangeException("maximumCount", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNumRequired));
122             }
123
124             if (initialCount > maximumCount)
125             {
126                 throw new ArgumentException(SR.GetString(SR.Argument_SemaphoreInitialMaximum));
127             }
128             
129             if(null != name && MAX_PATH < name.Length)
130             {
131                 throw new ArgumentException(SR.GetString(SR.Argument_WaitHandleNameTooLong));
132             }
133             SafeWaitHandle   myHandle;
134
135 #if MONO
136             int errorCode;
137             myHandle = new SafeWaitHandle (CreateSemaphore_internal (initialCount, maximumCount, name, out errorCode), true);
138 #else
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);
149                 }
150             }
151             else {
152 #endif
153                 myHandle = SafeNativeMethods.CreateSemaphore(null, initialCount, maximumCount, name);
154 #if !FEATURE_PAL && !FEATURE_NETCORE
155             }
156 #endif
157
158             int errorCode = Marshal.GetLastWin32Error();
159 #endif
160             if (myHandle.IsInvalid)
161             {
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();
165             }
166             createdNew = errorCode != NativeMethods.ERROR_ALREADY_EXISTS;
167             this.SafeWaitHandle = myHandle;
168         }
169
170 #if FEATURE_NETCORE
171         [SecurityCritical]
172 #else
173         [ResourceExposure(ResourceScope.Machine)]
174         [ResourceConsumption(ResourceScope.Machine)]
175 #endif
176         private Semaphore(SafeWaitHandle handle)
177         {
178             this.SafeWaitHandle = handle;
179         }
180
181 #if FEATURE_NETCORE
182         [SecurityCritical]
183 #else
184         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
185         [ResourceExposure(ResourceScope.Machine)]
186         [ResourceConsumption(ResourceScope.Machine)]
187 #endif
188         public static Semaphore OpenExisting(string name)
189         {
190 #if !FEATURE_PAL && !FEATURE_NETCORE
191             return OpenExisting(name, SemaphoreRights.Modify | SemaphoreRights.Synchronize);
192         }
193
194         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
195         [ResourceExposure(ResourceScope.Machine)]
196         [ResourceConsumption(ResourceScope.Machine)]
197         public static Semaphore OpenExisting(string name, SemaphoreRights rights)
198         {
199             Semaphore result;
200             switch (OpenExistingWorker(name, rights, out result))
201 #else //FEATURE_PAL || FEATURE_NETCORE
202             Semaphore result;
203             switch (OpenExistingWorker(name, out result))
204 #endif //FEATURE_PAL || FEATURE_NETCORE
205             {
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
213                 default:
214                     return result;
215             }
216         }
217
218 #if FEATURE_NETCORE
219         [SecurityCritical]
220 #else
221         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
222         [ResourceExposure(ResourceScope.Machine)]
223         [ResourceConsumption(ResourceScope.Machine)]
224 #endif
225         public static bool TryOpenExisting(string name, out Semaphore result)
226         {
227 #if !FEATURE_PAL && !FEATURE_NETCORE
228             return OpenExistingWorker(name, SemaphoreRights.Modify | SemaphoreRights.Synchronize, out result) == OpenExistingResult.Success;
229 #else
230             return OpenExistingWorker(name, out result) == OpenExistingResult.Success;
231 #endif
232         }
233
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)
239         {
240             return OpenExistingWorker(name, rights, out result) == OpenExistingResult.Success;
241         }
242 #endif
243
244         // This exists in WaitHandle, but is oddly ifdefed for some reason...
245         private enum OpenExistingResult
246         {
247             Success,
248             NameNotFound,
249             PathNotFound,
250             NameInvalid
251         }
252
253 #if FEATURE_NETCORE
254         [SecurityCritical]
255 #else
256         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
257         [ResourceExposure(ResourceScope.Machine)]
258         [ResourceConsumption(ResourceScope.Machine)]
259 #endif
260         private static OpenExistingResult OpenExistingWorker(
261             string name, 
262 #if !FEATURE_PAL && !FEATURE_NETCORE
263             SemaphoreRights rights, 
264 #endif
265             out Semaphore result)
266         {
267             if (name == null)
268             {
269                 throw new ArgumentNullException("name");
270             }
271             if(name.Length  == 0)
272             {
273                 throw new ArgumentException(SR.GetString(SR.InvalidNullEmptyArgument, "name"), "name");
274             }
275             if(null != name && MAX_PATH < name.Length)
276             {
277                 throw new ArgumentException(SR.GetString(SR.Argument_WaitHandleNameTooLong));
278             }
279
280             result = null;
281 #if MOBILE
282             throw new NotSupportedException ();
283 #else
284
285 #if MONO
286             int errorCode;
287             var myHandle = new SafeWaitHandle (OpenSemaphore_internal (name, rights, out errorCode), true);
288 #else
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;
293
294             SafeWaitHandle myHandle = SafeNativeMethods.OpenSemaphore(SEMAPHORE_MODIFY_STATE | SYNCHRONIZE, false, name);
295 #else
296             SafeWaitHandle myHandle = SafeNativeMethods.OpenSemaphore((int) rights, false, name);
297 #endif
298 #endif
299             
300             if (myHandle.IsInvalid)
301             {
302 #if !MONO
303                 int errorCode = Marshal.GetLastWin32Error();
304 #endif
305
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();
314             }
315             result = new Semaphore(myHandle);
316             return OpenExistingResult.Success;
317 #endif
318         }
319
320
321         // increase the count on a semaphore, returns previous count
322 #if !FEATURE_NETCORE
323         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
324         [PrePrepareMethod]
325 #endif
326         public int Release()
327         {  
328             return Release(1);
329         }
330
331         // increase the count on a semaphore, returns previous count
332 #if FEATURE_NETCORE
333         [SecuritySafeCritical]
334 #else
335         [ResourceExposure(ResourceScope.None)]
336         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
337         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
338 #endif
339         public int Release(int releaseCount)
340         {
341             if (releaseCount < 1)
342             {
343                 throw new ArgumentOutOfRangeException("releaseCount", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNumRequired));
344             }
345             int previousCount;
346
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
349             //Non-Zero return 
350
351 #if MONO
352             if (!ReleaseSemaphore_internal(Handle, releaseCount, out previousCount))
353 #else
354             if (!SafeNativeMethods.ReleaseSemaphore(SafeWaitHandle, releaseCount, out previousCount))
355 #endif
356             {
357                 throw new SemaphoreFullException();
358             }
359
360             return previousCount;
361         }
362
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);
368         }
369
370         [ResourceExposure(ResourceScope.Machine)]
371         [ResourceConsumption(ResourceScope.Machine)]
372         public void SetAccessControl(SemaphoreSecurity semaphoreSecurity) {
373             if (semaphoreSecurity == null)
374                 throw new ArgumentNullException("semaphoreSecurity");
375
376             semaphoreSecurity.Persist(SafeWaitHandle);
377         }
378 #endif
379
380 #if MONO
381         [MethodImplAttribute(MethodImplOptions.InternalCall)]
382         internal static extern IntPtr CreateSemaphore_internal (
383             int initialCount, int maximumCount, string name, out int errorCode);
384
385         [MethodImplAttribute(MethodImplOptions.InternalCall)]
386         internal static extern bool ReleaseSemaphore_internal (
387             IntPtr handle, int releaseCount, out int previousCount);
388
389         [MethodImplAttribute (MethodImplOptions.InternalCall)]
390         private static extern IntPtr OpenSemaphore_internal (string name, SemaphoreRights rights, out int errorCode);
391 #endif
392     }
393 }
394