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/misc-private.h>
20 #include <mono/utils/mono-mutex.h>
23 #define DEBUG(...) g_message(__VA_ARGS__)
28 static gboolean own_if_signalled(gpointer handle)
32 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
33 if (_wapi_handle_trylock_shared_handles () == EBUSY) {
38 if (_wapi_handle_issignalled (handle)) {
39 _wapi_handle_ops_own (handle);
43 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
44 _wapi_handle_unlock_shared_handles ();
50 static gboolean own_if_owned(gpointer handle)
54 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
55 if (_wapi_handle_trylock_shared_handles () == EBUSY) {
60 if (_wapi_handle_ops_isowned (handle)) {
61 _wapi_handle_ops_own (handle);
65 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
66 _wapi_handle_unlock_shared_handles ();
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,
95 struct timespec abstime;
97 gboolean apc_pending = FALSE;
98 gpointer current_thread = wapi_get_current_thread_handle ();
100 if (current_thread == NULL) {
101 SetLastError (ERROR_INVALID_HANDLE);
105 if (handle == _WAPI_THREAD_CURRENT) {
106 handle = wapi_get_current_thread_handle ();
107 if (handle == NULL) {
108 SetLastError (ERROR_INVALID_HANDLE);
113 if ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
114 SetLastError (ERROR_INVALID_HANDLE);
118 if (_wapi_handle_test_capabilities (handle,
119 WAPI_HANDLE_CAP_WAIT) == FALSE) {
120 DEBUG ("%s: handle %p can't be waited for", __func__,
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_cur_apc_pending ())
134 ret = WAIT_IO_COMPLETION;
140 DEBUG ("%s: locking handle %p", __func__, handle);
142 thr_ret = _wapi_handle_lock_handle (handle);
143 g_assert (thr_ret == 0);
145 if (_wapi_handle_test_capabilities (handle,
146 WAPI_HANDLE_CAP_OWN) == TRUE) {
147 if (own_if_owned (handle) == TRUE) {
148 DEBUG ("%s: handle %p already owned", __func__,
155 if (own_if_signalled (handle) == TRUE) {
156 DEBUG ("%s: handle %p already signalled", __func__,
167 /* Have to wait for it */
168 if (timeout != INFINITE) {
169 _wapi_calc_timeout (&abstime, timeout);
173 /* Check before waiting on the condition, just in case
175 _wapi_handle_ops_prewait (handle);
177 if (own_if_signalled (handle)) {
178 DEBUG ("%s: handle %p signalled", __func__,
185 waited = _wapi_handle_timedwait_signal_handle (handle, timeout == INFINITE ? NULL : &abstime, alertable, FALSE, &apc_pending);
187 if(waited==0 && !apc_pending) {
188 /* Condition was signalled, so hopefully
189 * handle is signalled now. (It might not be
190 * if someone else got in before us.)
192 if (own_if_signalled (handle)) {
193 DEBUG ("%s: handle %p signalled", __func__,
200 /* Better luck next time */
202 } while(waited == 0 && !apc_pending);
204 /* Timeout or other error */
205 DEBUG ("%s: wait on handle %p error: %s", __func__, handle,
208 ret = apc_pending ? WAIT_IO_COMPLETION : WAIT_TIMEOUT;
212 DEBUG ("%s: unlocking handle %p", __func__, handle);
214 thr_ret = _wapi_handle_unlock_handle (handle);
215 g_assert (thr_ret == 0);
220 guint32 WaitForSingleObject(gpointer handle, guint32 timeout)
222 return WaitForSingleObjectEx (handle, timeout, FALSE);
227 * SignalObjectAndWait:
228 * @signal_handle: An object to signal
229 * @wait: An object to wait for
230 * @timeout: The maximum time in milliseconds to wait for
231 * @alertable: Specifies whether the function returnes when the system
232 * queues an I/O completion routine or an APC for the calling thread.
234 * Atomically signals @signal and waits for @wait to become signalled,
235 * or @timeout ms elapses. If @timeout is zero, the object's state is
236 * tested and the function returns immediately. If @timeout is
237 * %INFINITE, the function waits forever.
239 * @signal can be a semaphore, mutex or event object.
241 * If @alertable is %TRUE and the system queues an I/O completion
242 * routine or an APC for the calling thread, the function returns and
243 * the thread calls the completion routine or APC function. If
244 * %FALSE, the function does not return, and the thread does not call
245 * the completion routine or APC function. A completion routine is
246 * queued when the ReadFileEx() or WriteFileEx() function in which it
247 * was specified has completed. The calling thread is the thread that
248 * initiated the read or write operation. An APC is queued when
249 * QueueUserAPC() is called. Currently completion routines and APC
250 * functions are not supported.
252 * Return value: %WAIT_ABANDONED - @wait is a mutex that was not
253 * released by the owning thread when it exited. Ownershop of the
254 * mutex object is granted to the calling thread and the mutex is set
255 * to nonsignalled. %WAIT_IO_COMPLETION - the wait was ended by one
256 * or more user-mode asynchronous procedure calls queued to the
257 * thread. %WAIT_OBJECT_0 - The state of @wait is signalled.
258 * %WAIT_TIMEOUT - The @timeout interval elapsed and @wait's state is
259 * still not signalled. %WAIT_FAILED - an error occurred.
261 guint32 SignalObjectAndWait(gpointer signal_handle, gpointer wait,
262 guint32 timeout, gboolean alertable)
265 struct timespec abstime;
267 gboolean apc_pending = FALSE;
268 gpointer current_thread = wapi_get_current_thread_handle ();
270 if (current_thread == NULL) {
271 SetLastError (ERROR_INVALID_HANDLE);
275 if (signal_handle == _WAPI_THREAD_CURRENT) {
276 signal_handle = wapi_get_current_thread_handle ();
277 if (signal_handle == NULL) {
278 SetLastError (ERROR_INVALID_HANDLE);
283 if (wait == _WAPI_THREAD_CURRENT) {
284 wait = wapi_get_current_thread_handle ();
286 SetLastError (ERROR_INVALID_HANDLE);
291 if ((GPOINTER_TO_UINT (signal_handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
292 SetLastError (ERROR_INVALID_HANDLE);
296 if ((GPOINTER_TO_UINT (wait) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
297 SetLastError (ERROR_INVALID_HANDLE);
301 if (_wapi_handle_test_capabilities (signal_handle,
302 WAPI_HANDLE_CAP_SIGNAL)==FALSE) {
306 if (_wapi_handle_test_capabilities (wait,
307 WAPI_HANDLE_CAP_WAIT)==FALSE) {
311 _wapi_handle_ops_prewait (wait);
313 if (_wapi_handle_test_capabilities (wait, WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE) {
314 g_warning ("%s: handle %p has special wait, implement me!!",
317 return (WAIT_FAILED);
320 DEBUG ("%s: locking handle %p", __func__, wait);
322 thr_ret = _wapi_handle_lock_handle (wait);
323 g_assert (thr_ret == 0);
325 _wapi_handle_ops_signal (signal_handle);
327 if (_wapi_handle_test_capabilities (wait, WAPI_HANDLE_CAP_OWN)==TRUE) {
328 if (own_if_owned (wait)) {
329 DEBUG ("%s: handle %p already owned", __func__,
336 if (own_if_signalled (wait)) {
337 DEBUG ("%s: handle %p already signalled", __func__, wait);
343 /* Have to wait for it */
344 if (timeout != INFINITE) {
345 _wapi_calc_timeout (&abstime, timeout);
349 /* Check before waiting on the condition, just in case
351 _wapi_handle_ops_prewait (wait);
353 if (own_if_signalled (wait)) {
354 DEBUG ("%s: handle %p signalled", __func__, wait);
360 waited = _wapi_handle_timedwait_signal_handle (wait, timeout == INFINITE ? NULL : &abstime, alertable, FALSE, &apc_pending);
362 if (waited==0 && !apc_pending) {
363 /* Condition was signalled, so hopefully
364 * handle is signalled now. (It might not be
365 * if someone else got in before us.)
367 if (own_if_signalled (wait)) {
368 DEBUG ("%s: handle %p signalled", __func__,
375 /* Better luck next time */
377 } while(waited == 0 && !apc_pending);
379 /* Timeout or other error */
380 DEBUG ("%s: wait on handle %p error: %s", __func__, wait,
383 ret = apc_pending ? WAIT_IO_COMPLETION : WAIT_TIMEOUT;
387 DEBUG ("%s: unlocking handle %p", __func__, wait);
389 thr_ret = _wapi_handle_unlock_handle (wait);
390 g_assert (thr_ret == 0);
395 static gboolean test_and_own (guint32 numobjects, gpointer *handles,
396 gboolean waitall, guint32 *count,
402 DEBUG ("%s: locking handles", __func__);
404 done = _wapi_handle_count_signalled_handles (numobjects, handles,
405 waitall, count, lowest);
407 if (waitall == TRUE) {
408 for (i = 0; i < numobjects; i++) {
409 own_if_signalled (handles[i]);
412 own_if_signalled (handles[*lowest]);
416 DEBUG ("%s: unlocking handles", __func__);
418 _wapi_handle_unlock_handles (numobjects, handles);
424 * WaitForMultipleObjectsEx:
425 * @numobjects: The number of objects in @handles. The maximum allowed
426 * is %MAXIMUM_WAIT_OBJECTS.
427 * @handles: An array of object handles. Duplicates are not allowed.
428 * @waitall: If %TRUE, this function waits until all of the handles
429 * are signalled. If %FALSE, this function returns when any object is
431 * @timeout: The maximum time in milliseconds to wait for.
432 * @alertable: if TRUE, the wait can be interrupted by an APC call
434 * This function returns when either one or more of @handles is
435 * signalled, or @timeout ms elapses. If @timeout is zero, the state
436 * of each item of @handles is tested and the function returns
437 * immediately. If @timeout is %INFINITE, the function waits forever.
439 * Return value: %WAIT_OBJECT_0 to %WAIT_OBJECT_0 + @numobjects - 1 -
440 * if @waitall is %TRUE, indicates that all objects are signalled. If
441 * @waitall is %FALSE, the return value minus %WAIT_OBJECT_0 indicates
442 * the first index into @handles of the objects that are signalled.
443 * %WAIT_ABANDONED_0 to %WAIT_ABANDONED_0 + @numobjects - 1 - if
444 * @waitall is %TRUE, indicates that all objects are signalled, and at
445 * least one object is an abandoned mutex object (See
446 * WaitForSingleObject() for a description of abandoned mutexes.) If
447 * @waitall is %FALSE, the return value minus %WAIT_ABANDONED_0
448 * indicates the first index into @handles of an abandoned mutex.
449 * %WAIT_TIMEOUT - The @timeout interval elapsed and no objects in
450 * @handles are signalled. %WAIT_FAILED - an error occurred.
451 * %WAIT_IO_COMPLETION - the wait was ended by an APC.
453 guint32 WaitForMultipleObjectsEx(guint32 numobjects, gpointer *handles,
454 gboolean waitall, guint32 timeout,
457 gboolean duplicate = FALSE, bogustype = FALSE, done;
458 guint32 count, lowest;
459 struct timespec abstime;
463 gpointer current_thread = wapi_get_current_thread_handle ();
466 gpointer sorted_handles [MAXIMUM_WAIT_OBJECTS];
467 gboolean apc_pending = FALSE;
469 if (current_thread == NULL) {
470 SetLastError (ERROR_INVALID_HANDLE);
474 if (numobjects > MAXIMUM_WAIT_OBJECTS) {
475 DEBUG ("%s: Too many handles: %d", __func__, numobjects);
480 if (numobjects == 1) {
481 return WaitForSingleObjectEx (handles [0], timeout, alertable);
484 /* Check for duplicates */
485 for (i = 0; i < numobjects; i++) {
486 if (handles[i] == _WAPI_THREAD_CURRENT) {
487 handles[i] = wapi_get_current_thread_handle ();
489 if (handles[i] == NULL) {
490 DEBUG ("%s: Handle %d bogus", __func__, i);
497 if ((GPOINTER_TO_UINT (handles[i]) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
498 DEBUG ("%s: Handle %d pseudo process", __func__,
505 if (_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_WAIT) == FALSE) {
506 DEBUG ("%s: Handle %p can't be waited for",
507 __func__, handles[i]);
513 sorted_handles [i] = handles [i];
514 _wapi_handle_ops_prewait (handles[i]);
517 qsort (sorted_handles, numobjects, sizeof (gpointer), g_direct_equal);
518 for (i = 1; i < numobjects; i++) {
519 if (sorted_handles [i - 1] == sorted_handles [i]) {
525 if (duplicate == TRUE) {
526 DEBUG ("%s: Returning due to duplicates", __func__);
531 if (bogustype == TRUE) {
532 DEBUG ("%s: Returning due to bogus type", __func__);
538 for (i = 0; i < numobjects; ++i)
539 if (_wapi_handle_type (handles [i]) == WAPI_HANDLE_PROCESS || _WAPI_SHARED_HANDLE (_wapi_handle_type (handles[i])))
540 /* Can't wait for a process handle + another handle without polling */
543 done = test_and_own (numobjects, handles, waitall, &count, &lowest);
545 return(WAIT_OBJECT_0+lowest);
551 /* Have to wait for some or all handles to become signalled
554 if(timeout!=INFINITE) {
555 _wapi_calc_timeout (&abstime, timeout);
558 for (i = 0; i < numobjects; i++) {
559 /* Add a reference, as we need to ensure the handle wont
560 * disappear from under us while we're waiting in the loop
561 * (not lock, as we don't want exclusive access here)
563 _wapi_handle_ref (handles[i]);
567 /* Prod all handles with prewait methods and
568 * special-wait handles that aren't already signalled
570 for (i = 0; i < numobjects; i++) {
571 _wapi_handle_ops_prewait (handles[i]);
573 if (_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE && _wapi_handle_issignalled (handles[i]) == FALSE) {
574 _wapi_handle_ops_special_wait (handles[i], 0, alertable);
578 DEBUG ("%s: locking signal mutex", __func__);
580 thr_ret = _wapi_handle_lock_signal_mutex ();
581 g_assert (thr_ret == 0);
583 /* Check the signalled state of handles inside the critical section */
586 for (i = 0; i < numobjects; i++)
587 if (!_wapi_handle_issignalled (handles [i]))
591 for (i = 0; i < numobjects; i++)
592 if (_wapi_handle_issignalled (handles [i]))
598 ret = _wapi_handle_timedwait_signal (timeout == INFINITE ? NULL : &abstime, poll, &apc_pending);
600 /* No need to wait */
604 DEBUG ("%s: unlocking signal mutex", __func__);
606 thr_ret = _wapi_handle_unlock_signal_mutex (NULL);
607 g_assert (thr_ret == 0);
609 if (alertable && apc_pending) {
610 retval = WAIT_IO_COMPLETION;
614 /* Check if everything is signalled, as we can't
615 * guarantee to notice a shared signal even if the
618 done = test_and_own (numobjects, handles, waitall,
621 retval = WAIT_OBJECT_0+lowest;
623 } else if (ret != 0) {
624 /* Didn't get all handles, and there was a
625 * timeout or other error
627 DEBUG ("%s: wait returned error: %s", __func__,
631 retval = WAIT_TIMEOUT;
633 retval = WAIT_FAILED;
639 for (i = 0; i < numobjects; i++) {
640 /* Unref everything we reffed above */
641 _wapi_handle_unref (handles[i]);
647 guint32 WaitForMultipleObjects(guint32 numobjects, gpointer *handles,
648 gboolean waitall, guint32 timeout)
650 return WaitForMultipleObjectsEx(numobjects, handles, waitall, timeout, FALSE);
655 * @handle: a handle to the process to wait for
656 * @timeout: the maximum time in milliseconds to wait for
658 * This function returns when either @handle process is waiting
659 * for input, or @timeout ms elapses. If @timeout is zero, the
660 * process state is tested and the function returns immediately.
661 * If @timeout is %INFINITE, the function waits forever.
663 * Return value: 0 - @handle process is waiting for input.
664 * %WAIT_TIMEOUT - The @timeout interval elapsed and
665 * @handle process is not waiting for input. %WAIT_FAILED - an error
668 guint32 WaitForInputIdle(gpointer handle, guint32 timeout)
670 /*TODO: Not implemented*/