WaitHandle.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. //
  2. // System.Threading.WaitHandle.cs
  3. //
  4. // Author:
  5. // Dick Porter ([email protected])
  6. // Gonzalo Paniagua Javier ([email protected]
  7. //
  8. // (C) 2002,2003 Ximian, Inc. (http://www.ximian.com)
  9. // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
  10. //
  11. // Permission is hereby granted, free of charge, to any person obtaining
  12. // a copy of this software and associated documentation files (the
  13. // "Software"), to deal in the Software without restriction, including
  14. // without limitation the rights to use, copy, modify, merge, publish,
  15. // distribute, sublicense, and/or sell copies of the Software, and to
  16. // permit persons to whom the Software is furnished to do so, subject to
  17. // the following conditions:
  18. //
  19. // The above copyright notice and this permission notice shall be
  20. // included in all copies or substantial portions of the Software.
  21. //
  22. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  23. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  24. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  25. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  26. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  27. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  28. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  29. //
  30. using System;
  31. using System.Reflection;
  32. using System.Runtime.CompilerServices;
  33. using System.Runtime.Remoting.Contexts;
  34. using System.Security.Permissions;
  35. using System.Runtime.InteropServices;
  36. using Microsoft.Win32.SafeHandles;
  37. using System.Runtime.ConstrainedExecution;
  38. namespace System.Threading
  39. {
  40. [StructLayout (LayoutKind.Sequential)]
  41. public abstract partial class WaitHandle
  42. : MarshalByRefObject, IDisposable
  43. {
  44. protected static readonly IntPtr InvalidHandle = (IntPtr) (-1);
  45. internal const int MaxWaitHandles = 64;
  46. // We rely on the reference source implementation of WaitHandle, and it delegates to a function named
  47. // WaitOneNative to perform the actual operation of waiting on a handle.
  48. // This native operation actually has to call back into managed code and invoke .Wait
  49. // on the current SynchronizationContext. As such, our implementation of this "native" method
  50. // is actually managed code, and the real native icall being used is Wait_internal.
  51. static int WaitOneNative (SafeHandle waitableSafeHandle, uint millisecondsTimeout, bool hasThreadAffinity, bool exitContext)
  52. {
  53. bool release = false;
  54. var context = SynchronizationContext.Current;
  55. try {
  56. waitableSafeHandle.DangerousAddRef (ref release);
  57. #if !DISABLE_REMOTING
  58. if (exitContext)
  59. SynchronizationAttribute.ExitContext ();
  60. #endif
  61. // HACK: Documentation (and public posts by experts like Joe Duffy) suggests that
  62. // users must first call SetWaitNotificationRequired to flag that a given synchronization
  63. // context overrides .Wait. Because invoking the Wait method is somewhat expensive, we use
  64. // the notification-required flag to determine whether or not we should invoke the managed
  65. // wait method.
  66. // Another option would be to check whether this context uses the default Wait implementation,
  67. // but I don't know of a cheap way to do this that handles derived types correctly.
  68. // If the thread does not have a synchronization context set at all, we can safely just
  69. // jump directly to invoking Wait_internal.
  70. if ((context != null) && context.IsWaitNotificationRequired ()) {
  71. return context.Wait (
  72. new IntPtr[] { waitableSafeHandle.DangerousGetHandle () },
  73. false,
  74. (int)millisecondsTimeout
  75. );
  76. } else {
  77. unsafe {
  78. IntPtr handle = waitableSafeHandle.DangerousGetHandle ();
  79. return Wait_internal (&handle, 1, false, (int)millisecondsTimeout);
  80. }
  81. }
  82. } finally {
  83. if (release)
  84. waitableSafeHandle.DangerousRelease ();
  85. #if !DISABLE_REMOTING
  86. if (exitContext)
  87. SynchronizationAttribute.EnterContext ();
  88. #endif
  89. }
  90. }
  91. static int WaitMultiple(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext, bool WaitAll)
  92. {
  93. if (waitHandles.Length > MaxWaitHandles)
  94. return WAIT_FAILED;
  95. int release_last = -1;
  96. var context = SynchronizationContext.Current;
  97. try {
  98. #if !DISABLE_REMOTING
  99. if (exitContext)
  100. SynchronizationAttribute.ExitContext ();
  101. #endif
  102. for (int i = 0; i < waitHandles.Length; ++i) {
  103. try {} finally {
  104. /* we have to put it in a finally block, to avoid having a ThreadAbortException
  105. * between the return from DangerousAddRef and the assignement to release_last */
  106. bool release = false;
  107. waitHandles [i].SafeWaitHandle.DangerousAddRef (ref release);
  108. release_last = i;
  109. }
  110. }
  111. if ((context != null) && context.IsWaitNotificationRequired ()) {
  112. IntPtr[] handles = new IntPtr[waitHandles.Length];
  113. for (int i = 0; i < waitHandles.Length; ++i)
  114. handles[i] = waitHandles[i].SafeWaitHandle.DangerousGetHandle ();
  115. return context.Wait (
  116. handles,
  117. false,
  118. (int)millisecondsTimeout
  119. );
  120. } else {
  121. unsafe {
  122. IntPtr* handles = stackalloc IntPtr[waitHandles.Length];
  123. for (int i = 0; i < waitHandles.Length; ++i)
  124. handles[i] = waitHandles[i].SafeWaitHandle.DangerousGetHandle ();
  125. return Wait_internal (handles, waitHandles.Length, WaitAll, millisecondsTimeout);
  126. }
  127. }
  128. } finally {
  129. for (int i = release_last; i >= 0; --i) {
  130. waitHandles [i].SafeWaitHandle.DangerousRelease ();
  131. }
  132. #if !DISABLE_REMOTING
  133. if (exitContext)
  134. SynchronizationAttribute.EnterContext ();
  135. #endif
  136. }
  137. }
  138. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  139. internal unsafe static extern int Wait_internal(IntPtr* handles, int numHandles, bool waitAll, int ms);
  140. static int SignalAndWaitOne (SafeWaitHandle waitHandleToSignal,SafeWaitHandle waitHandleToWaitOn, int millisecondsTimeout, bool hasThreadAffinity, bool exitContext)
  141. {
  142. bool releaseHandleToSignal = false, releaseHandleToWaitOn = false;
  143. try {
  144. waitHandleToSignal.DangerousAddRef (ref releaseHandleToSignal);
  145. waitHandleToWaitOn.DangerousAddRef (ref releaseHandleToWaitOn);
  146. return SignalAndWait_Internal (waitHandleToSignal.DangerousGetHandle (), waitHandleToWaitOn.DangerousGetHandle (), millisecondsTimeout);
  147. } finally {
  148. if (releaseHandleToSignal)
  149. waitHandleToSignal.DangerousRelease ();
  150. if (releaseHandleToWaitOn)
  151. waitHandleToWaitOn.DangerousRelease ();
  152. }
  153. }
  154. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  155. static extern int SignalAndWait_Internal (IntPtr toSignal, IntPtr toWaitOn, int ms);
  156. }
  157. }