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