New test.
[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
37 namespace System.Threading
38 {
39         public abstract class WaitHandle : MarshalByRefObject, IDisposable
40         {
41                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
42                 private static extern bool WaitAll_internal(WaitHandle[] handles, int ms, bool exitContext);
43                 
44                 static void CheckArray (WaitHandle [] handles, bool waitAll)
45                 {
46                         if (handles == null)
47                                 throw new ArgumentNullException ("waitHandles");
48
49                         int length = handles.Length;
50                         if (length > 64)
51                                 throw new NotSupportedException ("Too many handles");
52
53                         if (waitAll && length > 1 &&
54                             (Thread.CurrentThread.ApartmentState == ApartmentState.STA ||
55                              Assembly.GetEntryAssembly ().EntryPoint.GetCustomAttributes (typeof (STAThreadAttribute), false).Length == 1))
56                                 throw new NotSupportedException ("WaitAll for multiple handles is not allowed on an STA thread.");
57                         
58                         foreach (WaitHandle w in handles) {
59                                 if (w == null)
60                                         throw new ArgumentNullException ("waitHandles", "null handle");
61
62                                 if (w.os_handle == InvalidHandle)
63                                         throw new ArgumentException ("null element found", "waitHandle");
64                         }
65                 }
66                 
67                 public static bool WaitAll(WaitHandle[] waitHandles)
68                 {
69                         CheckArray (waitHandles, true);
70                         return(WaitAll_internal(waitHandles, Timeout.Infinite, false));
71                 }
72
73                 public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
74                 {
75                         CheckArray (waitHandles, true);
76                         try {
77                                 if (exitContext) SynchronizationAttribute.ExitContext ();
78                                 return(WaitAll_internal(waitHandles, millisecondsTimeout, false));
79                         }
80                         finally {
81                                 if (exitContext) SynchronizationAttribute.EnterContext ();
82                         }
83                 }
84
85                 public static bool WaitAll(WaitHandle[] waitHandles,
86                                            TimeSpan timeout,
87                                            bool exitContext)
88                 {
89                         CheckArray (waitHandles, true);
90                         long ms = (long) timeout.TotalMilliseconds;
91                         
92                         if (ms < -1 || ms > Int32.MaxValue)
93                                 throw new ArgumentOutOfRangeException ("timeout");
94
95                         try {
96                                 if (exitContext) SynchronizationAttribute.ExitContext ();
97                                 return (WaitAll_internal (waitHandles, (int) ms, exitContext));
98                         }
99                         finally {
100                                 if (exitContext) SynchronizationAttribute.EnterContext ();
101                         }
102                 }
103
104                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
105                 private static extern int WaitAny_internal(WaitHandle[] handles, int ms, bool exitContext);
106
107                 // LAMESPEC: Doesn't specify how to signal failures
108                 public static int WaitAny(WaitHandle[] waitHandles)
109                 {
110                         CheckArray (waitHandles, false);
111                         return(WaitAny_internal(waitHandles, Timeout.Infinite, false));
112                 }
113
114                 public static int WaitAny(WaitHandle[] waitHandles,
115                                           int millisecondsTimeout,
116                                           bool exitContext)
117                 {
118                         CheckArray (waitHandles, false);
119                         try {
120                                 if (exitContext) SynchronizationAttribute.ExitContext ();
121                                 return(WaitAny_internal(waitHandles, millisecondsTimeout, exitContext));
122                         }
123                         finally {
124                                 if (exitContext) SynchronizationAttribute.EnterContext ();
125                         }
126                 }
127
128                 public static int WaitAny(WaitHandle[] waitHandles,
129                                           TimeSpan timeout, bool exitContext)
130                 {
131                         CheckArray (waitHandles, false);
132                         long ms = (long) timeout.TotalMilliseconds;
133                         
134                         if (ms < -1 || ms > Int32.MaxValue)
135                                 throw new ArgumentOutOfRangeException ("timeout");
136
137                         try {
138                                 if (exitContext) SynchronizationAttribute.ExitContext ();
139                                 return (WaitAny_internal(waitHandles, (int) ms, exitContext));
140                         }
141                         finally {
142                                 if (exitContext) SynchronizationAttribute.EnterContext ();
143                         }
144                 }
145
146                 [MonoTODO]
147                 public WaitHandle() {
148                         // FIXME
149                 }
150
151                 public const int WaitTimeout = 258;
152
153                 private IntPtr os_handle = InvalidHandle;
154                 
155                 public virtual IntPtr Handle {
156                         get {
157                                 return(os_handle);
158                         }
159                                 
160                         [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode = true)]
161                         [SecurityPermission (SecurityAction.InheritanceDemand, UnmanagedCode = true)]
162                         set {
163                                 os_handle=value;
164                         }
165                 }
166
167                 public virtual void Close() {
168                         Dispose(true);
169                         GC.SuppressFinalize (this);
170                 }
171
172                 internal void CheckDisposed ()
173                 {
174                         if (disposed || os_handle == InvalidHandle)
175                                 throw new ObjectDisposedException (GetType ().FullName);
176                 }
177                 
178                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
179                 private extern bool WaitOne_internal(IntPtr handle, int ms, bool exitContext);
180
181                 public virtual bool WaitOne()
182                 {
183                         CheckDisposed ();
184                         return(WaitOne_internal(os_handle, Timeout.Infinite, false));
185                 }
186
187                 public virtual bool WaitOne(int millisecondsTimeout, bool exitContext)
188                 {
189                         CheckDisposed ();
190                         try {
191                                 if (exitContext) SynchronizationAttribute.ExitContext ();
192                                 return(WaitOne_internal(os_handle, millisecondsTimeout, exitContext));
193                         }
194                         finally {
195                                 if (exitContext) SynchronizationAttribute.EnterContext ();
196                         }
197                 }
198
199                 public virtual bool WaitOne(TimeSpan timeout, bool exitContext)
200                 {
201                         CheckDisposed ();
202                         long ms = (long) timeout.TotalMilliseconds;
203                         if (ms < -1 || ms > Int32.MaxValue)
204                                 throw new ArgumentOutOfRangeException ("timeout");
205
206                         try {
207                                 if (exitContext) SynchronizationAttribute.ExitContext ();
208                                 return (WaitOne_internal(os_handle, (int) ms, exitContext));
209                         }
210                         finally {
211                                 if (exitContext) SynchronizationAttribute.EnterContext ();
212                         }
213                 }
214
215                 protected static readonly IntPtr InvalidHandle = IntPtr.Zero;
216
217                 bool disposed = false;
218
219                 void IDisposable.Dispose() {
220                         Dispose(true);
221                         // Take yourself off the Finalization queue
222                         GC.SuppressFinalize(this);
223                 }
224                 
225                 protected virtual void Dispose(bool explicitDisposing) {
226                         // Check to see if Dispose has already been called.
227                         if (!disposed) {
228                                 disposed=true;
229                                 if (os_handle == InvalidHandle)
230                                         return;
231
232                                 lock (this) {
233                                         if (os_handle != InvalidHandle) {
234                                                 NativeEventCalls.CloseEvent_internal (os_handle);
235                                                 os_handle = InvalidHandle;
236                                         }
237                                 }
238                         }
239                 }
240
241                 ~WaitHandle() {
242                         Dispose(false);
243                 }
244         }
245 }