3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // <OWNER>Microsoft</OWNER>
8 /*=============================================================================
10 ** Class: WaitHandle (this name is NOT definitive)
13 ** Purpose: Class to represent all synchronization objects in the runtime (that allow multiple wait)
16 =============================================================================*/
22 using Microsoft
.Win32
;
23 using Microsoft
.Win32
.SafeHandles
;
25 namespace System
.Threading
27 using System
.Threading
;
28 using System
.Runtime
.Remoting
;
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)]
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
;
58 [System
.Security
.SecuritySafeCritical
] // auto-generated
59 private static IntPtr
GetInvalidHandle()
61 return Win32Native
.INVALID_HANDLE_VALUE
;
63 protected static readonly IntPtr InvalidHandle
= GetInvalidHandle();
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
78 protected WaitHandle()
83 [System
.Security
.SecuritySafeCritical
] // auto-generated
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
102 [SecurityPermissionAttribute(SecurityAction
.InheritanceDemand
, Flags
=SecurityPermissionFlag
.UnmanagedCode
)]
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;
125 safeWaitHandle
= new SafeWaitHandle(value, true);
132 public SafeWaitHandle SafeWaitHandle
134 [System
.Security
.SecurityCritical
] // auto-generated_required
136 [SecurityPermissionAttribute(SecurityAction
.InheritanceDemand
, Flags
=SecurityPermissionFlag
.UnmanagedCode
)]
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
152 [SecurityPermissionAttribute(SecurityAction
.InheritanceDemand
, Flags
=SecurityPermissionFlag
.UnmanagedCode
)]
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
163 RuntimeHelpers
.PrepareConstrainedRegions();
169 safeWaitHandle
= null;
170 waitHandle
= InvalidHandle
;
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 ()
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
);
253 if(AppDomainPauseManager
.IsPaused
)
254 AppDomainPauseManager
.ResumeEvent
.WaitOneWithoutFAS();
257 if (ret
== WAIT_ABANDONED
)
259 ThrowAbandonedMutexException();
262 return (ret
!= WaitTimeout
);
264 return (ret
!= WaitTimeout
&& ret
!= WAIT_FAILED
);
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();
280 int ret
= WaitOneNative(safeWaitHandle
, (uint)timeout
, hasThreadAffinity
, false);
281 if (ret
== WAIT_ABANDONED
)
283 ThrowAbandonedMutexException();
286 return (ret
!= WaitTimeout
);
288 return (ret
!= WaitTimeout
&& ret
!= WAIT_FAILED
);
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
);
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 ========================================================================*/
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
);
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
335 throw new ArgumentException(Environment
.GetResourceString("Argument_EmptyWaithandleArray"));
337 throw new ArgumentNullException(Environment
.GetResourceString("Argument_EmptyWaithandleArray"));
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"));
358 if (RemotingServices
.IsTransparentProxy(waitHandle
))
359 throw new InvalidOperationException(Environment
.GetResourceString("InvalidOperation_WaitOnTransparentProxy"));
362 internalWaitHandles
[i
] = waitHandle
;
365 // make sure we do not use waitHandles any more.
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
)
376 int ret
= WaitMultiple(internalWaitHandles
, millisecondsTimeout
, exitContext
, true /* waitall*/ );
379 if(AppDomainPauseManager
.IsPaused
)
380 AppDomainPauseManager
.ResumeEvent
.WaitOneWithoutFAS();
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
);
393 return (ret
!= WaitTimeout
);
395 return (ret
!= WaitTimeout
&& ret
!= WAIT_FAILED
);
399 public static bool WaitAll(
400 WaitHandle
[] waitHandles
,
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"));
471 if (RemotingServices
.IsTransparentProxy(waitHandle
))
472 throw new InvalidOperationException(Environment
.GetResourceString("InvalidOperation_WaitOnTransparentProxy"));
475 internalWaitHandles
[i
] = waitHandle
;
478 // make sure we do not use waitHandles any more.
481 int ret
= WaitMultiple(internalWaitHandles
, millisecondsTimeout
, exitContext
, false /* waitany*/ );
484 if(AppDomainPauseManager
.IsPaused
)
485 AppDomainPauseManager
.ResumeEvent
.WaitOneWithoutFAS();
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
]);
497 ThrowAbandonedMutexException();
501 GC
.KeepAlive(internalWaitHandles
);
505 [ReliabilityContract(Consistency
.WillNotCorruptState
, Cer
.MayFail
)]
506 public static int WaitAny(
507 WaitHandle
[] waitHandles
,
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);
540 /*=================================================
544 ==================================================*/
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
);
554 public static bool SignalAndWait(
558 return SignalAndWait(toSignal
,toWaitOn
,-1,false);
561 public static bool SignalAndWait(
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(
580 int millisecondsTimeout
,
585 throw new ArgumentNullException("toSignal");
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
)
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()
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()
656 GC
.SuppressFinalize(this);