The Labs \ Source Viewer \ SSCLI \ System.Threading \ WaitHandle

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*=============================================================================
  16. **
  17. ** Class: WaitHandle    (this name is NOT definitive)
  18. **
  19. **
  20. ** Purpose: Class to represent all synchronization objects in the runtime (that allow multiple wait)
  21. **
  22. **
  23. =============================================================================*/
  24. namespace System.Threading
  25. {
  26.     using System.Threading;
  27.     using System.Runtime.Remoting;
  28.     using System;
  29.     using System.Security.Permissions;
  30.     using System.Runtime.CompilerServices;
  31.     using Microsoft.Win32.SafeHandles;
  32.     using System.Runtime.Versioning;
  33.     using System.Runtime.ConstrainedExecution;
  34.     using Win32Native = Microsoft.Win32.Win32Native;
  35.    
  36.     [System.Runtime.InteropServices.ComVisible(true)]
  37.     public abstract class WaitHandle : MarshalByRefObject, IDisposable
  38.     {
  39.         public const int WaitTimeout = 258;
  40.        
  41.         private const int MAX_WAITHANDLES = 64;
  42.        
  43.         #pragma warning disable 414 // Field is not used from managed.
  44.         private IntPtr waitHandle;
  45.         // !!! DO NOT MOVE THIS FIELD. (See defn of WAITHANDLEREF in object.h - has hardcoded access to this field.)
  46.         #pragma warning restore 414
  47.         internal SafeWaitHandle safeWaitHandle;
  48.        
  49.         internal bool hasThreadAffinity;
  50.        
  51.         protected static readonly IntPtr InvalidHandle = Win32Native.INVALID_HANDLE_VALUE;
  52.         private const int WAIT_OBJECT_0 = 0;
  53.         private const int WAIT_ABANDONED = 128;
  54.         private const int WAIT_FAILED = 2147483647;
  55.         private const int ERROR_TOO_MANY_POSTS = 298;
  56.        
  57.         protected WaitHandle()
  58.         {
  59.             safeWaitHandle = null;
  60.             waitHandle = InvalidHandle;
  61.             hasThreadAffinity = false;
  62.         }
  63.        
  64.        
  65.         [Obsolete("Use the SafeWaitHandle property instead.")]
  66.         public virtual IntPtr Handle {
  67.             [ResourceExposure(ResourceScope.Machine)]
  68.             [ResourceConsumption(ResourceScope.Machine)]
  69.             get { return safeWaitHandle == null ? InvalidHandle : safeWaitHandle.DangerousGetHandle(); }
  70.            
  71.             [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  72.             [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  73.             [ResourceExposure(ResourceScope.Machine)]
  74.             [ResourceConsumption(ResourceScope.Machine)]
  75.             set {
  76.                 if (value == InvalidHandle) {
  77.                     safeWaitHandle.SetHandleAsInvalid();
  78.                     safeWaitHandle = null;
  79.                 }
  80.                 else {
  81.                     safeWaitHandle = new SafeWaitHandle(value, true);
  82.                 }
  83.                 waitHandle = value;
  84.             }
  85.         }
  86.        
  87.        
  88.         public SafeWaitHandle SafeWaitHandle {
  89.             [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  90.             [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  91.             [ResourceExposure(ResourceScope.Machine)]
  92.             [ResourceConsumption(ResourceScope.Machine)]
  93.             [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
  94.             get {
  95.                 if (safeWaitHandle == null) {
  96.                     safeWaitHandle = new SafeWaitHandle(InvalidHandle, false);
  97.                 }
  98.                 return safeWaitHandle;
  99.             }
  100.            
  101.             [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  102.             [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  103.             [ResourceExposure(ResourceScope.Machine)]
  104.             [ResourceConsumption(ResourceScope.Machine)]
  105.             [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  106.             set {
  107.                 // Set safeWaitHandle and waitHandle in a CER so we won't take
  108.                 // a thread abort between the statements and leave the wait
  109.                 // handle in an invalid state. Note this routine is not thread
  110.                 // safe however.
  111.                 RuntimeHelpers.PrepareConstrainedRegions();
  112.                 try {
  113.                 }
  114.                 finally {
  115.                     if (value == null) {
  116.                         safeWaitHandle = null;
  117.                         waitHandle = InvalidHandle;
  118.                     }
  119.                     else {
  120.                         safeWaitHandle = value;
  121.                         waitHandle = safeWaitHandle.DangerousGetHandle();
  122.                     }
  123.                 }
  124.             }
  125.         }
  126.        
  127.         // Assembly-private version that doesn't do a security check. Reduces the
  128.         // number of link-time security checks when reading & writing to a file,
  129.         // and helps avoid a link time check while initializing security (If you
  130.         // call a Serialization method that requires security before security
  131.         // has started up, the link time check will start up security, run
  132.         // serialization code for some security attribute stuff, call into
  133.         // FileStream, which will then call Sethandle, which requires a link time
  134.         // security check.). While security has fixed that problem, we still
  135.         // don't need to do a linktime check here.
  136.         [ResourceExposure(ResourceScope.Machine)]
  137.         [ResourceConsumption(ResourceScope.Machine)]
  138.         internal void SetHandleInternal(SafeWaitHandle handle)
  139.         {
  140.             safeWaitHandle = handle;
  141.             waitHandle = handle.DangerousGetHandle();
  142.         }
  143.        
  144.         public virtual bool WaitOne(int millisecondsTimeout, bool exitContext)
  145.         {
  146.             if (millisecondsTimeout < -1) {
  147.                 throw new ArgumentOutOfRangeException("millisecondsTimeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
  148.             }
  149.             return WaitOne((long)millisecondsTimeout, exitContext);
  150.         }
  151.        
  152.         public virtual bool WaitOne(TimeSpan timeout, bool exitContext)
  153.         {
  154.             long tm = (long)timeout.TotalMilliseconds;
  155.             if (-1 > tm || (long)Int32.MaxValue < tm) {
  156.                 throw new ArgumentOutOfRangeException("timeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
  157.             }
  158.             return WaitOne(tm, exitContext);
  159.         }
  160.        
  161.         public virtual bool WaitOne()
  162.         {
  163.             //Infinite Timeout
  164.             return WaitOne(-1, false);
  165.         }
  166.        
  167.         private bool WaitOne(long timeout, bool exitContext)
  168.         {
  169.             if (safeWaitHandle == null) {
  170.                 throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_Generic"));
  171.             }
  172.             int ret = WaitOneNative(safeWaitHandle, (uint)timeout, hasThreadAffinity, exitContext);
  173.             if (ret == WAIT_ABANDONED) {
  174.                 throw new AbandonedMutexException();
  175.             }
  176.             return (ret != WaitTimeout);
  177.         }
  178.        
  179.        
  180.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  181.         private static extern int WaitOneNative(SafeWaitHandle waitHandle, uint millisecondsTimeout, bool hasThreadAffinity, bool exitContext);
  182.        
  183. /*========================================================================
  184.         ** Waits for signal from all the objects.
  185.         ** timeout indicates how long to wait before the method returns.
  186.         ** This method will return either when all the object have been pulsed
  187.         ** or timeout milliseonds have elapsed.
  188.         ** If exitContext is true then the synchronization domain for the context
  189.         ** (if in a synchronized context) is exited before the wait and reacquired
  190.         ========================================================================*/       
  191.        
  192.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  193.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
  194.         private static extern int WaitMultiple(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext, bool WaitAll);
  195.        
  196.        
  197.         public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
  198.         {
  199.             if (waitHandles == null || waitHandles.Length == 0) {
  200.                 throw new ArgumentNullException("waitHandles");
  201.             }
  202.             if (waitHandles.Length > MAX_WAITHANDLES) {
  203.                 throw new NotSupportedException(Environment.GetResourceString("NotSupported_MaxWaitHandles"));
  204.             }
  205.             if (-1 > millisecondsTimeout) {
  206.                 throw new ArgumentOutOfRangeException("millisecondsTimeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
  207.             }
  208.             WaitHandle[] internalWaitHandles = new WaitHandle[waitHandles.Length];
  209.             for (int i = 0; i < waitHandles.Length; i++) {
  210.                 internalWaitHandles[i] = waitHandles[i];
  211.             }
  212.             #if _DEBUG
  213.             // make sure we do not use waitHandles any more.
  214.             waitHandles = null;
  215.             #endif
  216.                 /* waitall*/            int ret = WaitMultiple(internalWaitHandles, millisecondsTimeout, exitContext, true);
  217.             if ((WAIT_ABANDONED <= ret) && (WAIT_ABANDONED + internalWaitHandles.Length > ret)) {
  218.                 //In the case of WaitAll the OS will only provide the
  219.                 // information that mutex was abandoned.
  220.                 // It won't tell us which one. So we can't set the Index or provide access to the Mutex
  221.                 throw new AbandonedMutexException();
  222.             }
  223.             for (int i = 0; i < internalWaitHandles.Length; i++) {
  224.                 GC.KeepAlive(internalWaitHandles[i]);
  225.             }
  226.             return (ret != WaitTimeout);
  227.         }
  228.        
  229.         public static bool WaitAll(WaitHandle[] waitHandles, TimeSpan timeout, bool exitContext)
  230.         {
  231.             long tm = (long)timeout.TotalMilliseconds;
  232.             if (-1 > tm || (long)Int32.MaxValue < tm) {
  233.                 throw new ArgumentOutOfRangeException("timeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
  234.             }
  235.             return WaitAll(waitHandles, (int)tm, exitContext);
  236.         }
  237.        
  238.        
  239. /*========================================================================
  240.         ** Shorthand for WaitAll with timeout = Timeout.Infinite and exitContext = true
  241.         ========================================================================*/       
  242.         public static bool WaitAll(WaitHandle[] waitHandles)
  243.         {
  244.             return WaitAll(waitHandles, Timeout.Infinite, true);
  245.         }
  246.        
  247. /*========================================================================
  248.         ** Waits for notification from any of the objects.
  249.         ** timeout indicates how long to wait before the method returns.
  250.         ** This method will return either when either one of the object have been
  251.         ** signalled or timeout milliseonds have elapsed.
  252.         ** If exitContext is true then the synchronization domain for the context
  253.         ** (if in a synchronized context) is exited before the wait and reacquired
  254.         ========================================================================*/       
  255.        
  256.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
  257.         public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
  258.         {
  259.             if (waitHandles == null) {
  260.                 throw new ArgumentNullException("waitHandles");
  261.             }
  262.             if (MAX_WAITHANDLES < waitHandles.Length) {
  263.                 throw new NotSupportedException(Environment.GetResourceString("NotSupported_MaxWaitHandles"));
  264.             }
  265.             if (-1 > millisecondsTimeout) {
  266.                 throw new ArgumentOutOfRangeException("millisecondsTimeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
  267.             }
  268.             WaitHandle[] internalWaitHandles = new WaitHandle[waitHandles.Length];
  269.             for (int i = 0; i < waitHandles.Length; i++) {
  270.                 internalWaitHandles[i] = waitHandles[i];
  271.             }
  272.             #if _DEBUG
  273.             // make sure we do not use waitHandles any more.
  274.             waitHandles = null;
  275.             #endif
  276.                 /* waitany*/            int ret = WaitMultiple(internalWaitHandles, millisecondsTimeout, exitContext, false);
  277.             for (int i = 0; i < internalWaitHandles.Length; i++) {
  278.                 GC.KeepAlive(internalWaitHandles[i]);
  279.             }
  280.             if ((WAIT_ABANDONED <= ret) && (WAIT_ABANDONED + internalWaitHandles.Length > ret)) {
  281.                 int mutexIndex = ret - WAIT_ABANDONED;
  282.                 if (0 <= mutexIndex && mutexIndex < internalWaitHandles.Length) {
  283.                     throw new AbandonedMutexException(mutexIndex, internalWaitHandles[mutexIndex]);
  284.                 }
  285.                 else {
  286.                     throw new AbandonedMutexException();
  287.                 }
  288.             }
  289.             else
  290.                 return ret;
  291.            
  292.         }
  293.        
  294.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
  295.         public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout, bool exitContext)
  296.         {
  297.             long tm = (long)timeout.TotalMilliseconds;
  298.             if (-1 > tm || (long)Int32.MaxValue < tm) {
  299.                 throw new ArgumentOutOfRangeException("timeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
  300.             }
  301.             return WaitAny(waitHandles, (int)tm, exitContext);
  302.         }
  303.        
  304. /*========================================================================
  305.         ** Shorthand for WaitAny with timeout = Timeout.Infinite and exitContext = true
  306.         ========================================================================*/       
  307.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
  308.         public static int WaitAny(WaitHandle[] waitHandles)
  309.         {
  310.             return WaitAny(waitHandles, Timeout.Infinite, true);
  311.         }
  312.        
  313.        
  314.         public virtual void Close()
  315.         {
  316.             Dispose(true);
  317.             GC.nativeSuppressFinalize(this);
  318.         }
  319.        
  320.         protected virtual void Dispose(bool explicitDisposing)
  321.         {
  322.             if (safeWaitHandle != null) {
  323.                 safeWaitHandle.Close();
  324.             }
  325.         }
  326.        
  327.         /// <internalonly/>
  328.         void IDisposable.Dispose()
  329.         {
  330.             Dispose(true);
  331.             GC.nativeSuppressFinalize(this);
  332.         }
  333.     }
  334. }

Developer Fusion