2 * wait.c: wait for handles to become signalled
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002-2006 Novell, Inc.
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/mono-mutex.h>
19 #include <mono/io-layer/misc-private.h>
23 static gboolean own_if_signalled(gpointer handle)
27 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
28 if (_wapi_handle_trylock_shared_handles () == EBUSY) {
33 if (_wapi_handle_issignalled (handle)) {
34 _wapi_handle_ops_own (handle);
38 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
39 _wapi_handle_unlock_shared_handles ();
45 static gboolean own_if_owned(gpointer handle)
49 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
50 if (_wapi_handle_trylock_shared_handles () == EBUSY) {
55 if (_wapi_handle_ops_isowned (handle)) {
56 _wapi_handle_ops_own (handle);
60 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
61 _wapi_handle_unlock_shared_handles ();
68 * WaitForSingleObjectEx:
69 * @handle: an object to wait for
70 * @timeout: the maximum time in milliseconds to wait for
71 * @alertable: if TRUE, the wait can be interrupted by an APC call
73 * This function returns when either @handle is signalled, or @timeout
74 * ms elapses. If @timeout is zero, the object's state is tested and
75 * the function returns immediately. If @timeout is %INFINITE, the
76 * function waits forever.
78 * Return value: %WAIT_ABANDONED - @handle is a mutex that was not
79 * released by the owning thread when it exited. Ownership of the
80 * mutex object is granted to the calling thread and the mutex is set
81 * to nonsignalled. %WAIT_OBJECT_0 - The state of @handle is
82 * signalled. %WAIT_TIMEOUT - The @timeout interval elapsed and
83 * @handle's state is still not signalled. %WAIT_FAILED - an error
84 * occurred. %WAIT_IO_COMPLETION - the wait was ended by an APC.
86 guint32 WaitForSingleObjectEx(gpointer handle, guint32 timeout,
90 struct timespec abstime;
92 gboolean apc_pending = FALSE;
93 gpointer current_thread = _wapi_thread_handle_from_id (pthread_self ());
95 if (current_thread == NULL) {
96 SetLastError (ERROR_INVALID_HANDLE);
100 if (handle == _WAPI_THREAD_CURRENT) {
101 handle = _wapi_thread_handle_from_id (pthread_self ());
102 if (handle == NULL) {
103 SetLastError (ERROR_INVALID_HANDLE);
108 if ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
109 SetLastError (ERROR_INVALID_HANDLE);
113 if (_wapi_handle_test_capabilities (handle,
114 WAPI_HANDLE_CAP_WAIT) == FALSE) {
116 g_message ("%s: handle %p can't be waited for", __func__,
123 _wapi_handle_ops_prewait (handle);
125 if (_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE) {
127 g_message ("%s: handle %p has special wait", __func__, handle);
130 ret = _wapi_handle_ops_special_wait (handle, timeout);
132 if (alertable && _wapi_thread_apc_pending (current_thread)) {
134 ret = WAIT_IO_COMPLETION;
142 g_message ("%s: locking handle %p", __func__, handle);
145 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
147 thr_ret = _wapi_handle_lock_handle (handle);
148 g_assert (thr_ret == 0);
150 if (_wapi_handle_test_capabilities (handle,
151 WAPI_HANDLE_CAP_OWN) == TRUE) {
152 if (own_if_owned (handle) == TRUE) {
154 g_message ("%s: handle %p already owned", __func__,
162 if (alertable && _wapi_thread_apc_pending (current_thread)) {
164 ret = WAIT_IO_COMPLETION;
168 if (own_if_signalled (handle) == TRUE) {
170 g_message ("%s: handle %p already signalled", __func__,
182 /* Have to wait for it */
183 if (timeout != INFINITE) {
184 _wapi_calc_timeout (&abstime, timeout);
188 /* Check before waiting on the condition, just in case
190 _wapi_handle_ops_prewait (handle);
192 if (own_if_signalled (handle)) {
194 g_message ("%s: handle %p signalled", __func__,
202 if (timeout == INFINITE) {
203 waited = _wapi_handle_wait_signal_handle (handle, alertable);
205 waited = _wapi_handle_timedwait_signal_handle (handle, &abstime, alertable, FALSE);
209 apc_pending = _wapi_thread_apc_pending (current_thread);
211 if(waited==0 && !apc_pending) {
212 /* Condition was signalled, so hopefully
213 * handle is signalled now. (It might not be
214 * if someone else got in before us.)
216 if (own_if_signalled (handle)) {
218 g_message ("%s: handle %p signalled", __func__,
226 /* Better luck next time */
228 } while(waited == 0 && !apc_pending);
230 /* Timeout or other error */
232 g_message ("%s: wait on handle %p error: %s", __func__, handle,
241 g_message ("%s: unlocking handle %p", __func__, handle);
244 thr_ret = _wapi_handle_unlock_handle (handle);
245 g_assert (thr_ret == 0);
246 pthread_cleanup_pop (0);
250 _wapi_thread_dispatch_apc_queue (current_thread);
251 ret = WAIT_IO_COMPLETION;
257 guint32 WaitForSingleObject(gpointer handle, guint32 timeout)
259 return WaitForSingleObjectEx (handle, timeout, FALSE);
264 * SignalObjectAndWait:
265 * @signal_handle: An object to signal
266 * @wait: An object to wait for
267 * @timeout: The maximum time in milliseconds to wait for
268 * @alertable: Specifies whether the function returnes when the system
269 * queues an I/O completion routine or an APC for the calling thread.
271 * Atomically signals @signal and waits for @wait to become signalled,
272 * or @timeout ms elapses. If @timeout is zero, the object's state is
273 * tested and the function returns immediately. If @timeout is
274 * %INFINITE, the function waits forever.
276 * @signal can be a semaphore, mutex or event object.
278 * If @alertable is %TRUE and the system queues an I/O completion
279 * routine or an APC for the calling thread, the function returns and
280 * the thread calls the completion routine or APC function. If
281 * %FALSE, the function does not return, and the thread does not call
282 * the completion routine or APC function. A completion routine is
283 * queued when the ReadFileEx() or WriteFileEx() function in which it
284 * was specified has completed. The calling thread is the thread that
285 * initiated the read or write operation. An APC is queued when
286 * QueueUserAPC() is called. Currently completion routines and APC
287 * functions are not supported.
289 * Return value: %WAIT_ABANDONED - @wait is a mutex that was not
290 * released by the owning thread when it exited. Ownershop of the
291 * mutex object is granted to the calling thread and the mutex is set
292 * to nonsignalled. %WAIT_IO_COMPLETION - the wait was ended by one
293 * or more user-mode asynchronous procedure calls queued to the
294 * thread. %WAIT_OBJECT_0 - The state of @wait is signalled.
295 * %WAIT_TIMEOUT - The @timeout interval elapsed and @wait's state is
296 * still not signalled. %WAIT_FAILED - an error occurred.
298 guint32 SignalObjectAndWait(gpointer signal_handle, gpointer wait,
299 guint32 timeout, gboolean alertable)
302 struct timespec abstime;
304 gboolean apc_pending = FALSE;
305 gpointer current_thread = _wapi_thread_handle_from_id (pthread_self ());
307 if (current_thread == NULL) {
308 SetLastError (ERROR_INVALID_HANDLE);
312 if (signal_handle == _WAPI_THREAD_CURRENT) {
313 signal_handle = _wapi_thread_handle_from_id (pthread_self ());
314 if (signal_handle == NULL) {
315 SetLastError (ERROR_INVALID_HANDLE);
320 if (wait == _WAPI_THREAD_CURRENT) {
321 wait = _wapi_thread_handle_from_id (pthread_self ());
323 SetLastError (ERROR_INVALID_HANDLE);
328 if ((GPOINTER_TO_UINT (signal_handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
329 SetLastError (ERROR_INVALID_HANDLE);
333 if ((GPOINTER_TO_UINT (wait) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
334 SetLastError (ERROR_INVALID_HANDLE);
338 if (_wapi_handle_test_capabilities (signal_handle,
339 WAPI_HANDLE_CAP_SIGNAL)==FALSE) {
343 if (_wapi_handle_test_capabilities (wait,
344 WAPI_HANDLE_CAP_WAIT)==FALSE) {
348 _wapi_handle_ops_prewait (wait);
350 if (_wapi_handle_test_capabilities (wait, WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE) {
351 g_warning ("%s: handle %p has special wait, implement me!!",
354 return (WAIT_FAILED);
358 g_message ("%s: locking handle %p", __func__, wait);
361 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
363 thr_ret = _wapi_handle_lock_handle (wait);
364 g_assert (thr_ret == 0);
366 _wapi_handle_ops_signal (signal_handle);
368 if (_wapi_handle_test_capabilities (wait, WAPI_HANDLE_CAP_OWN)==TRUE) {
369 if (own_if_owned (wait)) {
371 g_message ("%s: handle %p already owned", __func__,
379 if (alertable && _wapi_thread_apc_pending (current_thread)) {
381 ret = WAIT_IO_COMPLETION;
385 if (own_if_signalled (wait)) {
387 g_message ("%s: handle %p already signalled", __func__, wait);
394 /* Have to wait for it */
395 if (timeout != INFINITE) {
396 _wapi_calc_timeout (&abstime, timeout);
400 /* Check before waiting on the condition, just in case
402 _wapi_handle_ops_prewait (wait);
404 if (own_if_signalled (wait)) {
406 g_message ("%s: handle %p signalled", __func__, wait);
413 if (timeout == INFINITE) {
414 waited = _wapi_handle_wait_signal_handle (wait, alertable);
416 waited = _wapi_handle_timedwait_signal_handle (wait, &abstime, alertable, FALSE);
420 apc_pending = _wapi_thread_apc_pending (current_thread);
423 if (waited==0 && !apc_pending) {
424 /* Condition was signalled, so hopefully
425 * handle is signalled now. (It might not be
426 * if someone else got in before us.)
428 if (own_if_signalled (wait)) {
430 g_message ("%s: handle %p signalled", __func__,
438 /* Better luck next time */
440 } while(waited == 0 && !apc_pending);
442 /* Timeout or other error */
444 g_message ("%s: wait on handle %p error: %s", __func__, wait,
453 g_message ("%s: unlocking handle %p", __func__, wait);
456 thr_ret = _wapi_handle_unlock_handle (wait);
457 g_assert (thr_ret == 0);
458 pthread_cleanup_pop (0);
461 _wapi_thread_dispatch_apc_queue (current_thread);
462 ret = WAIT_IO_COMPLETION;
468 struct handle_cleanup_data
474 static void handle_cleanup (void *data)
476 struct handle_cleanup_data *handles = (struct handle_cleanup_data *)data;
478 _wapi_handle_unlock_handles (handles->numobjects, handles->handles);
481 static gboolean test_and_own (guint32 numobjects, gpointer *handles,
482 gboolean waitall, guint32 *count,
485 struct handle_cleanup_data cleanup_data;
490 g_message ("%s: locking handles", __func__);
492 cleanup_data.numobjects = numobjects;
493 cleanup_data.handles = handles;
495 pthread_cleanup_push (handle_cleanup, (void *)&cleanup_data);
496 done = _wapi_handle_count_signalled_handles (numobjects, handles,
497 waitall, count, lowest);
499 if (waitall == TRUE) {
500 for (i = 0; i < numobjects; i++) {
501 own_if_signalled (handles[i]);
504 own_if_signalled (handles[*lowest]);
509 g_message ("%s: unlocking handles", __func__);
512 /* calls the unlock function */
513 pthread_cleanup_pop (1);
519 * WaitForMultipleObjectsEx:
520 * @numobjects: The number of objects in @handles. The maximum allowed
521 * is %MAXIMUM_WAIT_OBJECTS.
522 * @handles: An array of object handles. Duplicates are not allowed.
523 * @waitall: If %TRUE, this function waits until all of the handles
524 * are signalled. If %FALSE, this function returns when any object is
526 * @timeout: The maximum time in milliseconds to wait for.
527 * @alertable: if TRUE, the wait can be interrupted by an APC call
529 * This function returns when either one or more of @handles is
530 * signalled, or @timeout ms elapses. If @timeout is zero, the state
531 * of each item of @handles is tested and the function returns
532 * immediately. If @timeout is %INFINITE, the function waits forever.
534 * Return value: %WAIT_OBJECT_0 to %WAIT_OBJECT_0 + @numobjects - 1 -
535 * if @waitall is %TRUE, indicates that all objects are signalled. If
536 * @waitall is %FALSE, the return value minus %WAIT_OBJECT_0 indicates
537 * the first index into @handles of the objects that are signalled.
538 * %WAIT_ABANDONED_0 to %WAIT_ABANDONED_0 + @numobjects - 1 - if
539 * @waitall is %TRUE, indicates that all objects are signalled, and at
540 * least one object is an abandoned mutex object (See
541 * WaitForSingleObject() for a description of abandoned mutexes.) If
542 * @waitall is %FALSE, the return value minus %WAIT_ABANDONED_0
543 * indicates the first index into @handles of an abandoned mutex.
544 * %WAIT_TIMEOUT - The @timeout interval elapsed and no objects in
545 * @handles are signalled. %WAIT_FAILED - an error occurred.
546 * %WAIT_IO_COMPLETION - the wait was ended by an APC.
548 guint32 WaitForMultipleObjectsEx(guint32 numobjects, gpointer *handles,
549 gboolean waitall, guint32 timeout,
552 gboolean duplicate = FALSE, bogustype = FALSE, done;
553 guint32 count, lowest;
554 struct timespec abstime;
558 gpointer current_thread = _wapi_thread_handle_from_id (pthread_self ());
561 gpointer sorted_handles [MAXIMUM_WAIT_OBJECTS];
563 if (current_thread == NULL) {
564 SetLastError (ERROR_INVALID_HANDLE);
568 if (numobjects > MAXIMUM_WAIT_OBJECTS) {
570 g_message ("%s: Too many handles: %d", __func__, numobjects);
576 if (numobjects == 1) {
577 return WaitForSingleObjectEx (handles [0], timeout, alertable);
580 /* Check for duplicates */
581 for (i = 0; i < numobjects; i++) {
582 if (handles[i] == _WAPI_THREAD_CURRENT) {
583 handles[i] = _wapi_thread_handle_from_id (pthread_self ());
585 if (handles[i] == NULL) {
587 g_message ("%s: Handle %d bogus", __func__, i);
595 if ((GPOINTER_TO_UINT (handles[i]) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
597 g_message ("%s: Handle %d pseudo process", __func__,
605 if (_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_WAIT) == FALSE) {
607 g_message ("%s: Handle %p can't be waited for",
608 __func__, handles[i]);
615 sorted_handles [i] = handles [i];
616 _wapi_handle_ops_prewait (handles[i]);
619 qsort (sorted_handles, numobjects, sizeof (gpointer), g_direct_equal);
620 for (i = 1; i < numobjects; i++) {
621 if (sorted_handles [i - 1] == sorted_handles [i]) {
627 if (duplicate == TRUE) {
629 g_message ("%s: Returning due to duplicates", __func__);
635 if (bogustype == TRUE) {
637 g_message ("%s: Returning due to bogus type", __func__);
644 for (i = 0; i < numobjects; ++i)
645 if (_wapi_handle_type (handles [i]) == WAPI_HANDLE_PROCESS || _WAPI_SHARED_HANDLE (_wapi_handle_type (handles[i])))
646 /* Can't wait for a process handle + another handle without polling */
649 done = test_and_own (numobjects, handles, waitall, &count, &lowest);
651 return(WAIT_OBJECT_0+lowest);
657 /* Have to wait for some or all handles to become signalled
660 if(timeout!=INFINITE) {
661 _wapi_calc_timeout (&abstime, timeout);
664 if (alertable && _wapi_thread_apc_pending (current_thread)) {
665 _wapi_thread_dispatch_apc_queue (current_thread);
666 return WAIT_IO_COMPLETION;
669 for (i = 0; i < numobjects; i++) {
670 /* Add a reference, as we need to ensure the handle wont
671 * disappear from under us while we're waiting in the loop
672 * (not lock, as we don't want exclusive access here)
674 _wapi_handle_ref (handles[i]);
678 /* Prod all handles with prewait methods and
679 * special-wait handles that aren't already signalled
681 for (i = 0; i < numobjects; i++) {
682 _wapi_handle_ops_prewait (handles[i]);
684 if (_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE && _wapi_handle_issignalled (handles[i]) == FALSE) {
685 _wapi_handle_ops_special_wait (handles[i], 0);
690 g_message ("%s: locking signal mutex", __func__);
693 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_signal_mutex, NULL);
694 thr_ret = _wapi_handle_lock_signal_mutex ();
695 g_assert (thr_ret == 0);
697 /* Check the signalled state of handles inside the critical section */
700 for (i = 0; i < numobjects; i++)
701 if (!_wapi_handle_issignalled (handles [i]))
705 for (i = 0; i < numobjects; i++)
706 if (_wapi_handle_issignalled (handles [i]))
712 if (timeout == INFINITE) {
713 ret = _wapi_handle_wait_signal (poll);
715 ret = _wapi_handle_timedwait_signal (&abstime, poll);
718 /* No need to wait */
723 g_message ("%s: unlocking signal mutex", __func__);
726 thr_ret = _wapi_handle_unlock_signal_mutex (NULL);
727 g_assert (thr_ret == 0);
728 pthread_cleanup_pop (0);
730 if (alertable && _wapi_thread_apc_pending (current_thread)) {
731 _wapi_thread_dispatch_apc_queue (current_thread);
732 retval = WAIT_IO_COMPLETION;
736 /* Check if everything is signalled, as we can't
737 * guarantee to notice a shared signal even if the
740 done = test_and_own (numobjects, handles, waitall,
743 retval = WAIT_OBJECT_0+lowest;
745 } else if (ret != 0) {
746 /* Didn't get all handles, and there was a
747 * timeout or other error
750 g_message ("%s: wait returned error: %s", __func__,
755 retval = WAIT_TIMEOUT;
757 retval = WAIT_FAILED;
763 for (i = 0; i < numobjects; i++) {
764 /* Unref everything we reffed above */
765 _wapi_handle_unref (handles[i]);
771 guint32 WaitForMultipleObjects(guint32 numobjects, gpointer *handles,
772 gboolean waitall, guint32 timeout)
774 return WaitForMultipleObjectsEx(numobjects, handles, waitall, timeout, FALSE);
779 * @handle: a handle to the process to wait for
780 * @timeout: the maximum time in milliseconds to wait for
782 * This function returns when either @handle process is waiting
783 * for input, or @timeout ms elapses. If @timeout is zero, the
784 * process state is tested and the function returns immediately.
785 * If @timeout is %INFINITE, the function waits forever.
787 * Return value: 0 - @handle process is waiting for input.
788 * %WAIT_TIMEOUT - The @timeout interval elapsed and
789 * @handle process is not waiting for input. %WAIT_FAILED - an error
792 guint32 WaitForInputIdle(gpointer handle, guint32 timeout)
794 /*TODO: Not implemented*/