2 * wait.c: wait for handles to become signalled
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002-2006 Novell, Inc.
15 #include <mono/utils/gc_wrapper.h>
17 #include <mono/io-layer/wapi.h>
18 #include <mono/io-layer/handles-private.h>
19 #include <mono/io-layer/wapi-private.h>
20 #include <mono/io-layer/mono-mutex.h>
21 #include <mono/io-layer/misc-private.h>
25 static gboolean
own_if_signalled(gpointer handle
)
29 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle
))) {
30 if (_wapi_handle_trylock_shared_handles () == EBUSY
) {
35 if (_wapi_handle_issignalled (handle
)) {
36 _wapi_handle_ops_own (handle
);
40 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle
))) {
41 _wapi_handle_unlock_shared_handles ();
47 static gboolean
own_if_owned(gpointer handle
)
51 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle
))) {
52 if (_wapi_handle_trylock_shared_handles () == EBUSY
) {
57 if (_wapi_handle_ops_isowned (handle
)) {
58 _wapi_handle_ops_own (handle
);
62 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle
))) {
63 _wapi_handle_unlock_shared_handles ();
70 * WaitForSingleObjectEx:
71 * @handle: an object to wait for
72 * @timeout: the maximum time in milliseconds to wait for
73 * @alertable: if TRUE, the wait can be interrupted by an APC call
75 * This function returns when either @handle is signalled, or @timeout
76 * ms elapses. If @timeout is zero, the object's state is tested and
77 * the function returns immediately. If @timeout is %INFINITE, the
78 * function waits forever.
80 * Return value: %WAIT_ABANDONED - @handle is a mutex that was not
81 * released by the owning thread when it exited. Ownership of the
82 * mutex object is granted to the calling thread and the mutex is set
83 * to nonsignalled. %WAIT_OBJECT_0 - The state of @handle is
84 * signalled. %WAIT_TIMEOUT - The @timeout interval elapsed and
85 * @handle's state is still not signalled. %WAIT_FAILED - an error
86 * occurred. %WAIT_IO_COMPLETION - the wait was ended by an APC.
88 guint32
WaitForSingleObjectEx(gpointer handle
, guint32 timeout
,
92 struct timespec abstime
;
94 gboolean apc_pending
= FALSE
;
95 gpointer current_thread
= _wapi_thread_handle_from_id (pthread_self ());
97 if (current_thread
== NULL
) {
98 SetLastError (ERROR_INVALID_HANDLE
);
102 if (handle
== _WAPI_THREAD_CURRENT
) {
103 handle
= _wapi_thread_handle_from_id (pthread_self ());
104 if (handle
== NULL
) {
105 SetLastError (ERROR_INVALID_HANDLE
);
110 if ((GPOINTER_TO_UINT (handle
) & _WAPI_PROCESS_UNHANDLED
) == _WAPI_PROCESS_UNHANDLED
) {
111 SetLastError (ERROR_INVALID_HANDLE
);
115 if (_wapi_handle_test_capabilities (handle
,
116 WAPI_HANDLE_CAP_WAIT
) == FALSE
) {
118 g_message ("%s: handle %p can't be waited for", __func__
,
125 _wapi_handle_ops_prewait (handle
);
127 if (_wapi_handle_test_capabilities (handle
, WAPI_HANDLE_CAP_SPECIAL_WAIT
) == TRUE
) {
129 g_message ("%s: handle %p has special wait", __func__
, handle
);
132 ret
= _wapi_handle_ops_special_wait (handle
, timeout
);
134 if (alertable
&& _wapi_thread_apc_pending (current_thread
)) {
136 ret
= WAIT_IO_COMPLETION
;
144 g_message ("%s: locking handle %p", __func__
, handle
);
147 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle
,
149 thr_ret
= _wapi_handle_lock_handle (handle
);
150 g_assert (thr_ret
== 0);
152 if (_wapi_handle_test_capabilities (handle
,
153 WAPI_HANDLE_CAP_OWN
) == TRUE
) {
154 if (own_if_owned (handle
) == TRUE
) {
156 g_message ("%s: handle %p already owned", __func__
,
164 if (alertable
&& _wapi_thread_apc_pending (current_thread
)) {
166 ret
= WAIT_IO_COMPLETION
;
170 if (own_if_signalled (handle
) == TRUE
) {
172 g_message ("%s: handle %p already signalled", __func__
,
184 /* Have to wait for it */
185 if (timeout
!= INFINITE
) {
186 _wapi_calc_timeout (&abstime
, timeout
);
190 /* Check before waiting on the condition, just in case
192 _wapi_handle_ops_prewait (handle
);
194 if (own_if_signalled (handle
)) {
196 g_message ("%s: handle %p signalled", __func__
,
204 if (timeout
== INFINITE
) {
205 waited
= _wapi_handle_wait_signal_handle (handle
, alertable
);
207 waited
= _wapi_handle_timedwait_signal_handle (handle
, &abstime
, alertable
, FALSE
);
211 apc_pending
= _wapi_thread_apc_pending (current_thread
);
213 if(waited
==0 && !apc_pending
) {
214 /* Condition was signalled, so hopefully
215 * handle is signalled now. (It might not be
216 * if someone else got in before us.)
218 if (own_if_signalled (handle
)) {
220 g_message ("%s: handle %p signalled", __func__
,
228 /* Better luck next time */
230 } while(waited
== 0 && !apc_pending
);
232 /* Timeout or other error */
234 g_message ("%s: wait on handle %p error: %s", __func__
, handle
,
243 g_message ("%s: unlocking handle %p", __func__
, handle
);
246 thr_ret
= _wapi_handle_unlock_handle (handle
);
247 g_assert (thr_ret
== 0);
248 pthread_cleanup_pop (0);
252 _wapi_thread_dispatch_apc_queue (current_thread
);
253 ret
= WAIT_IO_COMPLETION
;
259 guint32
WaitForSingleObject(gpointer handle
, guint32 timeout
)
261 return WaitForSingleObjectEx (handle
, timeout
, FALSE
);
266 * SignalObjectAndWait:
267 * @signal_handle: An object to signal
268 * @wait: An object to wait for
269 * @timeout: The maximum time in milliseconds to wait for
270 * @alertable: Specifies whether the function returnes when the system
271 * queues an I/O completion routine or an APC for the calling thread.
273 * Atomically signals @signal and waits for @wait to become signalled,
274 * or @timeout ms elapses. If @timeout is zero, the object's state is
275 * tested and the function returns immediately. If @timeout is
276 * %INFINITE, the function waits forever.
278 * @signal can be a semaphore, mutex or event object.
280 * If @alertable is %TRUE and the system queues an I/O completion
281 * routine or an APC for the calling thread, the function returns and
282 * the thread calls the completion routine or APC function. If
283 * %FALSE, the function does not return, and the thread does not call
284 * the completion routine or APC function. A completion routine is
285 * queued when the ReadFileEx() or WriteFileEx() function in which it
286 * was specified has completed. The calling thread is the thread that
287 * initiated the read or write operation. An APC is queued when
288 * QueueUserAPC() is called. Currently completion routines and APC
289 * functions are not supported.
291 * Return value: %WAIT_ABANDONED - @wait is a mutex that was not
292 * released by the owning thread when it exited. Ownershop of the
293 * mutex object is granted to the calling thread and the mutex is set
294 * to nonsignalled. %WAIT_IO_COMPLETION - the wait was ended by one
295 * or more user-mode asynchronous procedure calls queued to the
296 * thread. %WAIT_OBJECT_0 - The state of @wait is signalled.
297 * %WAIT_TIMEOUT - The @timeout interval elapsed and @wait's state is
298 * still not signalled. %WAIT_FAILED - an error occurred.
300 guint32
SignalObjectAndWait(gpointer signal_handle
, gpointer wait
,
301 guint32 timeout
, gboolean alertable
)
304 struct timespec abstime
;
306 gboolean apc_pending
= FALSE
;
307 gpointer current_thread
= _wapi_thread_handle_from_id (pthread_self ());
309 if (current_thread
== NULL
) {
310 SetLastError (ERROR_INVALID_HANDLE
);
314 if (signal_handle
== _WAPI_THREAD_CURRENT
) {
315 signal_handle
= _wapi_thread_handle_from_id (pthread_self ());
316 if (signal_handle
== NULL
) {
317 SetLastError (ERROR_INVALID_HANDLE
);
322 if (wait
== _WAPI_THREAD_CURRENT
) {
323 wait
= _wapi_thread_handle_from_id (pthread_self ());
325 SetLastError (ERROR_INVALID_HANDLE
);
330 if ((GPOINTER_TO_UINT (signal_handle
) & _WAPI_PROCESS_UNHANDLED
) == _WAPI_PROCESS_UNHANDLED
) {
331 SetLastError (ERROR_INVALID_HANDLE
);
335 if ((GPOINTER_TO_UINT (wait
) & _WAPI_PROCESS_UNHANDLED
) == _WAPI_PROCESS_UNHANDLED
) {
336 SetLastError (ERROR_INVALID_HANDLE
);
340 if (_wapi_handle_test_capabilities (signal_handle
,
341 WAPI_HANDLE_CAP_SIGNAL
)==FALSE
) {
345 if (_wapi_handle_test_capabilities (wait
,
346 WAPI_HANDLE_CAP_WAIT
)==FALSE
) {
350 _wapi_handle_ops_prewait (wait
);
352 if (_wapi_handle_test_capabilities (wait
, WAPI_HANDLE_CAP_SPECIAL_WAIT
) == TRUE
) {
353 g_warning ("%s: handle %p has special wait, implement me!!",
356 return (WAIT_FAILED
);
360 g_message ("%s: locking handle %p", __func__
, wait
);
363 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle
,
365 thr_ret
= _wapi_handle_lock_handle (wait
);
366 g_assert (thr_ret
== 0);
368 _wapi_handle_ops_signal (signal_handle
);
370 if (_wapi_handle_test_capabilities (wait
, WAPI_HANDLE_CAP_OWN
)==TRUE
) {
371 if (own_if_owned (wait
)) {
373 g_message ("%s: handle %p already owned", __func__
,
381 if (alertable
&& _wapi_thread_apc_pending (current_thread
)) {
383 ret
= WAIT_IO_COMPLETION
;
387 if (own_if_signalled (wait
)) {
389 g_message ("%s: handle %p already signalled", __func__
, wait
);
396 /* Have to wait for it */
397 if (timeout
!= INFINITE
) {
398 _wapi_calc_timeout (&abstime
, timeout
);
402 /* Check before waiting on the condition, just in case
404 _wapi_handle_ops_prewait (wait
);
406 if (own_if_signalled (wait
)) {
408 g_message ("%s: handle %p signalled", __func__
, wait
);
415 if (timeout
== INFINITE
) {
416 waited
= _wapi_handle_wait_signal_handle (wait
, alertable
);
418 waited
= _wapi_handle_timedwait_signal_handle (wait
, &abstime
, alertable
, FALSE
);
422 apc_pending
= _wapi_thread_apc_pending (current_thread
);
425 if (waited
==0 && !apc_pending
) {
426 /* Condition was signalled, so hopefully
427 * handle is signalled now. (It might not be
428 * if someone else got in before us.)
430 if (own_if_signalled (wait
)) {
432 g_message ("%s: handle %p signalled", __func__
,
440 /* Better luck next time */
442 } while(waited
== 0 && !apc_pending
);
444 /* Timeout or other error */
446 g_message ("%s: wait on handle %p error: %s", __func__
, wait
,
455 g_message ("%s: unlocking handle %p", __func__
, wait
);
458 thr_ret
= _wapi_handle_unlock_handle (wait
);
459 g_assert (thr_ret
== 0);
460 pthread_cleanup_pop (0);
463 _wapi_thread_dispatch_apc_queue (current_thread
);
464 ret
= WAIT_IO_COMPLETION
;
470 struct handle_cleanup_data
476 static void handle_cleanup (void *data
)
478 struct handle_cleanup_data
*handles
= (struct handle_cleanup_data
*)data
;
480 _wapi_handle_unlock_handles (handles
->numobjects
, handles
->handles
);
483 static gboolean
test_and_own (guint32 numobjects
, gpointer
*handles
,
484 gboolean waitall
, guint32
*count
,
487 struct handle_cleanup_data cleanup_data
;
492 g_message ("%s: locking handles", __func__
);
494 cleanup_data
.numobjects
= numobjects
;
495 cleanup_data
.handles
= handles
;
497 pthread_cleanup_push (handle_cleanup
, (void *)&cleanup_data
);
498 done
= _wapi_handle_count_signalled_handles (numobjects
, handles
,
499 waitall
, count
, lowest
);
501 if (waitall
== TRUE
) {
502 for (i
= 0; i
< numobjects
; i
++) {
503 own_if_signalled (handles
[i
]);
506 own_if_signalled (handles
[*lowest
]);
511 g_message ("%s: unlocking handles", __func__
);
514 /* calls the unlock function */
515 pthread_cleanup_pop (1);
523 * WaitForMultipleObjectsEx:
524 * @numobjects: The number of objects in @handles. The maximum allowed
525 * is %MAXIMUM_WAIT_OBJECTS.
526 * @handles: An array of object handles. Duplicates are not allowed.
527 * @waitall: If %TRUE, this function waits until all of the handles
528 * are signalled. If %FALSE, this function returns when any object is
530 * @timeout: The maximum time in milliseconds to wait for.
531 * @alertable: if TRUE, the wait can be interrupted by an APC call
533 * This function returns when either one or more of @handles is
534 * signalled, or @timeout ms elapses. If @timeout is zero, the state
535 * of each item of @handles is tested and the function returns
536 * immediately. If @timeout is %INFINITE, the function waits forever.
538 * Return value: %WAIT_OBJECT_0 to %WAIT_OBJECT_0 + @numobjects - 1 -
539 * if @waitall is %TRUE, indicates that all objects are signalled. If
540 * @waitall is %FALSE, the return value minus %WAIT_OBJECT_0 indicates
541 * the first index into @handles of the objects that are signalled.
542 * %WAIT_ABANDONED_0 to %WAIT_ABANDONED_0 + @numobjects - 1 - if
543 * @waitall is %TRUE, indicates that all objects are signalled, and at
544 * least one object is an abandoned mutex object (See
545 * WaitForSingleObject() for a description of abandoned mutexes.) If
546 * @waitall is %FALSE, the return value minus %WAIT_ABANDONED_0
547 * indicates the first index into @handles of an abandoned mutex.
548 * %WAIT_TIMEOUT - The @timeout interval elapsed and no objects in
549 * @handles are signalled. %WAIT_FAILED - an error occurred.
550 * %WAIT_IO_COMPLETION - the wait was ended by an APC.
552 guint32
WaitForMultipleObjectsEx(guint32 numobjects
, gpointer
*handles
,
553 gboolean waitall
, guint32 timeout
,
557 gboolean duplicate
= FALSE
, bogustype
= FALSE
, done
;
558 guint32 count
, lowest
;
559 struct timespec abstime
;
563 gpointer current_thread
= _wapi_thread_handle_from_id (pthread_self ());
567 if (current_thread
== NULL
) {
568 SetLastError (ERROR_INVALID_HANDLE
);
572 if (numobjects
> MAXIMUM_WAIT_OBJECTS
) {
574 g_message ("%s: Too many handles: %d", __func__
, numobjects
);
580 if (numobjects
== 1) {
581 return WaitForSingleObjectEx (handles
[0], timeout
, alertable
);
584 /* Check for duplicates */
585 dups
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
586 for (i
= 0; i
< numobjects
; i
++) {
589 if (handles
[i
] == _WAPI_THREAD_CURRENT
) {
590 handles
[i
] = _wapi_thread_handle_from_id (pthread_self ());
592 if (handles
[i
] == NULL
) {
594 g_message ("%s: Handle %d bogus", __func__
, i
);
602 if ((GPOINTER_TO_UINT (handles
[i
]) & _WAPI_PROCESS_UNHANDLED
) == _WAPI_PROCESS_UNHANDLED
) {
604 g_message ("%s: Handle %d pseudo process", __func__
,
612 exists
= g_hash_table_lookup (dups
, handles
[i
]);
613 if (exists
!= NULL
) {
615 g_message ("%s: Handle %p duplicated", __func__
,
623 if (_wapi_handle_test_capabilities (handles
[i
], WAPI_HANDLE_CAP_WAIT
) == FALSE
) {
625 g_message ("%s: Handle %p can't be waited for",
626 __func__
, handles
[i
]);
633 g_hash_table_insert (dups
, handles
[i
], handles
[i
]);
634 _wapi_handle_ops_prewait (handles
[i
]);
636 g_hash_table_destroy (dups
);
638 if (duplicate
== TRUE
) {
640 g_message ("%s: Returning due to duplicates", __func__
);
646 if (bogustype
== TRUE
) {
648 g_message ("%s: Returning due to bogus type", __func__
);
655 for (i
= 0; i
< numobjects
; ++i
)
656 if (_wapi_handle_type (handles
[i
]) == WAPI_HANDLE_PROCESS
|| _WAPI_SHARED_HANDLE (_wapi_handle_type (handles
[i
])))
657 /* Can't wait for a process handle + another handle without polling */
660 done
= test_and_own (numobjects
, handles
, waitall
, &count
, &lowest
);
662 return(WAIT_OBJECT_0
+lowest
);
668 /* Have to wait for some or all handles to become signalled
671 if(timeout
!=INFINITE
) {
672 _wapi_calc_timeout (&abstime
, timeout
);
675 if (alertable
&& _wapi_thread_apc_pending (current_thread
)) {
676 _wapi_thread_dispatch_apc_queue (current_thread
);
677 return WAIT_IO_COMPLETION
;
680 for (i
= 0; i
< numobjects
; i
++) {
681 /* Add a reference, as we need to ensure the handle wont
682 * disappear from under us while we're waiting in the loop
683 * (not lock, as we don't want exclusive access here)
685 _wapi_handle_ref (handles
[i
]);
689 /* Prod all handles with prewait methods and
690 * special-wait handles that aren't already signalled
692 for (i
= 0; i
< numobjects
; i
++) {
693 _wapi_handle_ops_prewait (handles
[i
]);
695 if (_wapi_handle_test_capabilities (handles
[i
], WAPI_HANDLE_CAP_SPECIAL_WAIT
) == TRUE
&& _wapi_handle_issignalled (handles
[i
]) == FALSE
) {
696 _wapi_handle_ops_special_wait (handles
[i
], 0);
701 g_message ("%s: locking signal mutex", __func__
);
704 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_signal_mutex
, NULL
);
705 thr_ret
= _wapi_handle_lock_signal_mutex ();
706 g_assert (thr_ret
== 0);
708 /* Check the signalled state of handles inside the critical section */
711 for (i
= 0; i
< numobjects
; i
++)
712 if (!_wapi_handle_issignalled (handles
[i
]))
716 for (i
= 0; i
< numobjects
; i
++)
717 if (_wapi_handle_issignalled (handles
[i
]))
723 if (timeout
== INFINITE
) {
724 ret
= _wapi_handle_wait_signal (poll
);
726 ret
= _wapi_handle_timedwait_signal (&abstime
, poll
);
729 /* No need to wait */
734 g_message ("%s: unlocking signal mutex", __func__
);
737 thr_ret
= _wapi_handle_unlock_signal_mutex (NULL
);
738 g_assert (thr_ret
== 0);
739 pthread_cleanup_pop (0);
741 if (alertable
&& _wapi_thread_apc_pending (current_thread
)) {
742 _wapi_thread_dispatch_apc_queue (current_thread
);
743 retval
= WAIT_IO_COMPLETION
;
747 /* Check if everything is signalled, as we can't
748 * guarantee to notice a shared signal even if the
751 done
= test_and_own (numobjects
, handles
, waitall
,
754 retval
= WAIT_OBJECT_0
+lowest
;
756 } else if (ret
!= 0) {
757 /* Didn't get all handles, and there was a
758 * timeout or other error
761 g_message ("%s: wait returned error: %s", __func__
,
766 retval
= WAIT_TIMEOUT
;
768 retval
= WAIT_FAILED
;
774 for (i
= 0; i
< numobjects
; i
++) {
775 /* Unref everything we reffed above */
776 _wapi_handle_unref (handles
[i
]);
782 guint32
WaitForMultipleObjects(guint32 numobjects
, gpointer
*handles
,
783 gboolean waitall
, guint32 timeout
)
785 return WaitForMultipleObjectsEx(numobjects
, handles
, waitall
, timeout
, FALSE
);
790 * @handle: a handle to the process to wait for
791 * @timeout: the maximum time in milliseconds to wait for
793 * This function returns when either @handle process is waiting
794 * for input, or @timeout ms elapses. If @timeout is zero, the
795 * process state is tested and the function returns immediately.
796 * If @timeout is %INFINITE, the function waits forever.
798 * Return value: 0 - @handle process is waiting for input.
799 * %WAIT_TIMEOUT - The @timeout interval elapsed and
800 * @handle process is not waiting for input. %WAIT_FAILED - an error
803 guint32
WaitForInputIdle(gpointer handle
, guint32 timeout
)
805 /*TODO: Not implemented*/