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