Small 4fx fixes
[mono.git] / mcs / class / corlib / System.Threading / WaitHandle.cs
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)
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
31 using System;
32 using System.Reflection;
33 using System.Runtime.CompilerServices;
34 using System.Runtime.Remoting.Contexts;
35 using System.Security.Permissions;
36 using System.Runtime.InteropServices;
37 using Microsoft.Win32.SafeHandles;
38 using System.Runtime.ConstrainedExecution;
39
40 namespace System.Threading
41 {
42         [ComVisible (true)]
43         public abstract class WaitHandle : MarshalByRefObject, IDisposable
44         {
45                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
46                 private static extern bool WaitAll_internal(WaitHandle[] handles, int ms, bool exitContext);
47                 
48                 static void CheckArray (WaitHandle [] handles, bool waitAll)
49                 {
50                         if (handles == null)
51                                 throw new ArgumentNullException ("waitHandles");
52
53                         int length = handles.Length;
54                         if (length > 64)
55                                 throw new NotSupportedException ("Too many handles");
56
57 #if false
58                         //
59                         // Although we should thrown an exception if this is an STA thread,
60                         // Mono does not know anything about STA threads, and just makes
61                         // things like Paint.NET not even possible to work.
62                         //
63                         // See bug #78455 for the bug this is supposed to fix. 
64                         // 
65                         if (waitAll && length > 1 && IsSTAThread)
66                                 throw new NotSupportedException ("WaitAll for multiple handles is not allowed on an STA thread.");
67 #endif
68                         foreach (WaitHandle w in handles) {
69                                 if (w == null)
70                                         throw new ArgumentNullException ("waitHandles", "null handle");
71
72                                 if (w.safe_wait_handle == null)
73                                         throw new ArgumentException ("null element found", "waitHandle");
74
75                         }
76                 }
77 #if false
78                 // usage of property is commented - see above
79                 static bool IsSTAThread {
80                         get {
81                                 bool isSTA = Thread.CurrentThread.ApartmentState ==
82                                         ApartmentState.STA;
83
84                                 // FIXME: remove this check after Thread.ApartmentState
85                                 // has been properly implemented.
86                                 if (!isSTA) {
87                                         Assembly asm = Assembly.GetEntryAssembly ();
88                                         if (asm != null)
89                                                 isSTA = asm.EntryPoint.GetCustomAttributes (typeof (STAThreadAttribute), false).Length > 0;
90                                 }
91
92                                 return isSTA;
93                         }
94                 }
95 #endif
96                 public static bool WaitAll(WaitHandle[] waitHandles)
97                 {
98                         CheckArray (waitHandles, true);
99                         return(WaitAll_internal(waitHandles, Timeout.Infinite, false));
100                 }
101
102                 public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
103                 {
104                         CheckArray (waitHandles, true);
105                         // check negative - except for -1 (which is Timeout.Infinite)
106                         if (millisecondsTimeout < Timeout.Infinite)
107                                 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
108
109                         try {
110                                 if (exitContext) SynchronizationAttribute.ExitContext ();
111                                 return(WaitAll_internal(waitHandles, millisecondsTimeout, false));
112                         }
113                         finally {
114                                 if (exitContext) SynchronizationAttribute.EnterContext ();
115                         }
116                 }
117
118                 public static bool WaitAll(WaitHandle[] waitHandles,
119                                            TimeSpan timeout,
120                                            bool exitContext)
121                 {
122                         CheckArray (waitHandles, true);
123                         long ms = (long) timeout.TotalMilliseconds;
124                         
125                         if (ms < -1 || ms > Int32.MaxValue)
126                                 throw new ArgumentOutOfRangeException ("timeout");
127
128                         try {
129                                 if (exitContext) SynchronizationAttribute.ExitContext ();
130                                 return (WaitAll_internal (waitHandles, (int) ms, exitContext));
131                         }
132                         finally {
133                                 if (exitContext) SynchronizationAttribute.EnterContext ();
134                         }
135                 }
136
137                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
138                 private static extern int WaitAny_internal(WaitHandle[] handles, int ms, bool exitContext);
139
140                 // LAMESPEC: Doesn't specify how to signal failures
141                 [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
142                 public static int WaitAny(WaitHandle[] waitHandles)
143                 {
144                         CheckArray (waitHandles, false);
145                         return(WaitAny_internal(waitHandles, Timeout.Infinite, false));
146                 }
147
148                 [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
149                 public static int WaitAny(WaitHandle[] waitHandles,
150                                           int millisecondsTimeout,
151                                           bool exitContext)
152                 {
153                         CheckArray (waitHandles, false);
154                         // check negative - except for -1 (which is Timeout.Infinite)
155                         if (millisecondsTimeout < Timeout.Infinite)
156                                 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
157
158                         try {
159                                 if (exitContext) SynchronizationAttribute.ExitContext ();
160                                 return(WaitAny_internal(waitHandles, millisecondsTimeout, exitContext));
161                         }
162                         finally {
163                                 if (exitContext) SynchronizationAttribute.EnterContext ();
164                         }
165                 }
166
167                 [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
168                 public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout)
169                 {
170                         return WaitAny (waitHandles, timeout, false);
171                 }
172
173                 [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
174                 public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout)
175                 {
176                         return WaitAny (waitHandles, millisecondsTimeout, false);
177                 }
178
179                 [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
180                 public static int WaitAny(WaitHandle[] waitHandles,
181                                           TimeSpan timeout, bool exitContext)
182                 {
183                         CheckArray (waitHandles, false);
184                         long ms = (long) timeout.TotalMilliseconds;
185                         
186                         if (ms < -1 || ms > Int32.MaxValue)
187                                 throw new ArgumentOutOfRangeException ("timeout");
188
189                         try {
190                                 if (exitContext) SynchronizationAttribute.ExitContext ();
191                                 return (WaitAny_internal(waitHandles, (int) ms, exitContext));
192                         }
193                         finally {
194                                 if (exitContext) SynchronizationAttribute.EnterContext ();
195                         }
196                 }
197
198                 protected WaitHandle()
199                 {
200                         // FIXME
201                 }
202
203                 public virtual void Close() {
204                         Dispose(true);
205                         GC.SuppressFinalize (this);
206                 }
207
208                 public const int WaitTimeout = 258;
209
210                 //
211                 // In 2.0 we use SafeWaitHandles instead of IntPtrs
212                 //
213                 SafeWaitHandle safe_wait_handle;
214
215                 [Obsolete ("In the profiles > 2.x, use SafeHandle instead of Handle")]
216                 public virtual IntPtr Handle {
217                         get {
218                                 return safe_wait_handle.DangerousGetHandle ();
219                         }
220
221                         [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode = true)]
222                         [SecurityPermission (SecurityAction.InheritanceDemand, UnmanagedCode = true)]
223                         set {
224                                 if (value == InvalidHandle)
225                                         safe_wait_handle = new SafeWaitHandle (InvalidHandle, false);
226                                 else
227                                         safe_wait_handle = new SafeWaitHandle (value, true);
228                         }
229                 }
230                 
231                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
232                 private extern bool WaitOne_internal(IntPtr handle, int ms, bool exitContext);
233
234                 protected virtual void Dispose (bool explicitDisposing)
235                 {
236                         if (!disposed){
237                                 disposed = true;
238
239                                 //
240                                 // This is only the case if the handle was never properly initialized
241                                 // most likely a bug in the derived class
242                                 //
243                                 if (safe_wait_handle == null)
244                                         return;
245
246                                 lock (this){
247                                         if (safe_wait_handle != null)
248                                                 safe_wait_handle.Dispose ();
249                                 }
250                         }
251                 }
252
253                 public SafeWaitHandle SafeWaitHandle {
254                         [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
255                         get {
256                                 return safe_wait_handle;
257                         }
258
259                         [ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
260                         set {
261                                 if (value == null)
262                                         safe_wait_handle = new SafeWaitHandle (InvalidHandle, false);
263                                 else
264                                         safe_wait_handle = value;
265                         }
266                 }
267
268                 public static bool SignalAndWait (WaitHandle toSignal,
269                                                   WaitHandle toWaitOn)
270                 {
271                         return SignalAndWait (toSignal, toWaitOn, -1, false);
272                 }
273                 
274                 public static bool SignalAndWait (WaitHandle toSignal,
275                                                   WaitHandle toWaitOn,
276                                                   int millisecondsTimeout,
277                                                   bool exitContext)
278                 {
279                         if (toSignal == null)
280                                 throw new ArgumentNullException ("toSignal");
281                         if (toWaitOn == null)
282                                 throw new ArgumentNullException ("toWaitOn");
283
284                         if (millisecondsTimeout < -1)
285                                 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
286
287                         return SignalAndWait_Internal (toSignal.Handle, toWaitOn.Handle, millisecondsTimeout, exitContext);
288                 }
289                 
290                 public static bool SignalAndWait (WaitHandle toSignal,
291                                                   WaitHandle toWaitOn,
292                                                   TimeSpan timeout,
293                                                   bool exitContext)
294                 {
295                         double ms = timeout.TotalMilliseconds;
296                         if (ms > Int32.MaxValue)
297                                 throw new ArgumentOutOfRangeException ("timeout");
298
299                         return SignalAndWait (toSignal, toWaitOn, Convert.ToInt32 (ms), false);
300                 }
301
302                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
303                 static extern bool SignalAndWait_Internal (IntPtr toSignal, IntPtr toWaitOn, int ms, bool exitContext);
304
305                 public virtual bool WaitOne()
306                 {
307                         CheckDisposed ();
308                         bool release = false;
309                         try {
310                                 safe_wait_handle.DangerousAddRef (ref release);
311                                 return (WaitOne_internal(safe_wait_handle.DangerousGetHandle (), Timeout.Infinite, false));
312                         } finally {
313                                 if (release)
314                                         safe_wait_handle.DangerousRelease ();
315                         }
316                 }
317
318                 public virtual bool WaitOne(int millisecondsTimeout, bool exitContext)
319                 {
320                         CheckDisposed ();
321                         // check negative - except for -1 (which is Timeout.Infinite)
322                         if (millisecondsTimeout < Timeout.Infinite)
323                                 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
324
325                         bool release = false;
326                         try {
327                                 if (exitContext)
328                                         SynchronizationAttribute.ExitContext ();
329                                 safe_wait_handle.DangerousAddRef (ref release);
330                                 return (WaitOne_internal(safe_wait_handle.DangerousGetHandle (), millisecondsTimeout, exitContext));
331                         } finally {
332                                 if (exitContext)
333                                         SynchronizationAttribute.EnterContext ();
334                                 if (release)
335                                         safe_wait_handle.DangerousRelease ();
336                         }
337                 }
338
339                 public virtual bool WaitOne (int millisecondsTimeout)
340                 {
341                         return WaitOne (millisecondsTimeout, false);
342                 }
343
344                 public virtual bool WaitOne (TimeSpan timeout)
345                 {
346                         return WaitOne (timeout, false);
347                 }
348
349                 public virtual bool WaitOne(TimeSpan timeout, bool exitContext)
350                 {
351                         CheckDisposed ();
352                         long ms = (long) timeout.TotalMilliseconds;
353                         if (ms < -1 || ms > Int32.MaxValue)
354                                 throw new ArgumentOutOfRangeException ("timeout");
355
356                         bool release = false;
357                         try {
358                                 if (exitContext)
359                                         SynchronizationAttribute.ExitContext ();
360                                 safe_wait_handle.DangerousAddRef (ref release);
361                                 return (WaitOne_internal(safe_wait_handle.DangerousGetHandle (), (int) ms, exitContext));
362                         }
363                         finally {
364                                 if (exitContext)
365                                         SynchronizationAttribute.EnterContext ();
366                                 if (release)
367                                         safe_wait_handle.DangerousRelease ();
368                         }
369                 }
370
371                 internal void CheckDisposed ()
372                 {
373                         if (disposed || safe_wait_handle == null)
374                                 throw new ObjectDisposedException (GetType ().FullName);
375                 }
376
377                 public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout)
378                 {
379                         return WaitAll (waitHandles, millisecondsTimeout, false);
380                 }
381
382                 public static bool WaitAll(WaitHandle[] waitHandles, TimeSpan timeout)
383                 {
384                         return WaitAll (waitHandles, timeout, false);
385                 }
386                 
387                 protected static readonly IntPtr InvalidHandle = (IntPtr) (-1);
388                 bool disposed = false;
389
390                 void IDisposable.Dispose() {
391                         Dispose(true);
392                         // Take yourself off the Finalization queue
393                         GC.SuppressFinalize(this);
394                 }
395                 
396                 ~WaitHandle() {
397                         Dispose(false);
398                 }
399         }
400 }