2 // System.Threading.WaitHandle.cs
5 // Dick Porter (dick@ximian.com)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com
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:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
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.
32 using System.Reflection;
33 using System.Runtime.CompilerServices;
34 using System.Runtime.Remoting.Contexts;
35 using System.Security.Permissions;
38 using System.Runtime.InteropServices;
39 using Microsoft.Win32.SafeHandles;
42 namespace System.Threading
44 public abstract class WaitHandle : MarshalByRefObject, IDisposable
46 [MethodImplAttribute(MethodImplOptions.InternalCall)]
47 private static extern bool WaitAll_internal(WaitHandle[] handles, int ms, bool exitContext);
49 static void CheckArray (WaitHandle [] handles, bool waitAll)
52 throw new ArgumentNullException ("waitHandles");
54 int length = handles.Length;
56 throw new NotSupportedException ("Too many handles");
58 if (waitAll && length > 1 && IsSTAThread)
59 throw new NotSupportedException ("WaitAll for multiple handles is not allowed on an STA thread.");
61 foreach (WaitHandle w in handles) {
63 throw new ArgumentNullException ("waitHandles", "null handle");
66 if (w.safe_wait_handle == null)
67 throw new ArgumentException ("null element found", "waitHandle");
69 if (w.os_handle == InvalidHandle)
70 throw new ArgumentException ("null element found", "waitHandle");
75 static bool IsSTAThread {
77 bool isSTA = Thread.CurrentThread.ApartmentState ==
80 // FIXME: remove this check after Thread.ApartmentState
81 // has been properly implemented.
83 Assembly asm = Assembly.GetEntryAssembly ();
85 isSTA = asm.EntryPoint.GetCustomAttributes (typeof (STAThreadAttribute), false).Length > 0;
92 public static bool WaitAll(WaitHandle[] waitHandles)
94 CheckArray (waitHandles, true);
95 return(WaitAll_internal(waitHandles, Timeout.Infinite, false));
98 public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
100 CheckArray (waitHandles, true);
102 if (exitContext) SynchronizationAttribute.ExitContext ();
103 return(WaitAll_internal(waitHandles, millisecondsTimeout, false));
106 if (exitContext) SynchronizationAttribute.EnterContext ();
110 public static bool WaitAll(WaitHandle[] waitHandles,
114 CheckArray (waitHandles, true);
115 long ms = (long) timeout.TotalMilliseconds;
117 if (ms < -1 || ms > Int32.MaxValue)
118 throw new ArgumentOutOfRangeException ("timeout");
121 if (exitContext) SynchronizationAttribute.ExitContext ();
122 return (WaitAll_internal (waitHandles, (int) ms, exitContext));
125 if (exitContext) SynchronizationAttribute.EnterContext ();
129 [MethodImplAttribute(MethodImplOptions.InternalCall)]
130 private static extern int WaitAny_internal(WaitHandle[] handles, int ms, bool exitContext);
132 // LAMESPEC: Doesn't specify how to signal failures
133 public static int WaitAny(WaitHandle[] waitHandles)
135 CheckArray (waitHandles, false);
136 return(WaitAny_internal(waitHandles, Timeout.Infinite, false));
139 public static int WaitAny(WaitHandle[] waitHandles,
140 int millisecondsTimeout,
143 CheckArray (waitHandles, false);
145 if (exitContext) SynchronizationAttribute.ExitContext ();
146 return(WaitAny_internal(waitHandles, millisecondsTimeout, exitContext));
149 if (exitContext) SynchronizationAttribute.EnterContext ();
153 public static int WaitAny(WaitHandle[] waitHandles,
154 TimeSpan timeout, bool exitContext)
156 CheckArray (waitHandles, false);
157 long ms = (long) timeout.TotalMilliseconds;
159 if (ms < -1 || ms > Int32.MaxValue)
160 throw new ArgumentOutOfRangeException ("timeout");
163 if (exitContext) SynchronizationAttribute.ExitContext ();
164 return (WaitAny_internal(waitHandles, (int) ms, exitContext));
167 if (exitContext) SynchronizationAttribute.EnterContext ();
172 public WaitHandle() {
176 public virtual void Close() {
178 GC.SuppressFinalize (this);
181 public const int WaitTimeout = 258;
185 // In 2.0 we use SafeWaitHandles instead of IntPtrs
187 SafeWaitHandle safe_wait_handle;
189 [Obsolete ("In the profiles > 2.x, use SafeHandle instead of Handle")]
190 public virtual IntPtr Handle {
192 return safe_wait_handle.DangerousGetHandle ();
195 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode = true)]
196 [SecurityPermission (SecurityAction.InheritanceDemand, UnmanagedCode = true)]
199 // Notice, from the 2.x documentation:
200 // Assigning a new value to the Handle property, will not release
201 // the previous handle, this could lead to a leak
203 safe_wait_handle = new SafeWaitHandle (value, false);
207 [MethodImplAttribute(MethodImplOptions.InternalCall)]
208 private extern bool WaitOne_internal(IntPtr handle, int ms, bool exitContext);
210 protected virtual void Dispose (bool explicitDisposing)
216 // This is only the case if the handle was never properly initialized
217 // most likely a but in the derived class
219 if (safe_wait_handle == null)
223 if (safe_wait_handle != null)
224 safe_wait_handle.Dispose ();
229 public SafeWaitHandle SafeWaitHandle {
231 return safe_wait_handle;
235 if (safe_wait_handle != null)
236 safe_wait_handle.Close ();
238 safe_wait_handle = value;
242 public virtual bool WaitOne()
245 bool release = false;
247 safe_wait_handle.DangerousAddRef (ref release);
248 return (WaitOne_internal(safe_wait_handle.DangerousGetHandle (), Timeout.Infinite, false));
251 safe_wait_handle.DangerousRelease ();
255 public virtual bool WaitOne(int millisecondsTimeout, bool exitContext)
258 bool release = false;
261 SynchronizationAttribute.ExitContext ();
262 safe_wait_handle.DangerousAddRef (ref release);
263 return (WaitOne_internal(safe_wait_handle.DangerousGetHandle (), millisecondsTimeout, exitContext));
266 SynchronizationAttribute.EnterContext ();
268 safe_wait_handle.DangerousRelease ();
272 public virtual bool WaitOne(TimeSpan timeout, bool exitContext)
275 long ms = (long) timeout.TotalMilliseconds;
276 if (ms < -1 || ms > Int32.MaxValue)
277 throw new ArgumentOutOfRangeException ("timeout");
279 bool release = false;
282 SynchronizationAttribute.ExitContext ();
283 safe_wait_handle.DangerousAddRef (ref release);
284 return (WaitOne_internal(safe_wait_handle.DangerousGetHandle (), (int) ms, exitContext));
288 SynchronizationAttribute.EnterContext ();
290 safe_wait_handle.DangerousRelease ();
294 internal void CheckDisposed ()
296 if (disposed || safe_wait_handle == null)
297 throw new ObjectDisposedException (GetType ().FullName);
300 private IntPtr os_handle = InvalidHandle;
302 public virtual IntPtr Handle {
307 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode = true)]
308 [SecurityPermission (SecurityAction.InheritanceDemand, UnmanagedCode = true)]
314 internal void CheckDisposed ()
316 if (disposed || os_handle == InvalidHandle)
317 throw new ObjectDisposedException (GetType ().FullName);
320 [MethodImplAttribute(MethodImplOptions.InternalCall)]
321 private extern bool WaitOne_internal(IntPtr handle, int ms, bool exitContext);
323 protected virtual void Dispose(bool explicitDisposing) {
324 // Check to see if Dispose has already been called.
327 if (os_handle == InvalidHandle)
331 if (os_handle != InvalidHandle) {
332 NativeEventCalls.CloseEvent_internal (os_handle);
333 os_handle = InvalidHandle;
339 public virtual bool WaitOne()
342 return(WaitOne_internal(os_handle, Timeout.Infinite, false));
345 public virtual bool WaitOne(int millisecondsTimeout, bool exitContext)
349 if (exitContext) SynchronizationAttribute.ExitContext ();
350 return(WaitOne_internal(os_handle, millisecondsTimeout, exitContext));
353 if (exitContext) SynchronizationAttribute.EnterContext ();
357 public virtual bool WaitOne(TimeSpan timeout, bool exitContext)
360 long ms = (long) timeout.TotalMilliseconds;
361 if (ms < -1 || ms > Int32.MaxValue)
362 throw new ArgumentOutOfRangeException ("timeout");
365 if (exitContext) SynchronizationAttribute.ExitContext ();
366 return (WaitOne_internal(os_handle, (int) ms, exitContext));
369 if (exitContext) SynchronizationAttribute.EnterContext ();
374 protected static readonly IntPtr InvalidHandle = IntPtr.Zero;
375 bool disposed = false;
377 void IDisposable.Dispose() {
379 // Take yourself off the Finalization queue
380 GC.SuppressFinalize(this);