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/io-trace.h>
19 #include <mono/utils/mono-logger-internals.h>
20 #include <mono/utils/mono-time.h>
22 static gboolean own_if_signalled(gpointer handle)
26 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
27 if (_wapi_handle_trylock_shared_handles () == EBUSY) {
32 if (_wapi_handle_issignalled (handle)) {
33 _wapi_handle_ops_own (handle);
37 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
38 _wapi_handle_unlock_shared_handles ();
44 static gboolean own_if_owned(gpointer handle)
48 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
49 if (_wapi_handle_trylock_shared_handles () == EBUSY) {
54 if (_wapi_handle_ops_isowned (handle)) {
55 _wapi_handle_ops_own (handle);
59 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
60 _wapi_handle_unlock_shared_handles ();
67 * WaitForSingleObjectEx:
68 * @handle: an object to wait for
69 * @timeout: the maximum time in milliseconds to wait for
70 * @alertable: if TRUE, the wait can be interrupted by an APC call
72 * This function returns when either @handle is signalled, or @timeout
73 * ms elapses. If @timeout is zero, the object's state is tested and
74 * the function returns immediately. If @timeout is %INFINITE, the
75 * function waits forever.
77 * Return value: %WAIT_ABANDONED - @handle is a mutex that was not
78 * released by the owning thread when it exited. Ownership of the
79 * mutex object is granted to the calling thread and the mutex is set
80 * to nonsignalled. %WAIT_OBJECT_0 - The state of @handle is
81 * signalled. %WAIT_TIMEOUT - The @timeout interval elapsed and
82 * @handle's state is still not signalled. %WAIT_FAILED - an error
83 * occurred. %WAIT_IO_COMPLETION - the wait was ended by an APC.
85 guint32 WaitForSingleObjectEx(gpointer handle, guint32 timeout,
90 gboolean apc_pending = FALSE;
91 gpointer current_thread = wapi_get_current_thread_handle ();
94 if (current_thread == NULL) {
95 SetLastError (ERROR_INVALID_HANDLE);
99 if (handle == _WAPI_THREAD_CURRENT) {
100 handle = wapi_get_current_thread_handle ();
101 if (handle == NULL) {
102 SetLastError (ERROR_INVALID_HANDLE);
107 if ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
108 SetLastError (ERROR_INVALID_HANDLE);
112 if (_wapi_handle_test_capabilities (handle,
113 WAPI_HANDLE_CAP_WAIT) == FALSE) {
114 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p can't be waited for", __func__,
120 _wapi_handle_ops_prewait (handle);
122 if (_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE) {
123 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p has special wait", __func__, handle);
125 ret = _wapi_handle_ops_special_wait (handle, timeout, alertable);
127 if (alertable && _wapi_thread_cur_apc_pending ())
128 ret = WAIT_IO_COMPLETION;
134 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: locking handle %p", __func__, handle);
136 thr_ret = _wapi_handle_lock_handle (handle);
137 g_assert (thr_ret == 0);
139 if (_wapi_handle_test_capabilities (handle,
140 WAPI_HANDLE_CAP_OWN) == TRUE) {
141 if (own_if_owned (handle) == TRUE) {
142 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p already owned", __func__,
149 if (own_if_signalled (handle) == TRUE) {
150 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p already signalled", __func__,
162 if (timeout != INFINITE)
163 end = mono_100ns_ticks () + timeout * 1000 * 10;
166 /* Check before waiting on the condition, just in case
168 _wapi_handle_ops_prewait (handle);
170 if (own_if_signalled (handle)) {
171 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p signalled", __func__,
178 if (timeout == INFINITE) {
179 waited = _wapi_handle_timedwait_signal_handle (handle, INFINITE, alertable, FALSE, &apc_pending);
181 now = mono_100ns_ticks ();
187 waited = _wapi_handle_timedwait_signal_handle (handle, (end - now) / 10 / 1000, alertable, FALSE, &apc_pending);
190 if(waited==0 && !apc_pending) {
191 /* Condition was signalled, so hopefully
192 * handle is signalled now. (It might not be
193 * if someone else got in before us.)
195 if (own_if_signalled (handle)) {
196 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p signalled", __func__,
203 /* Better luck next time */
205 } while(waited == 0 && !apc_pending);
207 /* Timeout or other error */
208 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: wait on handle %p error: %s", __func__, handle,
211 ret = apc_pending ? WAIT_IO_COMPLETION : WAIT_TIMEOUT;
215 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking handle %p", __func__, handle);
217 thr_ret = _wapi_handle_unlock_handle (handle);
218 g_assert (thr_ret == 0);
223 guint32 WaitForSingleObject(gpointer handle, guint32 timeout)
225 return WaitForSingleObjectEx (handle, timeout, FALSE);
230 * SignalObjectAndWait:
231 * @signal_handle: An object to signal
232 * @wait: An object to wait for
233 * @timeout: The maximum time in milliseconds to wait for
234 * @alertable: Specifies whether the function returnes when the system
235 * queues an I/O completion routine or an APC for the calling thread.
237 * Atomically signals @signal and waits for @wait to become signalled,
238 * or @timeout ms elapses. If @timeout is zero, the object's state is
239 * tested and the function returns immediately. If @timeout is
240 * %INFINITE, the function waits forever.
242 * @signal can be a semaphore, mutex or event object.
244 * If @alertable is %TRUE and the system queues an I/O completion
245 * routine or an APC for the calling thread, the function returns and
246 * the thread calls the completion routine or APC function. If
247 * %FALSE, the function does not return, and the thread does not call
248 * the completion routine or APC function. A completion routine is
249 * queued when the ReadFileEx() or WriteFileEx() function in which it
250 * was specified has completed. The calling thread is the thread that
251 * initiated the read or write operation. An APC is queued when
252 * QueueUserAPC() is called. Currently completion routines and APC
253 * functions are not supported.
255 * Return value: %WAIT_ABANDONED - @wait is a mutex that was not
256 * released by the owning thread when it exited. Ownershop of the
257 * mutex object is granted to the calling thread and the mutex is set
258 * to nonsignalled. %WAIT_IO_COMPLETION - the wait was ended by one
259 * or more user-mode asynchronous procedure calls queued to the
260 * thread. %WAIT_OBJECT_0 - The state of @wait is signalled.
261 * %WAIT_TIMEOUT - The @timeout interval elapsed and @wait's state is
262 * still not signalled. %WAIT_FAILED - an error occurred.
264 guint32 SignalObjectAndWait(gpointer signal_handle, gpointer wait,
265 guint32 timeout, gboolean alertable)
267 guint32 ret = 0, waited;
269 gboolean apc_pending = FALSE;
270 gpointer current_thread = wapi_get_current_thread_handle ();
273 if (current_thread == NULL) {
274 SetLastError (ERROR_INVALID_HANDLE);
278 if (signal_handle == _WAPI_THREAD_CURRENT) {
279 signal_handle = wapi_get_current_thread_handle ();
280 if (signal_handle == NULL) {
281 SetLastError (ERROR_INVALID_HANDLE);
286 if (wait == _WAPI_THREAD_CURRENT) {
287 wait = wapi_get_current_thread_handle ();
289 SetLastError (ERROR_INVALID_HANDLE);
294 if ((GPOINTER_TO_UINT (signal_handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
295 SetLastError (ERROR_INVALID_HANDLE);
299 if ((GPOINTER_TO_UINT (wait) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
300 SetLastError (ERROR_INVALID_HANDLE);
304 if (_wapi_handle_test_capabilities (signal_handle,
305 WAPI_HANDLE_CAP_SIGNAL)==FALSE) {
309 if (_wapi_handle_test_capabilities (wait,
310 WAPI_HANDLE_CAP_WAIT)==FALSE) {
314 _wapi_handle_ops_prewait (wait);
316 if (_wapi_handle_test_capabilities (wait, WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE) {
317 g_warning ("%s: handle %p has special wait, implement me!!",
320 return (WAIT_FAILED);
323 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: locking handle %p", __func__, wait);
325 thr_ret = _wapi_handle_lock_handle (wait);
326 g_assert (thr_ret == 0);
328 _wapi_handle_ops_signal (signal_handle);
330 if (_wapi_handle_test_capabilities (wait, WAPI_HANDLE_CAP_OWN)==TRUE) {
331 if (own_if_owned (wait)) {
332 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p already owned", __func__,
339 if (own_if_signalled (wait)) {
340 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p already signalled", __func__, wait);
346 if (timeout != INFINITE)
347 end = mono_100ns_ticks () + timeout * 1000 * 10;
350 /* Check before waiting on the condition, just in case
352 _wapi_handle_ops_prewait (wait);
354 if (own_if_signalled (wait)) {
355 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p signalled", __func__, wait);
361 if (timeout == INFINITE) {
362 waited = _wapi_handle_timedwait_signal_handle (wait, INFINITE, alertable, FALSE, &apc_pending);
364 now = mono_100ns_ticks ();
370 waited = _wapi_handle_timedwait_signal_handle (wait, (end - now) / 10 / 1000, alertable, FALSE, &apc_pending);
373 if (waited==0 && !apc_pending) {
374 /* Condition was signalled, so hopefully
375 * handle is signalled now. (It might not be
376 * if someone else got in before us.)
378 if (own_if_signalled (wait)) {
379 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p signalled", __func__,
386 /* Better luck next time */
388 } while(waited == 0 && !apc_pending);
390 /* Timeout or other error */
391 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: wait on handle %p error: %s", __func__, wait, strerror (ret));
393 ret = apc_pending ? WAIT_IO_COMPLETION : WAIT_TIMEOUT;
397 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking handle %p", __func__, wait);
399 thr_ret = _wapi_handle_unlock_handle (wait);
400 g_assert (thr_ret == 0);
405 static gboolean test_and_own (guint32 numobjects, gpointer *handles,
406 gboolean waitall, guint32 *count,
412 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: locking handles", __func__);
414 done = _wapi_handle_count_signalled_handles (numobjects, handles,
415 waitall, count, lowest);
417 if (waitall == TRUE) {
418 for (i = 0; i < numobjects; i++) {
419 own_if_signalled (handles[i]);
422 own_if_signalled (handles[*lowest]);
426 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking handles", __func__);
428 _wapi_handle_unlock_handles (numobjects, handles);
434 * WaitForMultipleObjectsEx:
435 * @numobjects: The number of objects in @handles. The maximum allowed
436 * is %MAXIMUM_WAIT_OBJECTS.
437 * @handles: An array of object handles. Duplicates are not allowed.
438 * @waitall: If %TRUE, this function waits until all of the handles
439 * are signalled. If %FALSE, this function returns when any object is
441 * @timeout: The maximum time in milliseconds to wait for.
442 * @alertable: if TRUE, the wait can be interrupted by an APC call
444 * This function returns when either one or more of @handles is
445 * signalled, or @timeout ms elapses. If @timeout is zero, the state
446 * of each item of @handles is tested and the function returns
447 * immediately. If @timeout is %INFINITE, the function waits forever.
449 * Return value: %WAIT_OBJECT_0 to %WAIT_OBJECT_0 + @numobjects - 1 -
450 * if @waitall is %TRUE, indicates that all objects are signalled. If
451 * @waitall is %FALSE, the return value minus %WAIT_OBJECT_0 indicates
452 * the first index into @handles of the objects that are signalled.
453 * %WAIT_ABANDONED_0 to %WAIT_ABANDONED_0 + @numobjects - 1 - if
454 * @waitall is %TRUE, indicates that all objects are signalled, and at
455 * least one object is an abandoned mutex object (See
456 * WaitForSingleObject() for a description of abandoned mutexes.) If
457 * @waitall is %FALSE, the return value minus %WAIT_ABANDONED_0
458 * indicates the first index into @handles of an abandoned mutex.
459 * %WAIT_TIMEOUT - The @timeout interval elapsed and no objects in
460 * @handles are signalled. %WAIT_FAILED - an error occurred.
461 * %WAIT_IO_COMPLETION - the wait was ended by an APC.
463 guint32 WaitForMultipleObjectsEx(guint32 numobjects, gpointer *handles,
464 gboolean waitall, guint32 timeout,
467 gboolean duplicate = FALSE, bogustype = FALSE, done;
468 guint32 count, lowest;
472 gpointer current_thread = wapi_get_current_thread_handle ();
475 gpointer sorted_handles [MAXIMUM_WAIT_OBJECTS];
476 gboolean apc_pending = FALSE;
479 if (current_thread == NULL) {
480 SetLastError (ERROR_INVALID_HANDLE);
484 if (numobjects > MAXIMUM_WAIT_OBJECTS) {
485 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Too many handles: %d", __func__, numobjects);
490 if (numobjects == 1) {
491 return WaitForSingleObjectEx (handles [0], timeout, alertable);
494 /* Check for duplicates */
495 for (i = 0; i < numobjects; i++) {
496 if (handles[i] == _WAPI_THREAD_CURRENT) {
497 handles[i] = wapi_get_current_thread_handle ();
499 if (handles[i] == NULL) {
500 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Handle %d bogus", __func__, i);
507 if ((GPOINTER_TO_UINT (handles[i]) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
508 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Handle %d pseudo process", __func__,
515 if (_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_WAIT) == FALSE) {
516 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Handle %p can't be waited for",
517 __func__, handles[i]);
523 sorted_handles [i] = handles [i];
524 _wapi_handle_ops_prewait (handles[i]);
527 qsort (sorted_handles, numobjects, sizeof (gpointer), g_direct_equal);
528 for (i = 1; i < numobjects; i++) {
529 if (sorted_handles [i - 1] == sorted_handles [i]) {
535 if (duplicate == TRUE) {
536 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning due to duplicates", __func__);
541 if (bogustype == TRUE) {
542 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning due to bogus type", __func__);
548 for (i = 0; i < numobjects; ++i)
549 if (_wapi_handle_type (handles [i]) == WAPI_HANDLE_PROCESS || _WAPI_SHARED_HANDLE (_wapi_handle_type (handles[i])))
550 /* Can't wait for a process handle + another handle without polling */
553 done = test_and_own (numobjects, handles, waitall, &count, &lowest);
555 return(WAIT_OBJECT_0+lowest);
562 if (timeout != INFINITE)
563 end = mono_100ns_ticks () + timeout * 1000 * 10;
565 /* Have to wait for some or all handles to become signalled
568 for (i = 0; i < numobjects; i++) {
569 /* Add a reference, as we need to ensure the handle wont
570 * disappear from under us while we're waiting in the loop
571 * (not lock, as we don't want exclusive access here)
573 _wapi_handle_ref (handles[i]);
577 /* Prod all handles with prewait methods and
578 * special-wait handles that aren't already signalled
580 for (i = 0; i < numobjects; i++) {
581 _wapi_handle_ops_prewait (handles[i]);
583 if (_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE && _wapi_handle_issignalled (handles[i]) == FALSE) {
584 _wapi_handle_ops_special_wait (handles[i], 0, alertable);
588 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: locking signal mutex", __func__);
590 thr_ret = _wapi_handle_lock_signal_mutex ();
591 g_assert (thr_ret == 0);
593 /* Check the signalled state of handles inside the critical section */
596 for (i = 0; i < numobjects; i++)
597 if (!_wapi_handle_issignalled (handles [i]))
601 for (i = 0; i < numobjects; i++)
602 if (_wapi_handle_issignalled (handles [i]))
608 if (timeout == INFINITE) {
609 ret = _wapi_handle_timedwait_signal (INFINITE, poll, &apc_pending);
611 now = mono_100ns_ticks ();
615 ret = _wapi_handle_timedwait_signal ((end - now) / 10 / 1000, poll, &apc_pending);
619 /* No need to wait */
623 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking signal mutex", __func__);
625 thr_ret = _wapi_handle_unlock_signal_mutex (NULL);
626 g_assert (thr_ret == 0);
628 if (alertable && apc_pending) {
629 retval = WAIT_IO_COMPLETION;
633 /* Check if everything is signalled, as we can't
634 * guarantee to notice a shared signal even if the
637 done = test_and_own (numobjects, handles, waitall,
640 retval = WAIT_OBJECT_0+lowest;
642 } else if (ret != 0) {
643 /* Didn't get all handles, and there was a
644 * timeout or other error
646 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: wait returned error: %s", __func__,
650 retval = WAIT_TIMEOUT;
652 retval = WAIT_FAILED;
658 for (i = 0; i < numobjects; i++) {
659 /* Unref everything we reffed above */
660 _wapi_handle_unref (handles[i]);
666 guint32 WaitForMultipleObjects(guint32 numobjects, gpointer *handles,
667 gboolean waitall, guint32 timeout)
669 return WaitForMultipleObjectsEx(numobjects, handles, waitall, timeout, FALSE);
674 * @handle: a handle to the process to wait for
675 * @timeout: the maximum time in milliseconds to wait for
677 * This function returns when either @handle process is waiting
678 * for input, or @timeout ms elapses. If @timeout is zero, the
679 * process state is tested and the function returns immediately.
680 * If @timeout is %INFINITE, the function waits forever.
682 * Return value: 0 - @handle process is waiting for input.
683 * %WAIT_TIMEOUT - The @timeout interval elapsed and
684 * @handle process is not waiting for input. %WAIT_FAILED - an error
687 guint32 WaitForInputIdle(gpointer handle, guint32 timeout)
689 /*TODO: Not implemented*/