[sgen] Fix critical/normal finalization order at domain unload
[mono.git] / mono / io-layer / wait.c
1 /*
2  * wait.c:  wait for handles to become signalled
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002-2006 Novell, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12 #include <string.h>
13 #include <errno.h>
14
15 #include <mono/io-layer/wapi.h>
16 #include <mono/io-layer/wapi-private.h>
17 #include <mono/io-layer/io-trace.h>
18 #include <mono/utils/mono-logger-internals.h>
19 #include <mono/utils/mono-time.h>
20 #include <mono/utils/w32handle.h>
21
22 static gboolean own_if_signalled(gpointer handle)
23 {
24         gboolean ret = FALSE;
25
26         if (mono_w32handle_issignalled (handle)) {
27                 mono_w32handle_ops_own (handle);
28                 ret = TRUE;
29         }
30
31         return(ret);
32 }
33
34 static gboolean own_if_owned(gpointer handle)
35 {
36         gboolean ret = FALSE;
37
38         if (mono_w32handle_ops_isowned (handle)) {
39                 mono_w32handle_ops_own (handle);
40                 ret = TRUE;
41         }
42
43         return(ret);
44 }
45
46 /**
47  * WaitForSingleObjectEx:
48  * @handle: an object to wait for
49  * @timeout: the maximum time in milliseconds to wait for
50  * @alertable: if TRUE, the wait can be interrupted by an APC call
51  *
52  * This function returns when either @handle is signalled, or @timeout
53  * ms elapses.  If @timeout is zero, the object's state is tested and
54  * the function returns immediately.  If @timeout is %INFINITE, the
55  * function waits forever.
56  *
57  * Return value: %WAIT_ABANDONED - @handle is a mutex that was not
58  * released by the owning thread when it exited.  Ownership of the
59  * mutex object is granted to the calling thread and the mutex is set
60  * to nonsignalled.  %WAIT_OBJECT_0 - The state of @handle is
61  * signalled.  %WAIT_TIMEOUT - The @timeout interval elapsed and
62  * @handle's state is still not signalled.  %WAIT_FAILED - an error
63  * occurred. %WAIT_IO_COMPLETION - the wait was ended by an APC.
64  */
65 guint32 WaitForSingleObjectEx(gpointer handle, guint32 timeout,
66                               gboolean alertable)
67 {
68         guint32 ret, waited;
69         int thr_ret;
70         gboolean apc_pending = FALSE;
71         gpointer current_thread = wapi_get_current_thread_handle ();
72         gint64 now, end;
73         
74         if (current_thread == NULL) {
75                 SetLastError (ERROR_INVALID_HANDLE);
76                 return(WAIT_FAILED);
77         }
78
79         if (handle == _WAPI_THREAD_CURRENT) {
80                 handle = wapi_get_current_thread_handle ();
81                 if (handle == NULL) {
82                         SetLastError (ERROR_INVALID_HANDLE);
83                         return(WAIT_FAILED);
84                 }
85         }
86
87         if ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
88                 SetLastError (ERROR_INVALID_HANDLE);
89                 return(WAIT_FAILED);
90         }
91         
92         if (mono_w32handle_test_capabilities (handle,
93                                             MONO_W32HANDLE_CAP_WAIT) == FALSE) {
94                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p can't be waited for", __func__,
95                            handle);
96
97                 return(WAIT_FAILED);
98         }
99
100         mono_w32handle_ops_prewait (handle);
101         
102         if (mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_SPECIAL_WAIT) == TRUE) {
103                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p has special wait", __func__, handle);
104
105                 ret = mono_w32handle_ops_specialwait (handle, timeout, alertable);
106         
107                 if (alertable && _wapi_thread_cur_apc_pending ())
108                         ret = WAIT_IO_COMPLETION;
109
110                 return ret;
111         }
112         
113         
114         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: locking handle %p", __func__, handle);
115
116         thr_ret = mono_w32handle_lock_handle (handle);
117         g_assert (thr_ret == 0);
118
119         if (mono_w32handle_test_capabilities (handle,
120                                             MONO_W32HANDLE_CAP_OWN) == TRUE) {
121                 if (own_if_owned (handle) == TRUE) {
122                         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p already owned", __func__,
123                                    handle);
124                         ret = WAIT_OBJECT_0;
125                         goto done;
126                 }
127         }
128
129         if (own_if_signalled (handle) == TRUE) {
130                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p already signalled", __func__,
131                            handle);
132
133                 ret=WAIT_OBJECT_0;
134                 goto done;
135         }
136
137         if (timeout == 0) {
138                 ret = WAIT_TIMEOUT;
139                 goto done;
140         }
141         
142         if (timeout != INFINITE)
143                 end = mono_100ns_ticks () + timeout * 1000 * 10;
144
145         do {
146                 /* Check before waiting on the condition, just in case
147                  */
148                 mono_w32handle_ops_prewait (handle);
149
150                 if (own_if_signalled (handle)) {
151                         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p signalled", __func__,
152                                    handle);
153
154                         ret = WAIT_OBJECT_0;
155                         goto done;
156                 }
157
158                 if (timeout == INFINITE) {
159                         waited = mono_w32handle_timedwait_signal_handle (handle, INFINITE, FALSE, alertable ? &apc_pending : NULL);
160                 } else {
161                         now = mono_100ns_ticks ();
162                         if (end < now) {
163                                 ret = WAIT_TIMEOUT;
164                                 goto done;
165                         }
166
167                         waited = mono_w32handle_timedwait_signal_handle (handle, (end - now) / 10 / 1000, FALSE, alertable ? &apc_pending : NULL);
168                 }
169
170                 if(waited==0 && !apc_pending) {
171                         /* Condition was signalled, so hopefully
172                          * handle is signalled now.  (It might not be
173                          * if someone else got in before us.)
174                          */
175                         if (own_if_signalled (handle)) {
176                                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p signalled", __func__,
177                                            handle);
178
179                                 ret=WAIT_OBJECT_0;
180                                 goto done;
181                         }
182                 
183                         /* Better luck next time */
184                 }
185         } while(waited == 0 && !apc_pending);
186
187         /* Timeout or other error */
188         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: wait on handle %p error: %s", __func__, handle,
189                    strerror (waited));
190
191         ret = apc_pending ? WAIT_IO_COMPLETION : WAIT_TIMEOUT;
192
193 done:
194
195         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking handle %p", __func__, handle);
196         
197         thr_ret = mono_w32handle_unlock_handle (handle);
198         g_assert (thr_ret == 0);
199
200         return(ret);
201 }
202
203 guint32 WaitForSingleObject(gpointer handle, guint32 timeout)
204 {
205         return WaitForSingleObjectEx (handle, timeout, FALSE);
206 }
207
208
209 /**
210  * SignalObjectAndWait:
211  * @signal_handle: An object to signal
212  * @wait: An object to wait for
213  * @timeout: The maximum time in milliseconds to wait for
214  * @alertable: Specifies whether the function returnes when the system
215  * queues an I/O completion routine or an APC for the calling thread.
216  *
217  * Atomically signals @signal and waits for @wait to become signalled,
218  * or @timeout ms elapses.  If @timeout is zero, the object's state is
219  * tested and the function returns immediately.  If @timeout is
220  * %INFINITE, the function waits forever.
221  *
222  * @signal can be a semaphore, mutex or event object.
223  *
224  * If @alertable is %TRUE and the system queues an I/O completion
225  * routine or an APC for the calling thread, the function returns and
226  * the thread calls the completion routine or APC function.  If
227  * %FALSE, the function does not return, and the thread does not call
228  * the completion routine or APC function.  A completion routine is
229  * queued when the ReadFileEx() or WriteFileEx() function in which it
230  * was specified has completed.  The calling thread is the thread that
231  * initiated the read or write operation.  An APC is queued when
232  * QueueUserAPC() is called.  Currently completion routines and APC
233  * functions are not supported.
234  *
235  * Return value: %WAIT_ABANDONED - @wait is a mutex that was not
236  * released by the owning thread when it exited.  Ownershop of the
237  * mutex object is granted to the calling thread and the mutex is set
238  * to nonsignalled.  %WAIT_IO_COMPLETION - the wait was ended by one
239  * or more user-mode asynchronous procedure calls queued to the
240  * thread.  %WAIT_OBJECT_0 - The state of @wait is signalled.
241  * %WAIT_TIMEOUT - The @timeout interval elapsed and @wait's state is
242  * still not signalled.  %WAIT_FAILED - an error occurred.
243  */
244 guint32 SignalObjectAndWait(gpointer signal_handle, gpointer wait,
245                             guint32 timeout, gboolean alertable)
246 {
247         guint32 ret = 0, waited;
248         int thr_ret;
249         gboolean apc_pending = FALSE;
250         gpointer current_thread = wapi_get_current_thread_handle ();
251         gint64 now, end;
252         
253         if (current_thread == NULL) {
254                 SetLastError (ERROR_INVALID_HANDLE);
255                 return(WAIT_FAILED);
256         }
257
258         if (signal_handle == _WAPI_THREAD_CURRENT) {
259                 signal_handle = wapi_get_current_thread_handle ();
260                 if (signal_handle == NULL) {
261                         SetLastError (ERROR_INVALID_HANDLE);
262                         return(WAIT_FAILED);
263                 }
264         }
265
266         if (wait == _WAPI_THREAD_CURRENT) {
267                 wait = wapi_get_current_thread_handle ();
268                 if (wait == NULL) {
269                         SetLastError (ERROR_INVALID_HANDLE);
270                         return(WAIT_FAILED);
271                 }
272         }
273
274         if ((GPOINTER_TO_UINT (signal_handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
275                 SetLastError (ERROR_INVALID_HANDLE);
276                 return(WAIT_FAILED);
277         }
278
279         if ((GPOINTER_TO_UINT (wait) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
280                 SetLastError (ERROR_INVALID_HANDLE);
281                 return(WAIT_FAILED);
282         }
283         
284         if (mono_w32handle_test_capabilities (signal_handle,
285                                             MONO_W32HANDLE_CAP_SIGNAL)==FALSE) {
286                 return(WAIT_FAILED);
287         }
288         
289         if (mono_w32handle_test_capabilities (wait,
290                                             MONO_W32HANDLE_CAP_WAIT)==FALSE) {
291                 return(WAIT_FAILED);
292         }
293
294         mono_w32handle_ops_prewait (wait);
295         
296         if (mono_w32handle_test_capabilities (wait, MONO_W32HANDLE_CAP_SPECIAL_WAIT) == TRUE) {
297                 g_warning ("%s: handle %p has special wait, implement me!!",
298                            __func__, wait);
299
300                 return (WAIT_FAILED);
301         }
302
303         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: locking handle %p", __func__, wait);
304
305         thr_ret = mono_w32handle_lock_handle (wait);
306         g_assert (thr_ret == 0);
307
308         mono_w32handle_ops_signal (signal_handle);
309
310         if (mono_w32handle_test_capabilities (wait, MONO_W32HANDLE_CAP_OWN)==TRUE) {
311                 if (own_if_owned (wait)) {
312                         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p already owned", __func__,
313                                    wait);
314                         ret = WAIT_OBJECT_0;
315                         goto done;
316                 }
317         }
318
319         if (own_if_signalled (wait)) {
320                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p already signalled", __func__, wait);
321
322                 ret = WAIT_OBJECT_0;
323                 goto done;
324         }
325
326         if (timeout != INFINITE)
327                 end = mono_100ns_ticks () + timeout * 1000 * 10;
328
329         do {
330                 /* Check before waiting on the condition, just in case
331                  */
332                 mono_w32handle_ops_prewait (wait);
333         
334                 if (own_if_signalled (wait)) {
335                         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p signalled", __func__, wait);
336
337                         ret = WAIT_OBJECT_0;
338                         goto done;
339                 }
340
341                 if (timeout == INFINITE) {
342                         waited = mono_w32handle_timedwait_signal_handle (wait, INFINITE, FALSE, alertable ? &apc_pending : NULL);
343                 } else {
344                         now = mono_100ns_ticks ();
345                         if (end < now) {
346                                 ret = WAIT_TIMEOUT;
347                                 goto done;
348                         }
349
350                         waited = mono_w32handle_timedwait_signal_handle (wait, (end - now) / 10 / 1000, FALSE, alertable ? &apc_pending : NULL);
351                 }
352
353                 if (waited==0 && !apc_pending) {
354                         /* Condition was signalled, so hopefully
355                          * handle is signalled now.  (It might not be
356                          * if someone else got in before us.)
357                          */
358                         if (own_if_signalled (wait)) {
359                                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p signalled", __func__,
360                                            wait);
361
362                                 ret = WAIT_OBJECT_0;
363                                 goto done;
364                         }
365                 
366                         /* Better luck next time */
367                 }
368         } while(waited == 0 && !apc_pending);
369
370         /* Timeout or other error */
371         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: wait on handle %p error: %s", __func__, wait, strerror (ret));
372
373         ret = apc_pending ? WAIT_IO_COMPLETION : WAIT_TIMEOUT;
374
375 done:
376
377         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking handle %p", __func__, wait);
378
379         thr_ret = mono_w32handle_unlock_handle (wait);
380         g_assert (thr_ret == 0);
381
382         return(ret);
383 }
384
385 static gboolean test_and_own (guint32 numobjects, gpointer *handles,
386                               gboolean waitall, guint32 *count,
387                               guint32 *lowest)
388 {
389         gboolean done;
390         int i;
391         
392         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: locking handles", __func__);
393         
394         done = mono_w32handle_count_signalled_handles (numobjects, handles,
395                                                      waitall, count, lowest);
396         if (done == TRUE) {
397                 if (waitall == TRUE) {
398                         for (i = 0; i < numobjects; i++) {
399                                 own_if_signalled (handles[i]);
400                         }
401                 } else {
402                         own_if_signalled (handles[*lowest]);
403                 }
404         }
405         
406         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking handles", __func__);
407
408         mono_w32handle_unlock_handles (numobjects, handles);
409
410         return(done);
411 }
412
413 /**
414  * WaitForMultipleObjectsEx:
415  * @numobjects: The number of objects in @handles. The maximum allowed
416  * is %MAXIMUM_WAIT_OBJECTS.
417  * @handles: An array of object handles.  Duplicates are not allowed.
418  * @waitall: If %TRUE, this function waits until all of the handles
419  * are signalled.  If %FALSE, this function returns when any object is
420  * signalled.
421  * @timeout: The maximum time in milliseconds to wait for.
422  * @alertable: if TRUE, the wait can be interrupted by an APC call
423  * 
424  * This function returns when either one or more of @handles is
425  * signalled, or @timeout ms elapses.  If @timeout is zero, the state
426  * of each item of @handles is tested and the function returns
427  * immediately.  If @timeout is %INFINITE, the function waits forever.
428  *
429  * Return value: %WAIT_OBJECT_0 to %WAIT_OBJECT_0 + @numobjects - 1 -
430  * if @waitall is %TRUE, indicates that all objects are signalled.  If
431  * @waitall is %FALSE, the return value minus %WAIT_OBJECT_0 indicates
432  * the first index into @handles of the objects that are signalled.
433  * %WAIT_ABANDONED_0 to %WAIT_ABANDONED_0 + @numobjects - 1 - if
434  * @waitall is %TRUE, indicates that all objects are signalled, and at
435  * least one object is an abandoned mutex object (See
436  * WaitForSingleObject() for a description of abandoned mutexes.)  If
437  * @waitall is %FALSE, the return value minus %WAIT_ABANDONED_0
438  * indicates the first index into @handles of an abandoned mutex.
439  * %WAIT_TIMEOUT - The @timeout interval elapsed and no objects in
440  * @handles are signalled.  %WAIT_FAILED - an error occurred.
441  * %WAIT_IO_COMPLETION - the wait was ended by an APC.
442  */
443 guint32 WaitForMultipleObjectsEx(guint32 numobjects, gpointer *handles,
444                                  gboolean waitall, guint32 timeout,
445                                  gboolean alertable)
446 {
447         gboolean duplicate = FALSE, bogustype = FALSE, done;
448         guint32 count, lowest;
449         guint i;
450         guint32 ret;
451         int thr_ret;
452         gpointer current_thread = wapi_get_current_thread_handle ();
453         guint32 retval;
454         gboolean poll;
455         gpointer sorted_handles [MAXIMUM_WAIT_OBJECTS];
456         gboolean apc_pending = FALSE;
457         gint64 now, end;
458         
459         if (current_thread == NULL) {
460                 SetLastError (ERROR_INVALID_HANDLE);
461                 return(WAIT_FAILED);
462         }
463         
464         if (numobjects > MAXIMUM_WAIT_OBJECTS) {
465                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Too many handles: %d", __func__, numobjects);
466
467                 return(WAIT_FAILED);
468         }
469         
470         if (numobjects == 1) {
471                 return WaitForSingleObjectEx (handles [0], timeout, alertable);
472         }
473
474         /* Check for duplicates */
475         for (i = 0; i < numobjects; i++) {
476                 if (handles[i] == _WAPI_THREAD_CURRENT) {
477                         handles[i] = wapi_get_current_thread_handle ();
478                         
479                         if (handles[i] == NULL) {
480                                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Handle %d bogus", __func__, i);
481
482                                 bogustype = TRUE;
483                                 break;
484                         }
485                 }
486
487                 if ((GPOINTER_TO_UINT (handles[i]) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
488                         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Handle %d pseudo process", __func__,
489                                    i);
490
491                         bogustype = TRUE;
492                         break;
493                 }
494
495                 if (mono_w32handle_test_capabilities (handles[i], MONO_W32HANDLE_CAP_WAIT) == FALSE) {
496                         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Handle %p can't be waited for",
497                                    __func__, handles[i]);
498
499                         bogustype = TRUE;
500                         break;
501                 }
502
503                 sorted_handles [i] = handles [i];
504                 mono_w32handle_ops_prewait (handles[i]);
505         }
506
507         qsort (sorted_handles, numobjects, sizeof (gpointer), g_direct_equal);
508         for (i = 1; i < numobjects; i++) {
509                 if (sorted_handles [i - 1] == sorted_handles [i]) {
510                         duplicate = TRUE;
511                         break;
512                 }
513         }
514
515         if (duplicate == TRUE) {
516                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning due to duplicates", __func__);
517
518                 return(WAIT_FAILED);
519         }
520
521         if (bogustype == TRUE) {
522                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning due to bogus type", __func__);
523
524                 return(WAIT_FAILED);
525         }
526
527         poll = FALSE;
528         for (i = 0; i < numobjects; ++i)
529                 if (mono_w32handle_get_type (handles [i]) == MONO_W32HANDLE_PROCESS)
530                         /* Can't wait for a process handle + another handle without polling */
531                         poll = TRUE;
532
533         done = test_and_own (numobjects, handles, waitall, &count, &lowest);
534         if (done == TRUE) {
535                 return(WAIT_OBJECT_0+lowest);
536         }
537         
538         if (timeout == 0) {
539                 return WAIT_TIMEOUT;
540         }
541
542         if (timeout != INFINITE)
543                 end = mono_100ns_ticks () + timeout * 1000 * 10;
544
545         /* Have to wait for some or all handles to become signalled
546          */
547
548         for (i = 0; i < numobjects; i++) {
549                 /* Add a reference, as we need to ensure the handle wont
550                  * disappear from under us while we're waiting in the loop
551                  * (not lock, as we don't want exclusive access here)
552                  */
553                 mono_w32handle_ref (handles[i]);
554         }
555
556         while(1) {
557                 /* Prod all handles with prewait methods and
558                  * special-wait handles that aren't already signalled
559                  */
560                 for (i = 0; i < numobjects; i++) {
561                         mono_w32handle_ops_prewait (handles[i]);
562                 
563                         if (mono_w32handle_test_capabilities (handles[i], MONO_W32HANDLE_CAP_SPECIAL_WAIT) == TRUE && mono_w32handle_issignalled (handles[i]) == FALSE) {
564                                 mono_w32handle_ops_specialwait (handles[i], 0, alertable);
565                         }
566                 }
567                 
568                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: locking signal mutex", __func__);
569
570                 thr_ret = mono_w32handle_lock_signal_mutex ();
571                 g_assert (thr_ret == 0);
572
573                 /* Check the signalled state of handles inside the critical section */
574                 if (waitall) {
575                         done = TRUE;
576                         for (i = 0; i < numobjects; i++)
577                                 if (!mono_w32handle_issignalled (handles [i]))
578                                         done = FALSE;
579                 } else {
580                         done = FALSE;
581                         for (i = 0; i < numobjects; i++)
582                                 if (mono_w32handle_issignalled (handles [i]))
583                                         done = TRUE;
584                 }
585                 
586                 if (!done) {
587                         /* Enter the wait */
588                         if (timeout == INFINITE) {
589                                 ret = mono_w32handle_timedwait_signal (INFINITE, poll, &apc_pending);
590                         } else {
591                                 now = mono_100ns_ticks ();
592                                 if (end < now) {
593                                         ret = WAIT_TIMEOUT;
594                                 } else {
595                                         ret = mono_w32handle_timedwait_signal ((end - now) / 10 / 1000, poll, &apc_pending);
596                                 }
597                         }
598                 } else {
599                         /* No need to wait */
600                         ret = 0;
601                 }
602
603                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking signal mutex", __func__);
604
605                 thr_ret = mono_w32handle_unlock_signal_mutex ();
606                 g_assert (thr_ret == 0);
607                 
608                 if (alertable && apc_pending) {
609                         retval = WAIT_IO_COMPLETION;
610                         break;
611                 }
612         
613                 /* Check if everything is signalled, as we can't
614                  * guarantee to notice a shared signal even if the
615                  * wait timed out
616                  */
617                 done = test_and_own (numobjects, handles, waitall,
618                                      &count, &lowest);
619                 if (done == TRUE) {
620                         retval = WAIT_OBJECT_0+lowest;
621                         break;
622                 } else if (ret != 0) {
623                         /* Didn't get all handles, and there was a
624                          * timeout or other error
625                          */
626                         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: wait returned error: %s", __func__,
627                                    strerror (ret));
628
629                         if(ret==ETIMEDOUT) {
630                                 retval = WAIT_TIMEOUT;
631                         } else {
632                                 retval = WAIT_FAILED;
633                         }
634                         break;
635                 }
636         }
637
638         for (i = 0; i < numobjects; i++) {
639                 /* Unref everything we reffed above */
640                 mono_w32handle_unref (handles[i]);
641         }
642
643         return retval;
644 }
645
646 guint32 WaitForMultipleObjects(guint32 numobjects, gpointer *handles,
647                                gboolean waitall, guint32 timeout)
648 {
649         return WaitForMultipleObjectsEx(numobjects, handles, waitall, timeout, FALSE);
650 }
651
652 /**
653  * WaitForInputIdle:
654  * @handle: a handle to the process to wait for
655  * @timeout: the maximum time in milliseconds to wait for
656  *
657  * This function returns when either @handle process is waiting
658  * for input, or @timeout ms elapses.  If @timeout is zero, the
659  * process state is tested and the function returns immediately.
660  * If @timeout is %INFINITE, the function waits forever.
661  *
662  * Return value: 0 - @handle process is waiting for input.
663  * %WAIT_TIMEOUT - The @timeout interval elapsed and
664  * @handle process is not waiting for input.  %WAIT_FAILED - an error
665  * occurred. 
666  */
667 guint32 WaitForInputIdle(gpointer handle, guint32 timeout)
668 {
669         /*TODO: Not implemented*/
670         return WAIT_TIMEOUT;
671 }
672