[threading] Remove old suspend code now that all targets support it.
[mono-project.git] / mono / io-layer / wait.c
blob8bdf39bdbf8ac54d05257c7365b73feb8b902b94
1 /*
2 * wait.c: wait for handles to become signalled
4 * Author:
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002-2006 Novell, Inc.
8 */
10 #include <config.h>
11 #include <glib.h>
12 #include <string.h>
13 #include <errno.h>
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/misc-private.h>
20 #include <mono/utils/mono-mutex.h>
22 #if 0
23 #define DEBUG(...) g_message(__VA_ARGS__)
24 #else
25 #define DEBUG(...)
26 #endif
28 static gboolean own_if_signalled(gpointer handle)
30 gboolean ret = FALSE;
32 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
33 if (_wapi_handle_trylock_shared_handles () == EBUSY) {
34 return (FALSE);
38 if (_wapi_handle_issignalled (handle)) {
39 _wapi_handle_ops_own (handle);
40 ret = TRUE;
43 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
44 _wapi_handle_unlock_shared_handles ();
47 return(ret);
50 static gboolean own_if_owned(gpointer handle)
52 gboolean ret = FALSE;
54 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
55 if (_wapi_handle_trylock_shared_handles () == EBUSY) {
56 return (FALSE);
60 if (_wapi_handle_ops_isowned (handle)) {
61 _wapi_handle_ops_own (handle);
62 ret = TRUE;
65 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
66 _wapi_handle_unlock_shared_handles ();
69 return(ret);
72 /**
73 * WaitForSingleObjectEx:
74 * @handle: an object to wait for
75 * @timeout: the maximum time in milliseconds to wait for
76 * @alertable: if TRUE, the wait can be interrupted by an APC call
78 * This function returns when either @handle is signalled, or @timeout
79 * ms elapses. If @timeout is zero, the object's state is tested and
80 * the function returns immediately. If @timeout is %INFINITE, the
81 * function waits forever.
83 * Return value: %WAIT_ABANDONED - @handle is a mutex that was not
84 * released by the owning thread when it exited. Ownership of the
85 * mutex object is granted to the calling thread and the mutex is set
86 * to nonsignalled. %WAIT_OBJECT_0 - The state of @handle is
87 * signalled. %WAIT_TIMEOUT - The @timeout interval elapsed and
88 * @handle's state is still not signalled. %WAIT_FAILED - an error
89 * occurred. %WAIT_IO_COMPLETION - the wait was ended by an APC.
91 guint32 WaitForSingleObjectEx(gpointer handle, guint32 timeout,
92 gboolean alertable)
94 guint32 ret, waited;
95 struct timespec abstime;
96 int thr_ret;
97 gboolean apc_pending = FALSE;
98 gpointer current_thread = wapi_get_current_thread_handle ();
100 if (current_thread == NULL) {
101 SetLastError (ERROR_INVALID_HANDLE);
102 return(WAIT_FAILED);
105 if (handle == _WAPI_THREAD_CURRENT) {
106 handle = wapi_get_current_thread_handle ();
107 if (handle == NULL) {
108 SetLastError (ERROR_INVALID_HANDLE);
109 return(WAIT_FAILED);
113 if ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
114 SetLastError (ERROR_INVALID_HANDLE);
115 return(WAIT_FAILED);
118 if (_wapi_handle_test_capabilities (handle,
119 WAPI_HANDLE_CAP_WAIT) == FALSE) {
120 DEBUG ("%s: handle %p can't be waited for", __func__,
121 handle);
123 return(WAIT_FAILED);
126 _wapi_handle_ops_prewait (handle);
128 if (_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE) {
129 DEBUG ("%s: handle %p has special wait", __func__, handle);
131 ret = _wapi_handle_ops_special_wait (handle, timeout, alertable);
133 if (alertable && _wapi_thread_apc_pending (current_thread)) {
134 apc_pending = TRUE;
135 ret = WAIT_IO_COMPLETION;
138 goto check_pending;
142 DEBUG ("%s: locking handle %p", __func__, handle);
144 thr_ret = _wapi_handle_lock_handle (handle);
145 g_assert (thr_ret == 0);
147 if (_wapi_handle_test_capabilities (handle,
148 WAPI_HANDLE_CAP_OWN) == TRUE) {
149 if (own_if_owned (handle) == TRUE) {
150 DEBUG ("%s: handle %p already owned", __func__,
151 handle);
152 ret = WAIT_OBJECT_0;
153 goto done;
157 if (alertable && _wapi_thread_apc_pending (current_thread)) {
158 apc_pending = TRUE;
159 ret = WAIT_IO_COMPLETION;
160 goto done;
163 if (own_if_signalled (handle) == TRUE) {
164 DEBUG ("%s: handle %p already signalled", __func__,
165 handle);
167 ret=WAIT_OBJECT_0;
168 goto done;
171 if (timeout == 0) {
172 ret = WAIT_TIMEOUT;
173 goto done;
175 /* Have to wait for it */
176 if (timeout != INFINITE) {
177 _wapi_calc_timeout (&abstime, timeout);
180 do {
181 /* Check before waiting on the condition, just in case
183 _wapi_handle_ops_prewait (handle);
185 if (own_if_signalled (handle)) {
186 DEBUG ("%s: handle %p signalled", __func__,
187 handle);
189 ret = WAIT_OBJECT_0;
190 goto done;
193 if (timeout == INFINITE) {
194 waited = _wapi_handle_wait_signal_handle (handle, alertable);
195 } else {
196 waited = _wapi_handle_timedwait_signal_handle (handle, &abstime, alertable, FALSE);
199 if (alertable)
200 apc_pending = _wapi_thread_apc_pending (current_thread);
202 if(waited==0 && !apc_pending) {
203 /* Condition was signalled, so hopefully
204 * handle is signalled now. (It might not be
205 * if someone else got in before us.)
207 if (own_if_signalled (handle)) {
208 DEBUG ("%s: handle %p signalled", __func__,
209 handle);
211 ret=WAIT_OBJECT_0;
212 goto done;
215 /* Better luck next time */
217 } while(waited == 0 && !apc_pending);
219 /* Timeout or other error */
220 DEBUG ("%s: wait on handle %p error: %s", __func__, handle,
221 strerror (waited));
223 ret = WAIT_TIMEOUT;
225 done:
227 DEBUG ("%s: unlocking handle %p", __func__, handle);
229 thr_ret = _wapi_handle_unlock_handle (handle);
230 g_assert (thr_ret == 0);
232 check_pending:
233 if (apc_pending)
234 ret = WAIT_IO_COMPLETION;
236 return(ret);
239 guint32 WaitForSingleObject(gpointer handle, guint32 timeout)
241 return WaitForSingleObjectEx (handle, timeout, FALSE);
246 * SignalObjectAndWait:
247 * @signal_handle: An object to signal
248 * @wait: An object to wait for
249 * @timeout: The maximum time in milliseconds to wait for
250 * @alertable: Specifies whether the function returnes when the system
251 * queues an I/O completion routine or an APC for the calling thread.
253 * Atomically signals @signal and waits for @wait to become signalled,
254 * or @timeout ms elapses. If @timeout is zero, the object's state is
255 * tested and the function returns immediately. If @timeout is
256 * %INFINITE, the function waits forever.
258 * @signal can be a semaphore, mutex or event object.
260 * If @alertable is %TRUE and the system queues an I/O completion
261 * routine or an APC for the calling thread, the function returns and
262 * the thread calls the completion routine or APC function. If
263 * %FALSE, the function does not return, and the thread does not call
264 * the completion routine or APC function. A completion routine is
265 * queued when the ReadFileEx() or WriteFileEx() function in which it
266 * was specified has completed. The calling thread is the thread that
267 * initiated the read or write operation. An APC is queued when
268 * QueueUserAPC() is called. Currently completion routines and APC
269 * functions are not supported.
271 * Return value: %WAIT_ABANDONED - @wait is a mutex that was not
272 * released by the owning thread when it exited. Ownershop of the
273 * mutex object is granted to the calling thread and the mutex is set
274 * to nonsignalled. %WAIT_IO_COMPLETION - the wait was ended by one
275 * or more user-mode asynchronous procedure calls queued to the
276 * thread. %WAIT_OBJECT_0 - The state of @wait is signalled.
277 * %WAIT_TIMEOUT - The @timeout interval elapsed and @wait's state is
278 * still not signalled. %WAIT_FAILED - an error occurred.
280 guint32 SignalObjectAndWait(gpointer signal_handle, gpointer wait,
281 guint32 timeout, gboolean alertable)
283 guint32 ret, waited;
284 struct timespec abstime;
285 int thr_ret;
286 gboolean apc_pending = FALSE;
287 gpointer current_thread = wapi_get_current_thread_handle ();
289 if (current_thread == NULL) {
290 SetLastError (ERROR_INVALID_HANDLE);
291 return(WAIT_FAILED);
294 if (signal_handle == _WAPI_THREAD_CURRENT) {
295 signal_handle = wapi_get_current_thread_handle ();
296 if (signal_handle == NULL) {
297 SetLastError (ERROR_INVALID_HANDLE);
298 return(WAIT_FAILED);
302 if (wait == _WAPI_THREAD_CURRENT) {
303 wait = wapi_get_current_thread_handle ();
304 if (wait == NULL) {
305 SetLastError (ERROR_INVALID_HANDLE);
306 return(WAIT_FAILED);
310 if ((GPOINTER_TO_UINT (signal_handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
311 SetLastError (ERROR_INVALID_HANDLE);
312 return(WAIT_FAILED);
315 if ((GPOINTER_TO_UINT (wait) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
316 SetLastError (ERROR_INVALID_HANDLE);
317 return(WAIT_FAILED);
320 if (_wapi_handle_test_capabilities (signal_handle,
321 WAPI_HANDLE_CAP_SIGNAL)==FALSE) {
322 return(WAIT_FAILED);
325 if (_wapi_handle_test_capabilities (wait,
326 WAPI_HANDLE_CAP_WAIT)==FALSE) {
327 return(WAIT_FAILED);
330 _wapi_handle_ops_prewait (wait);
332 if (_wapi_handle_test_capabilities (wait, WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE) {
333 g_warning ("%s: handle %p has special wait, implement me!!",
334 __func__, wait);
336 return (WAIT_FAILED);
339 DEBUG ("%s: locking handle %p", __func__, wait);
341 thr_ret = _wapi_handle_lock_handle (wait);
342 g_assert (thr_ret == 0);
344 _wapi_handle_ops_signal (signal_handle);
346 if (_wapi_handle_test_capabilities (wait, WAPI_HANDLE_CAP_OWN)==TRUE) {
347 if (own_if_owned (wait)) {
348 DEBUG ("%s: handle %p already owned", __func__,
349 wait);
350 ret = WAIT_OBJECT_0;
351 goto done;
355 if (alertable && _wapi_thread_apc_pending (current_thread)) {
356 apc_pending = TRUE;
357 ret = WAIT_IO_COMPLETION;
358 goto done;
361 if (own_if_signalled (wait)) {
362 DEBUG ("%s: handle %p already signalled", __func__, wait);
364 ret = WAIT_OBJECT_0;
365 goto done;
368 /* Have to wait for it */
369 if (timeout != INFINITE) {
370 _wapi_calc_timeout (&abstime, timeout);
373 do {
374 /* Check before waiting on the condition, just in case
376 _wapi_handle_ops_prewait (wait);
378 if (own_if_signalled (wait)) {
379 DEBUG ("%s: handle %p signalled", __func__, wait);
381 ret = WAIT_OBJECT_0;
382 goto done;
385 if (timeout == INFINITE) {
386 waited = _wapi_handle_wait_signal_handle (wait, alertable);
387 } else {
388 waited = _wapi_handle_timedwait_signal_handle (wait, &abstime, alertable, FALSE);
391 if (alertable) {
392 apc_pending = _wapi_thread_apc_pending (current_thread);
395 if (waited==0 && !apc_pending) {
396 /* Condition was signalled, so hopefully
397 * handle is signalled now. (It might not be
398 * if someone else got in before us.)
400 if (own_if_signalled (wait)) {
401 DEBUG ("%s: handle %p signalled", __func__,
402 wait);
404 ret = WAIT_OBJECT_0;
405 goto done;
408 /* Better luck next time */
410 } while(waited == 0 && !apc_pending);
412 /* Timeout or other error */
413 DEBUG ("%s: wait on handle %p error: %s", __func__, wait,
414 strerror (ret));
416 ret = WAIT_TIMEOUT;
418 done:
420 DEBUG ("%s: unlocking handle %p", __func__, wait);
422 thr_ret = _wapi_handle_unlock_handle (wait);
423 g_assert (thr_ret == 0);
425 if (apc_pending)
426 ret = WAIT_IO_COMPLETION;
428 return(ret);
431 static gboolean test_and_own (guint32 numobjects, gpointer *handles,
432 gboolean waitall, guint32 *count,
433 guint32 *lowest)
435 gboolean done;
436 int i;
438 DEBUG ("%s: locking handles", __func__);
440 done = _wapi_handle_count_signalled_handles (numobjects, handles,
441 waitall, count, lowest);
442 if (done == TRUE) {
443 if (waitall == TRUE) {
444 for (i = 0; i < numobjects; i++) {
445 own_if_signalled (handles[i]);
447 } else {
448 own_if_signalled (handles[*lowest]);
452 DEBUG ("%s: unlocking handles", __func__);
454 _wapi_handle_unlock_handles (numobjects, handles);
456 return(done);
460 * WaitForMultipleObjectsEx:
461 * @numobjects: The number of objects in @handles. The maximum allowed
462 * is %MAXIMUM_WAIT_OBJECTS.
463 * @handles: An array of object handles. Duplicates are not allowed.
464 * @waitall: If %TRUE, this function waits until all of the handles
465 * are signalled. If %FALSE, this function returns when any object is
466 * signalled.
467 * @timeout: The maximum time in milliseconds to wait for.
468 * @alertable: if TRUE, the wait can be interrupted by an APC call
470 * This function returns when either one or more of @handles is
471 * signalled, or @timeout ms elapses. If @timeout is zero, the state
472 * of each item of @handles is tested and the function returns
473 * immediately. If @timeout is %INFINITE, the function waits forever.
475 * Return value: %WAIT_OBJECT_0 to %WAIT_OBJECT_0 + @numobjects - 1 -
476 * if @waitall is %TRUE, indicates that all objects are signalled. If
477 * @waitall is %FALSE, the return value minus %WAIT_OBJECT_0 indicates
478 * the first index into @handles of the objects that are signalled.
479 * %WAIT_ABANDONED_0 to %WAIT_ABANDONED_0 + @numobjects - 1 - if
480 * @waitall is %TRUE, indicates that all objects are signalled, and at
481 * least one object is an abandoned mutex object (See
482 * WaitForSingleObject() for a description of abandoned mutexes.) If
483 * @waitall is %FALSE, the return value minus %WAIT_ABANDONED_0
484 * indicates the first index into @handles of an abandoned mutex.
485 * %WAIT_TIMEOUT - The @timeout interval elapsed and no objects in
486 * @handles are signalled. %WAIT_FAILED - an error occurred.
487 * %WAIT_IO_COMPLETION - the wait was ended by an APC.
489 guint32 WaitForMultipleObjectsEx(guint32 numobjects, gpointer *handles,
490 gboolean waitall, guint32 timeout,
491 gboolean alertable)
493 gboolean duplicate = FALSE, bogustype = FALSE, done;
494 guint32 count, lowest;
495 struct timespec abstime;
496 guint i;
497 guint32 ret;
498 int thr_ret;
499 gpointer current_thread = wapi_get_current_thread_handle ();
500 guint32 retval;
501 gboolean poll;
502 gpointer sorted_handles [MAXIMUM_WAIT_OBJECTS];
504 if (current_thread == NULL) {
505 SetLastError (ERROR_INVALID_HANDLE);
506 return(WAIT_FAILED);
509 if (numobjects > MAXIMUM_WAIT_OBJECTS) {
510 DEBUG ("%s: Too many handles: %d", __func__, numobjects);
512 return(WAIT_FAILED);
515 if (numobjects == 1) {
516 return WaitForSingleObjectEx (handles [0], timeout, alertable);
519 /* Check for duplicates */
520 for (i = 0; i < numobjects; i++) {
521 if (handles[i] == _WAPI_THREAD_CURRENT) {
522 handles[i] = wapi_get_current_thread_handle ();
524 if (handles[i] == NULL) {
525 DEBUG ("%s: Handle %d bogus", __func__, i);
527 bogustype = TRUE;
528 break;
532 if ((GPOINTER_TO_UINT (handles[i]) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
533 DEBUG ("%s: Handle %d pseudo process", __func__,
536 bogustype = TRUE;
537 break;
540 if (_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_WAIT) == FALSE) {
541 DEBUG ("%s: Handle %p can't be waited for",
542 __func__, handles[i]);
544 bogustype = TRUE;
545 break;
548 sorted_handles [i] = handles [i];
549 _wapi_handle_ops_prewait (handles[i]);
552 qsort (sorted_handles, numobjects, sizeof (gpointer), g_direct_equal);
553 for (i = 1; i < numobjects; i++) {
554 if (sorted_handles [i - 1] == sorted_handles [i]) {
555 duplicate = TRUE;
556 break;
560 if (duplicate == TRUE) {
561 DEBUG ("%s: Returning due to duplicates", __func__);
563 return(WAIT_FAILED);
566 if (bogustype == TRUE) {
567 DEBUG ("%s: Returning due to bogus type", __func__);
569 return(WAIT_FAILED);
572 poll = FALSE;
573 for (i = 0; i < numobjects; ++i)
574 if (_wapi_handle_type (handles [i]) == WAPI_HANDLE_PROCESS || _WAPI_SHARED_HANDLE (_wapi_handle_type (handles[i])))
575 /* Can't wait for a process handle + another handle without polling */
576 poll = TRUE;
578 done = test_and_own (numobjects, handles, waitall, &count, &lowest);
579 if (done == TRUE) {
580 return(WAIT_OBJECT_0+lowest);
583 if (timeout == 0) {
584 return WAIT_TIMEOUT;
586 /* Have to wait for some or all handles to become signalled
589 if(timeout!=INFINITE) {
590 _wapi_calc_timeout (&abstime, timeout);
593 if (alertable && _wapi_thread_apc_pending (current_thread))
594 return WAIT_IO_COMPLETION;
596 for (i = 0; i < numobjects; i++) {
597 /* Add a reference, as we need to ensure the handle wont
598 * disappear from under us while we're waiting in the loop
599 * (not lock, as we don't want exclusive access here)
601 _wapi_handle_ref (handles[i]);
604 while(1) {
605 /* Prod all handles with prewait methods and
606 * special-wait handles that aren't already signalled
608 for (i = 0; i < numobjects; i++) {
609 _wapi_handle_ops_prewait (handles[i]);
611 if (_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE && _wapi_handle_issignalled (handles[i]) == FALSE) {
612 _wapi_handle_ops_special_wait (handles[i], 0, alertable);
616 DEBUG ("%s: locking signal mutex", __func__);
618 thr_ret = _wapi_handle_lock_signal_mutex ();
619 g_assert (thr_ret == 0);
621 /* Check the signalled state of handles inside the critical section */
622 if (waitall) {
623 done = TRUE;
624 for (i = 0; i < numobjects; i++)
625 if (!_wapi_handle_issignalled (handles [i]))
626 done = FALSE;
627 } else {
628 done = FALSE;
629 for (i = 0; i < numobjects; i++)
630 if (_wapi_handle_issignalled (handles [i]))
631 done = TRUE;
634 if (!done) {
635 /* Enter the wait */
636 if (timeout == INFINITE) {
637 ret = _wapi_handle_wait_signal (poll);
638 } else {
639 ret = _wapi_handle_timedwait_signal (&abstime, poll);
641 } else {
642 /* No need to wait */
643 ret = 0;
646 DEBUG ("%s: unlocking signal mutex", __func__);
648 thr_ret = _wapi_handle_unlock_signal_mutex (NULL);
649 g_assert (thr_ret == 0);
651 if (alertable && _wapi_thread_apc_pending (current_thread)) {
652 retval = WAIT_IO_COMPLETION;
653 break;
656 /* Check if everything is signalled, as we can't
657 * guarantee to notice a shared signal even if the
658 * wait timed out
660 done = test_and_own (numobjects, handles, waitall,
661 &count, &lowest);
662 if (done == TRUE) {
663 retval = WAIT_OBJECT_0+lowest;
664 break;
665 } else if (ret != 0) {
666 /* Didn't get all handles, and there was a
667 * timeout or other error
669 DEBUG ("%s: wait returned error: %s", __func__,
670 strerror (ret));
672 if(ret==ETIMEDOUT) {
673 retval = WAIT_TIMEOUT;
674 } else {
675 retval = WAIT_FAILED;
677 break;
681 for (i = 0; i < numobjects; i++) {
682 /* Unref everything we reffed above */
683 _wapi_handle_unref (handles[i]);
686 return retval;
689 guint32 WaitForMultipleObjects(guint32 numobjects, gpointer *handles,
690 gboolean waitall, guint32 timeout)
692 return WaitForMultipleObjectsEx(numobjects, handles, waitall, timeout, FALSE);
696 * WaitForInputIdle:
697 * @handle: a handle to the process to wait for
698 * @timeout: the maximum time in milliseconds to wait for
700 * This function returns when either @handle process is waiting
701 * for input, or @timeout ms elapses. If @timeout is zero, the
702 * process state is tested and the function returns immediately.
703 * If @timeout is %INFINITE, the function waits forever.
705 * Return value: 0 - @handle process is waiting for input.
706 * %WAIT_TIMEOUT - The @timeout interval elapsed and
707 * @handle process is not waiting for input. %WAIT_FAILED - an error
708 * occurred.
710 guint32 WaitForInputIdle(gpointer handle, guint32 timeout)
712 /*TODO: Not implemented*/
713 return WAIT_TIMEOUT;