Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / mscorlib / system / threading / waithandle.cs
blob1dfaac3e7dce0d5aebc53fd383dfd3a751b7a234
1 // ==++==
2 //
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 //
5 // ==--==
6 //
7 // <OWNER>Microsoft</OWNER>
8 /*=============================================================================
9 **
10 ** Class: WaitHandle (this name is NOT definitive)
13 ** Purpose: Class to represent all synchronization objects in the runtime (that allow multiple wait)
16 =============================================================================*/
18 #if MONO
19 #undef FEATURE_PAL
20 #endif
22 using Microsoft.Win32;
23 using Microsoft.Win32.SafeHandles;
25 namespace System.Threading
27 using System.Threading;
28 using System.Runtime.Remoting;
29 using System;
30 using System.Security.Permissions;
31 using System.Runtime.CompilerServices;
32 using System.Runtime.InteropServices;
33 using System.Runtime.Versioning;
34 using System.Runtime.ConstrainedExecution;
35 using System.Diagnostics.Contracts;
36 using System.Diagnostics.CodeAnalysis;
38 [System.Runtime.InteropServices.ComVisible(true)]
39 #if FEATURE_REMOTING
40 public abstract partial class WaitHandle : MarshalByRefObject, IDisposable {
41 #else // FEATURE_REMOTING
42 public abstract partial class WaitHandle : IDisposable {
43 #endif // FEATURE_REMOTING
44 public const int WaitTimeout = 0x102;
46 private const int MAX_WAITHANDLES = 64;
48 #pragma warning disable 414 // Field is not used from managed.
49 private IntPtr waitHandle; // !!! DO NOT MOVE THIS FIELD. (See defn of WAITHANDLEREF in object.h - has hardcoded access to this field.)
50 #pragma warning restore 414
52 [System.Security.SecurityCritical] // auto-generated
53 internal volatile SafeWaitHandle safeWaitHandle;
55 internal bool hasThreadAffinity;
57 #if !MONO
58 [System.Security.SecuritySafeCritical] // auto-generated
59 private static IntPtr GetInvalidHandle()
61 return Win32Native.INVALID_HANDLE_VALUE;
63 protected static readonly IntPtr InvalidHandle = GetInvalidHandle();
64 #endif // !MONO
65 private const int WAIT_OBJECT_0 = 0;
66 private const int WAIT_ABANDONED = 0x80;
67 private const int WAIT_FAILED = 0x7FFFFFFF;
68 private const int ERROR_TOO_MANY_POSTS = 0x12A;
70 internal enum OpenExistingResult
72 Success,
73 NameNotFound,
74 PathNotFound,
75 NameInvalid
78 protected WaitHandle()
80 Init();
83 [System.Security.SecuritySafeCritical] // auto-generated
84 private void Init()
86 safeWaitHandle = null;
87 waitHandle = InvalidHandle;
88 hasThreadAffinity = false;
92 [Obsolete("Use the SafeWaitHandle property instead.")]
93 public virtual IntPtr Handle
95 [System.Security.SecuritySafeCritical] // auto-generated
96 [ResourceExposure(ResourceScope.Machine)]
97 [ResourceConsumption(ResourceScope.Machine)]
98 get { return safeWaitHandle == null ? InvalidHandle : safeWaitHandle.DangerousGetHandle();}
100 [System.Security.SecurityCritical] // auto-generated_required
101 #if !FEATURE_CORECLR
102 [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
103 #endif
104 [ResourceExposure(ResourceScope.Machine)]
105 [ResourceConsumption(ResourceScope.Machine)]
108 if (value == InvalidHandle)
110 // This line leaks a handle. However, it's currently
111 // not perfectly clear what the right behavior is here
112 // anyways. This preserves Everett behavior. We should
113 // ideally do these things:
114 // *) Expose a settable SafeHandle property on WaitHandle.
115 // *) Expose a settable OwnsHandle property on SafeHandle.
116 // We're looking into this. -- Microsoft
117 if (safeWaitHandle != null)
119 safeWaitHandle.SetHandleAsInvalid();
120 safeWaitHandle = null;
123 else
125 safeWaitHandle = new SafeWaitHandle(value, true);
127 waitHandle = value;
132 public SafeWaitHandle SafeWaitHandle
134 [System.Security.SecurityCritical] // auto-generated_required
135 #if !FEATURE_CORECLR
136 [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
137 #endif
138 [ResourceExposure(ResourceScope.Machine)]
139 [ResourceConsumption(ResourceScope.Machine)]
140 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
143 if (safeWaitHandle == null)
145 safeWaitHandle = new SafeWaitHandle(InvalidHandle, false);
147 return safeWaitHandle;
150 [System.Security.SecurityCritical] // auto-generated_required
151 #if !FEATURE_CORECLR
152 [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
153 #endif
154 [ResourceExposure(ResourceScope.Machine)]
155 [ResourceConsumption(ResourceScope.Machine)]
156 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
159 // Set safeWaitHandle and waitHandle in a CER so we won't take
160 // a thread abort between the statements and leave the wait
161 // handle in an invalid state. Note this routine is not thread
162 // safe however.
163 RuntimeHelpers.PrepareConstrainedRegions();
164 try { }
165 finally
167 if (value == null)
169 safeWaitHandle = null;
170 waitHandle = InvalidHandle;
172 else
174 safeWaitHandle = value;
175 waitHandle = safeWaitHandle.DangerousGetHandle();
181 // Assembly-private version that doesn't do a security check. Reduces the
182 // number of link-time security checks when reading & writing to a file,
183 // and helps avoid a link time check while initializing security (If you
184 // call a Serialization method that requires security before security
185 // has started up, the link time check will start up security, run
186 // serialization code for some security attribute stuff, call into
187 // FileStream, which will then call Sethandle, which requires a link time
188 // security check.). While security has fixed that problem, we still
189 // don't need to do a linktime check here.
190 [System.Security.SecurityCritical] // auto-generated
191 [ResourceExposure(ResourceScope.Machine)]
192 [ResourceConsumption(ResourceScope.Machine)]
193 internal void SetHandleInternal(SafeWaitHandle handle)
195 safeWaitHandle = handle;
196 waitHandle = handle.DangerousGetHandle();
199 public virtual bool WaitOne (int millisecondsTimeout, bool exitContext)
201 if (millisecondsTimeout < -1)
203 throw new ArgumentOutOfRangeException("millisecondsTimeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
205 Contract.EndContractBlock();
206 return WaitOne((long)millisecondsTimeout,exitContext);
209 public virtual bool WaitOne (TimeSpan timeout, bool exitContext)
211 long tm = (long)timeout.TotalMilliseconds;
212 if (-1 > tm || (long) Int32.MaxValue < tm)
214 throw new ArgumentOutOfRangeException("timeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
216 return WaitOne(tm,exitContext);
219 public virtual bool WaitOne ()
221 //Infinite Timeout
222 return WaitOne(-1,false);
225 public virtual bool WaitOne(int millisecondsTimeout)
227 return WaitOne(millisecondsTimeout, false);
230 public virtual bool WaitOne(TimeSpan timeout)
232 return WaitOne(timeout, false);
235 [System.Security.SecuritySafeCritical] // auto-generated
236 [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "Reviewed for thread-safety.")]
237 private bool WaitOne(long timeout, bool exitContext)
239 return InternalWaitOne(safeWaitHandle, timeout, hasThreadAffinity, exitContext);
242 [System.Security.SecurityCritical] // auto-generated
243 internal static bool InternalWaitOne(SafeHandle waitableSafeHandle, long millisecondsTimeout, bool hasThreadAffinity, bool exitContext)
245 if (waitableSafeHandle == null)
247 throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_Generic"));
249 Contract.EndContractBlock();
250 int ret = WaitOneNative(waitableSafeHandle, (uint)millisecondsTimeout, hasThreadAffinity, exitContext);
252 #if !MONO
253 if(AppDomainPauseManager.IsPaused)
254 AppDomainPauseManager.ResumeEvent.WaitOneWithoutFAS();
255 #endif // !MONO
257 if (ret == WAIT_ABANDONED)
259 ThrowAbandonedMutexException();
261 #if !MONO
262 return (ret != WaitTimeout);
263 #else
264 return (ret != WaitTimeout && ret != WAIT_FAILED);
265 #endif
268 [System.Security.SecurityCritical]
269 internal bool WaitOneWithoutFAS()
271 // version of waitone without fast application switch (FAS) support
272 // This is required to support the Wait which FAS needs (otherwise recursive dependency comes in)
273 if (safeWaitHandle == null)
275 throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_Generic"));
277 Contract.EndContractBlock();
279 long timeout = -1;
280 int ret = WaitOneNative(safeWaitHandle, (uint)timeout, hasThreadAffinity, false);
281 if (ret == WAIT_ABANDONED)
283 ThrowAbandonedMutexException();
285 #if !MONO
286 return (ret != WaitTimeout);
287 #else
288 return (ret != WaitTimeout && ret != WAIT_FAILED);
289 #endif
292 #if !MONO
293 [System.Security.SecurityCritical] // auto-generated
294 [ResourceExposure(ResourceScope.None)]
295 [MethodImplAttribute(MethodImplOptions.InternalCall)]
296 private static extern int WaitOneNative(SafeHandle waitableSafeHandle, uint millisecondsTimeout, bool hasThreadAffinity, bool exitContext);
297 #endif // !MONO
299 /*========================================================================
300 ** Waits for signal from all the objects.
301 ** timeout indicates how long to wait before the method returns.
302 ** This method will return either when all the object have been pulsed
303 ** or timeout milliseonds have elapsed.
304 ** If exitContext is true then the synchronization domain for the context
305 ** (if in a synchronized context) is exited before the wait and reacquired
306 ========================================================================*/
308 #if !MONO
309 [System.Security.SecurityCritical] // auto-generated
310 [ResourceExposure(ResourceScope.None)]
311 [MethodImplAttribute(MethodImplOptions.InternalCall)]
312 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
313 private static extern int WaitMultiple(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext, bool WaitAll);
314 #endif // !MONO
316 [System.Security.SecuritySafeCritical] // auto-generated
317 public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
319 if (waitHandles == null)
321 throw new ArgumentNullException(Environment.GetResourceString("ArgumentNull_Waithandles"));
323 if(waitHandles.Length == 0)
326 // Some history: in CLR 1.0 and 1.1, we threw ArgumentException in this case, which was correct.
327 // Somehow, in 2.0, this became ArgumentNullException. This was not fixed until Silverlight 2,
328 // which went back to ArgumentException.
330 // Now we're in a bit of a bind. Backward-compatibility requires us to keep throwing ArgumentException
331 // in CoreCLR, and ArgumentNullException in the desktop CLR. This is ugly, but so is breaking
332 // user code.
334 #if FEATURE_CORECLR
335 throw new ArgumentException(Environment.GetResourceString("Argument_EmptyWaithandleArray"));
336 #else
337 throw new ArgumentNullException(Environment.GetResourceString("Argument_EmptyWaithandleArray"));
338 #endif
340 if (waitHandles.Length > MAX_WAITHANDLES)
342 throw new NotSupportedException(Environment.GetResourceString("NotSupported_MaxWaitHandles"));
344 if (-1 > millisecondsTimeout)
346 throw new ArgumentOutOfRangeException("millisecondsTimeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
348 Contract.EndContractBlock();
349 WaitHandle[] internalWaitHandles = new WaitHandle[waitHandles.Length];
350 for (int i = 0; i < waitHandles.Length; i ++)
352 WaitHandle waitHandle = waitHandles[i];
354 if (waitHandle == null)
355 throw new ArgumentNullException(Environment.GetResourceString("ArgumentNull_ArrayElement"));
357 #if FEATURE_REMOTING
358 if (RemotingServices.IsTransparentProxy(waitHandle))
359 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_WaitOnTransparentProxy"));
360 #endif
362 internalWaitHandles[i] = waitHandle;
364 #if _DEBUG
365 // make sure we do not use waitHandles any more.
366 waitHandles = null;
367 #endif
369 #if FEATURE_LEGACYNETCF
370 // WinCE did not support "wait all." It turns out that this resulted in NetCF's WaitAll implementation always returning true.
371 // Unfortunately, some apps took a dependency on that, so we have to replicate the behavior here.
372 if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
373 return true;
374 #endif
376 int ret = WaitMultiple(internalWaitHandles, millisecondsTimeout, exitContext, true /* waitall*/ );
378 #if !MONO
379 if(AppDomainPauseManager.IsPaused)
380 AppDomainPauseManager.ResumeEvent.WaitOneWithoutFAS();
381 #endif // !MONO
383 if ((WAIT_ABANDONED <= ret) && (WAIT_ABANDONED+internalWaitHandles.Length > ret))
385 //In the case of WaitAll the OS will only provide the
386 // information that mutex was abandoned.
387 // It won't tell us which one. So we can't set the Index or provide access to the Mutex
388 ThrowAbandonedMutexException();
391 GC.KeepAlive(internalWaitHandles);
392 #if !MONO
393 return (ret != WaitTimeout);
394 #else
395 return (ret != WaitTimeout && ret != WAIT_FAILED);
396 #endif
399 public static bool WaitAll(
400 WaitHandle[] waitHandles,
401 TimeSpan timeout,
402 bool exitContext)
404 long tm = (long)timeout.TotalMilliseconds;
405 if (-1 > tm || (long) Int32.MaxValue < tm)
407 throw new ArgumentOutOfRangeException("timeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
409 return WaitAll(waitHandles,(int)tm, exitContext);
413 /*========================================================================
414 ** Shorthand for WaitAll with timeout = Timeout.Infinite and exitContext = true
415 ========================================================================*/
416 public static bool WaitAll(WaitHandle[] waitHandles)
418 return WaitAll(waitHandles, Timeout.Infinite, true);
421 public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout)
423 return WaitAll(waitHandles, millisecondsTimeout, true);
426 public static bool WaitAll(WaitHandle[] waitHandles, TimeSpan timeout)
428 return WaitAll(waitHandles, timeout, true);
432 /*========================================================================
433 ** Waits for notification from any of the objects.
434 ** timeout indicates how long to wait before the method returns.
435 ** This method will return either when either one of the object have been
436 ** signalled or timeout milliseonds have elapsed.
437 ** If exitContext is true then the synchronization domain for the context
438 ** (if in a synchronized context) is exited before the wait and reacquired
439 ========================================================================*/
441 [System.Security.SecuritySafeCritical] // auto-generated
442 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
443 public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
445 if (waitHandles==null)
447 throw new ArgumentNullException(Environment.GetResourceString("ArgumentNull_Waithandles"));
449 if(waitHandles.Length == 0)
451 throw new ArgumentException(Environment.GetResourceString("Argument_EmptyWaithandleArray"));
453 if (MAX_WAITHANDLES < waitHandles.Length)
455 throw new NotSupportedException(Environment.GetResourceString("NotSupported_MaxWaitHandles"));
457 if (-1 > millisecondsTimeout)
459 throw new ArgumentOutOfRangeException("millisecondsTimeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
461 Contract.EndContractBlock();
462 WaitHandle[] internalWaitHandles = new WaitHandle[waitHandles.Length];
463 for (int i = 0; i < waitHandles.Length; i ++)
465 WaitHandle waitHandle = waitHandles[i];
467 if (waitHandle == null)
468 throw new ArgumentNullException(Environment.GetResourceString("ArgumentNull_ArrayElement"));
470 #if FEATURE_REMOTING
471 if (RemotingServices.IsTransparentProxy(waitHandle))
472 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_WaitOnTransparentProxy"));
473 #endif
475 internalWaitHandles[i] = waitHandle;
477 #if _DEBUG
478 // make sure we do not use waitHandles any more.
479 waitHandles = null;
480 #endif
481 int ret = WaitMultiple(internalWaitHandles, millisecondsTimeout, exitContext, false /* waitany*/ );
483 #if !MONO
484 if(AppDomainPauseManager.IsPaused)
485 AppDomainPauseManager.ResumeEvent.WaitOneWithoutFAS();
486 #endif // !MONO
488 if ((WAIT_ABANDONED <= ret) && (WAIT_ABANDONED+internalWaitHandles.Length > ret))
490 int mutexIndex = ret -WAIT_ABANDONED;
491 if(0 <= mutexIndex && mutexIndex < internalWaitHandles.Length)
493 ThrowAbandonedMutexException(mutexIndex,internalWaitHandles[mutexIndex]);
495 else
497 ThrowAbandonedMutexException();
501 GC.KeepAlive(internalWaitHandles);
502 return ret;
505 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
506 public static int WaitAny(
507 WaitHandle[] waitHandles,
508 TimeSpan timeout,
509 bool exitContext)
511 long tm = (long)timeout.TotalMilliseconds;
512 if (-1 > tm || (long) Int32.MaxValue < tm)
514 throw new ArgumentOutOfRangeException("timeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
516 return WaitAny(waitHandles,(int)tm, exitContext);
518 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
519 public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout)
521 return WaitAny(waitHandles, timeout, true);
525 /*========================================================================
526 ** Shorthand for WaitAny with timeout = Timeout.Infinite and exitContext = true
527 ========================================================================*/
528 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
529 public static int WaitAny(WaitHandle[] waitHandles)
531 return WaitAny(waitHandles, Timeout.Infinite, true);
534 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
535 public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout)
537 return WaitAny(waitHandles, millisecondsTimeout, true);
539 #if !FEATURE_PAL
540 /*=================================================
542 == SignalAndWait
544 ==================================================*/
546 #if !MONO
547 [System.Security.SecurityCritical] // auto-generated
548 [ResourceExposure(ResourceScope.None)]
549 [MethodImplAttribute(MethodImplOptions.InternalCall)]
550 private static extern int SignalAndWaitOne(SafeWaitHandle waitHandleToSignal,SafeWaitHandle waitHandleToWaitOn, int millisecondsTimeout,
551 bool hasThreadAffinity, bool exitContext);
552 #endif // !MONO
554 public static bool SignalAndWait(
555 WaitHandle toSignal,
556 WaitHandle toWaitOn)
558 return SignalAndWait(toSignal,toWaitOn,-1,false);
561 public static bool SignalAndWait(
562 WaitHandle toSignal,
563 WaitHandle toWaitOn,
564 TimeSpan timeout,
565 bool exitContext)
567 long tm = (long)timeout.TotalMilliseconds;
568 if (-1 > tm || (long) Int32.MaxValue < tm)
570 throw new ArgumentOutOfRangeException("timeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
572 return SignalAndWait(toSignal,toWaitOn,(int)tm,exitContext);
575 [System.Security.SecuritySafeCritical] // auto-generated
576 [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "Reviewed for thread-safety.")]
577 public static bool SignalAndWait(
578 WaitHandle toSignal,
579 WaitHandle toWaitOn,
580 int millisecondsTimeout,
581 bool exitContext)
583 if(null == toSignal)
585 throw new ArgumentNullException("toSignal");
587 if(null == toWaitOn)
589 throw new ArgumentNullException("toWaitOn");
591 if (-1 > millisecondsTimeout)
593 throw new ArgumentOutOfRangeException("millisecondsTimeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
595 Contract.EndContractBlock();
597 //NOTE: This API is not supporting Pause/Resume as it's not exposed in CoreCLR (not in WP or SL)
598 int ret = SignalAndWaitOne(toSignal.safeWaitHandle,toWaitOn.safeWaitHandle,millisecondsTimeout,
599 toWaitOn.hasThreadAffinity,exitContext);
601 if(WAIT_FAILED != ret && toSignal.hasThreadAffinity)
603 Thread.EndCriticalRegion();
604 Thread.EndThreadAffinity();
607 if(WAIT_ABANDONED == ret)
609 ThrowAbandonedMutexException();
612 if(ERROR_TOO_MANY_POSTS == ret)
614 throw new InvalidOperationException(Environment.GetResourceString("Threading.WaitHandleTooManyPosts"));
617 //Object was signaled
618 if(WAIT_OBJECT_0 == ret)
620 return true;
623 //Timeout
624 return false;
626 #endif
628 private static void ThrowAbandonedMutexException()
630 throw new AbandonedMutexException();
633 private static void ThrowAbandonedMutexException(int location, WaitHandle handle)
635 throw new AbandonedMutexException(location, handle);
638 public virtual void Close()
640 Dispose(true);
641 GC.SuppressFinalize(this);
644 [System.Security.SecuritySafeCritical] // auto-generated
645 protected virtual void Dispose(bool explicitDisposing)
647 if (safeWaitHandle != null)
649 safeWaitHandle.Close();
653 public void Dispose()
655 Dispose(true);
656 GC.SuppressFinalize(this);