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