update readme (#21797)
[mono-project.git] / mcs / class / corlib / System.Threading / WaitHandle.cs
bloba0d945c18a98d4ddfaff90304a0f0bfd00f65738
1 //
2 // System.Threading.WaitHandle.cs
3 //
4 // Author:
5 // Dick Porter (dick@ximian.com)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com
7 //
8 // (C) 2002,2003 Ximian, Inc. (http://www.ximian.com)
9 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
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.
31 using System;
32 using System.Reflection;
33 using System.Runtime.CompilerServices;
34 #if FEATURE_REMOTING
35 using System.Runtime.Remoting.Contexts;
36 #endif
37 using System.Runtime.InteropServices;
38 using Microsoft.Win32.SafeHandles;
39 using System.Runtime.ConstrainedExecution;
41 namespace System.Threading
43 [StructLayout (LayoutKind.Sequential)]
44 public abstract partial class WaitHandle
46 protected static readonly IntPtr InvalidHandle = (IntPtr) (-1);
48 internal const int MaxWaitHandles = 64;
50 // We rely on the reference source implementation of WaitHandle, and it delegates to a function named
51 // WaitOneNative to perform the actual operation of waiting on a handle.
52 // This native operation actually has to call back into managed code and invoke .Wait
53 // on the current SynchronizationContext. As such, our implementation of this "native" method
54 // is actually managed code, and the real native icall being used is Wait_internal.
55 static int WaitOneNative (SafeHandle waitableSafeHandle, uint millisecondsTimeout, bool hasThreadAffinity, bool exitContext)
57 bool release = false;
58 #if !MONODROID
59 var context = SynchronizationContext.Current;
60 #endif
61 try {
62 waitableSafeHandle.DangerousAddRef (ref release);
64 #if FEATURE_REMOTING
65 if (exitContext)
66 SynchronizationAttribute.ExitContext ();
67 #endif
69 #if !MONODROID
70 // HACK: Documentation (and public posts by experts like Joe Duffy) suggests that
71 // users must first call SetWaitNotificationRequired to flag that a given synchronization
72 // context overrides .Wait. Because invoking the Wait method is somewhat expensive, we use
73 // the notification-required flag to determine whether or not we should invoke the managed
74 // wait method.
75 // Another option would be to check whether this context uses the default Wait implementation,
76 // but I don't know of a cheap way to do this that handles derived types correctly.
77 // If the thread does not have a synchronization context set at all, we can safely just
78 // jump directly to invoking Wait_internal.
79 if ((context != null) && context.IsWaitNotificationRequired ()) {
80 return context.Wait (
81 new IntPtr[] { waitableSafeHandle.DangerousGetHandle () },
82 false,
83 (int)millisecondsTimeout
85 } else
86 #endif
88 unsafe {
89 IntPtr handle = waitableSafeHandle.DangerousGetHandle ();
90 return Wait_internal (&handle, 1, false, (int)millisecondsTimeout);
93 } finally {
94 if (release)
95 waitableSafeHandle.DangerousRelease ();
97 #if FEATURE_REMOTING
98 if (exitContext)
99 SynchronizationAttribute.EnterContext ();
100 #endif
105 static int WaitMultiple(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext, bool WaitAll)
107 if (waitHandles.Length > MaxWaitHandles)
108 return WAIT_FAILED;
110 int release_last = -1;
111 var context = SynchronizationContext.Current;
113 try {
114 #if FEATURE_REMOTING
115 if (exitContext)
116 SynchronizationAttribute.ExitContext ();
117 #endif
119 for (int i = 0; i < waitHandles.Length; ++i) {
120 try {} finally {
121 /* we have to put it in a finally block, to avoid having a ThreadAbortException
122 * between the return from DangerousAddRef and the assignement to release_last */
123 bool release = false;
124 waitHandles [i].SafeWaitHandle.DangerousAddRef (ref release);
125 release_last = i;
129 if ((context != null) && context.IsWaitNotificationRequired ()) {
130 IntPtr[] handles = new IntPtr[waitHandles.Length];
131 for (int i = 0; i < waitHandles.Length; ++i)
132 handles[i] = waitHandles[i].SafeWaitHandle.DangerousGetHandle ();
134 return context.Wait (
135 handles,
136 false,
137 (int)millisecondsTimeout
139 } else {
140 unsafe {
141 IntPtr* handles = stackalloc IntPtr[waitHandles.Length];
143 for (int i = 0; i < waitHandles.Length; ++i)
144 handles[i] = waitHandles[i].SafeWaitHandle.DangerousGetHandle ();
146 return Wait_internal (handles, waitHandles.Length, WaitAll, millisecondsTimeout);
149 } finally {
150 for (int i = release_last; i >= 0; --i) {
151 waitHandles [i].SafeWaitHandle.DangerousRelease ();
154 #if FEATURE_REMOTING
155 if (exitContext)
156 SynchronizationAttribute.EnterContext ();
157 #endif
161 [MethodImplAttribute(MethodImplOptions.InternalCall)]
162 internal unsafe static extern int Wait_internal(IntPtr* handles, int numHandles, bool waitAll, int ms);
164 static int SignalAndWaitOne (SafeWaitHandle waitHandleToSignal,SafeWaitHandle waitHandleToWaitOn, int millisecondsTimeout, bool hasThreadAffinity, bool exitContext)
166 bool releaseHandleToSignal = false, releaseHandleToWaitOn = false;
167 try {
168 waitHandleToSignal.DangerousAddRef (ref releaseHandleToSignal);
169 waitHandleToWaitOn.DangerousAddRef (ref releaseHandleToWaitOn);
171 return SignalAndWait_Internal (waitHandleToSignal.DangerousGetHandle (), waitHandleToWaitOn.DangerousGetHandle (), millisecondsTimeout);
172 } finally {
173 if (releaseHandleToSignal)
174 waitHandleToSignal.DangerousRelease ();
175 if (releaseHandleToWaitOn)
176 waitHandleToWaitOn.DangerousRelease ();
180 [MethodImplAttribute(MethodImplOptions.InternalCall)]
181 static extern int SignalAndWait_Internal (IntPtr toSignal, IntPtr toWaitOn, int ms);
183 internal static int ToTimeoutMilliseconds(TimeSpan timeout)
185 var timeoutMilliseconds = (long)timeout.TotalMilliseconds;
186 if (timeoutMilliseconds < -1 || timeoutMilliseconds > int.MaxValue)
188 throw new ArgumentOutOfRangeException(nameof(timeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
190 return (int)timeoutMilliseconds;