static void mutex_abandon (gpointer handle, pid_t pid, pthread_t tid) { struct _WapiHandle_mutex *mutex_handle; gboolean ok; int thr_ret; ok = _wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX, (gpointer *)&mutex_handle); if (ok == FALSE) { g_warning ("%s: error looking up mutex handle %p", __func__, handle); return; } thr_ret = _wapi_handle_lock_handle (handle); g_assert (thr_ret == 0); if (mutex_handle->pid == pid && pthread_equal (mutex_handle->tid, tid)) { DEBUG ("%s: Mutex handle %p abandoned!", __func__, handle); mutex_handle->recursion = 0; mutex_handle->pid = 0; mutex_handle->tid = 0; _wapi_handle_set_signal_state (handle, TRUE, FALSE); } thr_ret = _wapi_handle_unlock_handle (handle); g_assert (thr_ret == 0); }
void _wapi_thread_set_termination_details (gpointer handle, guint32 exitstatus) { struct _WapiHandle_thread *thread_handle; gboolean ok; int thr_ret; if (_wapi_handle_issignalled (handle) || _wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) { /* We must have already deliberately finished with * this thread, so don't do any more now */ return; } #ifdef DEBUG g_message ("%s: Thread %p terminating", __func__, handle); #endif _wapi_thread_abandon_mutexes (handle); ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD, (gpointer *)&thread_handle); if (ok == FALSE) { g_warning ("%s: error looking up thread handle %p", __func__, handle); return; } pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle, handle); thr_ret = _wapi_handle_lock_handle (handle); g_assert (thr_ret == 0); thread_handle->exitstatus = exitstatus; thread_handle->state = THREAD_STATE_EXITED; MONO_SEM_DESTROY (&thread_handle->suspend_sem); g_ptr_array_free (thread_handle->owned_mutexes, TRUE); _wapi_handle_set_signal_state (handle, TRUE, TRUE); thr_ret = _wapi_handle_unlock_handle (handle); g_assert (thr_ret == 0); pthread_cleanup_pop (0); #ifdef DEBUG g_message("%s: Recording thread handle %p id %ld status as %d", __func__, handle, thread_handle->id, exitstatus); #endif /* The thread is no longer active, so unref it */ _wapi_handle_unref (handle); }
/** * WaitForSingleObjectEx: * @handle: an object to wait for * @timeout: the maximum time in milliseconds to wait for * @alertable: if TRUE, the wait can be interrupted by an APC call * * This function returns when either @handle is signalled, or @timeout * ms elapses. If @timeout is zero, the object's state is tested and * the function returns immediately. If @timeout is %INFINITE, the * function waits forever. * * Return value: %WAIT_ABANDONED - @handle is a mutex that was not * released by the owning thread when it exited. Ownership of the * mutex object is granted to the calling thread and the mutex is set * to nonsignalled. %WAIT_OBJECT_0 - The state of @handle is * signalled. %WAIT_TIMEOUT - The @timeout interval elapsed and * @handle's state is still not signalled. %WAIT_FAILED - an error * occurred. %WAIT_IO_COMPLETION - the wait was ended by an APC. */ guint32 WaitForSingleObjectEx(gpointer handle, guint32 timeout, gboolean alertable) { guint32 ret, waited; int thr_ret; gboolean apc_pending = FALSE; gpointer current_thread = wapi_get_current_thread_handle (); gint64 now, end; if (current_thread == NULL) { SetLastError (ERROR_INVALID_HANDLE); return(WAIT_FAILED); } if (handle == _WAPI_THREAD_CURRENT) { handle = wapi_get_current_thread_handle (); if (handle == NULL) { SetLastError (ERROR_INVALID_HANDLE); return(WAIT_FAILED); } } if ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { SetLastError (ERROR_INVALID_HANDLE); return(WAIT_FAILED); } if (_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_WAIT) == FALSE) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p can't be waited for", __func__, handle); return(WAIT_FAILED); } _wapi_handle_ops_prewait (handle); if (_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p has special wait", __func__, handle); ret = _wapi_handle_ops_special_wait (handle, timeout, alertable); if (alertable && _wapi_thread_cur_apc_pending ()) ret = WAIT_IO_COMPLETION; return ret; } MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: locking handle %p", __func__, handle); thr_ret = _wapi_handle_lock_handle (handle); g_assert (thr_ret == 0); if (_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN) == TRUE) { if (own_if_owned (handle) == TRUE) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p already owned", __func__, handle); ret = WAIT_OBJECT_0; goto done; } } if (own_if_signalled (handle) == TRUE) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p already signalled", __func__, handle); ret=WAIT_OBJECT_0; goto done; } if (timeout == 0) { ret = WAIT_TIMEOUT; goto done; } if (timeout != INFINITE) end = mono_100ns_ticks () + timeout * 1000 * 10; do { /* Check before waiting on the condition, just in case */ _wapi_handle_ops_prewait (handle); if (own_if_signalled (handle)) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p signalled", __func__, handle); ret = WAIT_OBJECT_0; goto done; } if (timeout == INFINITE) { waited = _wapi_handle_timedwait_signal_handle (handle, INFINITE, alertable, FALSE, &apc_pending); } else { now = mono_100ns_ticks (); if (end < now) { ret = WAIT_TIMEOUT; goto done; } waited = _wapi_handle_timedwait_signal_handle (handle, (end - now) / 10 / 1000, alertable, FALSE, &apc_pending); } if(waited==0 && !apc_pending) { /* Condition was signalled, so hopefully * handle is signalled now. (It might not be * if someone else got in before us.) */ if (own_if_signalled (handle)) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p signalled", __func__, handle); ret=WAIT_OBJECT_0; goto done; } /* Better luck next time */ } } while(waited == 0 && !apc_pending); /* Timeout or other error */ MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: wait on handle %p error: %s", __func__, handle, strerror (waited)); ret = apc_pending ? WAIT_IO_COMPLETION : WAIT_TIMEOUT; done: MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking handle %p", __func__, handle); thr_ret = _wapi_handle_unlock_handle (handle); g_assert (thr_ret == 0); return(ret); }
/** * WaitForSingleObjectEx: * @handle: an object to wait for * @timeout: the maximum time in milliseconds to wait for * @alertable: if TRUE, the wait can be interrupted by an APC call * * This function returns when either @handle is signalled, or @timeout * ms elapses. If @timeout is zero, the object's state is tested and * the function returns immediately. If @timeout is %INFINITE, the * function waits forever. * * Return value: %WAIT_ABANDONED - @handle is a mutex that was not * released by the owning thread when it exited. Ownership of the * mutex object is granted to the calling thread and the mutex is set * to nonsignalled. %WAIT_OBJECT_0 - The state of @handle is * signalled. %WAIT_TIMEOUT - The @timeout interval elapsed and * @handle's state is still not signalled. %WAIT_FAILED - an error * occurred. %WAIT_IO_COMPLETION - the wait was ended by an APC. */ guint32 WaitForSingleObjectEx(gpointer handle, guint32 timeout, gboolean alertable) { guint32 ret, waited; struct timespec abstime; int thr_ret; gboolean apc_pending = FALSE; gpointer current_thread = _wapi_thread_handle_from_id (pthread_self ()); if (current_thread == NULL) { SetLastError (ERROR_INVALID_HANDLE); return(WAIT_FAILED); } if (handle == _WAPI_THREAD_CURRENT) { handle = _wapi_thread_handle_from_id (pthread_self ()); if (handle == NULL) { SetLastError (ERROR_INVALID_HANDLE); return(WAIT_FAILED); } } if ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { SetLastError (ERROR_INVALID_HANDLE); return(WAIT_FAILED); } if (_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_WAIT) == FALSE) { #ifdef DEBUG g_message ("%s: handle %p can't be waited for", __func__, handle); #endif return(WAIT_FAILED); } _wapi_handle_ops_prewait (handle); if (_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE) { #ifdef DEBUG g_message ("%s: handle %p has special wait", __func__, handle); #endif ret = _wapi_handle_ops_special_wait (handle, timeout); if (alertable && _wapi_thread_apc_pending (current_thread)) { apc_pending = TRUE; ret = WAIT_IO_COMPLETION; } goto check_pending; } #ifdef DEBUG g_message ("%s: locking handle %p", __func__, handle); #endif pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle, handle); thr_ret = _wapi_handle_lock_handle (handle); g_assert (thr_ret == 0); if (_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN) == TRUE) { if (own_if_owned (handle) == TRUE) { #ifdef DEBUG g_message ("%s: handle %p already owned", __func__, handle); #endif ret = WAIT_OBJECT_0; goto done; } } if (alertable && _wapi_thread_apc_pending (current_thread)) { apc_pending = TRUE; ret = WAIT_IO_COMPLETION; goto done; } if (own_if_signalled (handle) == TRUE) { #ifdef DEBUG g_message ("%s: handle %p already signalled", __func__, handle); #endif ret=WAIT_OBJECT_0; goto done; } if (timeout == 0) { ret = WAIT_TIMEOUT; goto done; } /* Have to wait for it */ if (timeout != INFINITE) { _wapi_calc_timeout (&abstime, timeout); } do { /* Check before waiting on the condition, just in case */ _wapi_handle_ops_prewait (handle); if (own_if_signalled (handle)) { #ifdef DEBUG g_message ("%s: handle %p signalled", __func__, handle); #endif ret = WAIT_OBJECT_0; goto done; } if (timeout == INFINITE) { waited = _wapi_handle_wait_signal_handle (handle, alertable); } else { waited = _wapi_handle_timedwait_signal_handle (handle, &abstime, alertable, FALSE); } if (alertable) apc_pending = _wapi_thread_apc_pending (current_thread); if(waited==0 && !apc_pending) { /* Condition was signalled, so hopefully * handle is signalled now. (It might not be * if someone else got in before us.) */ if (own_if_signalled (handle)) { #ifdef DEBUG g_message ("%s: handle %p signalled", __func__, handle); #endif ret=WAIT_OBJECT_0; goto done; } /* Better luck next time */ } } while(waited == 0 && !apc_pending); /* Timeout or other error */ #ifdef DEBUG g_message ("%s: wait on handle %p error: %s", __func__, handle, strerror (waited)); #endif ret = WAIT_TIMEOUT; done: #ifdef DEBUG g_message ("%s: unlocking handle %p", __func__, handle); #endif thr_ret = _wapi_handle_unlock_handle (handle); g_assert (thr_ret == 0); pthread_cleanup_pop (0); check_pending: if (apc_pending) { _wapi_thread_dispatch_apc_queue (current_thread); ret = WAIT_IO_COMPLETION; } return(ret); }
/** * SignalObjectAndWait: * @signal_handle: An object to signal * @wait: An object to wait for * @timeout: The maximum time in milliseconds to wait for * @alertable: Specifies whether the function returnes when the system * queues an I/O completion routine or an APC for the calling thread. * * Atomically signals @signal and waits for @wait to become signalled, * or @timeout ms elapses. If @timeout is zero, the object's state is * tested and the function returns immediately. If @timeout is * %INFINITE, the function waits forever. * * @signal can be a semaphore, mutex or event object. * * If @alertable is %TRUE and the system queues an I/O completion * routine or an APC for the calling thread, the function returns and * the thread calls the completion routine or APC function. If * %FALSE, the function does not return, and the thread does not call * the completion routine or APC function. A completion routine is * queued when the ReadFileEx() or WriteFileEx() function in which it * was specified has completed. The calling thread is the thread that * initiated the read or write operation. An APC is queued when * QueueUserAPC() is called. Currently completion routines and APC * functions are not supported. * * Return value: %WAIT_ABANDONED - @wait is a mutex that was not * released by the owning thread when it exited. Ownershop of the * mutex object is granted to the calling thread and the mutex is set * to nonsignalled. %WAIT_IO_COMPLETION - the wait was ended by one * or more user-mode asynchronous procedure calls queued to the * thread. %WAIT_OBJECT_0 - The state of @wait is signalled. * %WAIT_TIMEOUT - The @timeout interval elapsed and @wait's state is * still not signalled. %WAIT_FAILED - an error occurred. */ guint32 SignalObjectAndWait(gpointer signal_handle, gpointer wait, guint32 timeout, gboolean alertable) { guint32 ret, waited; struct timespec abstime; int thr_ret; gboolean apc_pending = FALSE; gpointer current_thread = GetCurrentThread (); if (_wapi_handle_test_capabilities (signal_handle, WAPI_HANDLE_CAP_SIGNAL)==FALSE) { return(WAIT_FAILED); } if (_wapi_handle_test_capabilities (wait, WAPI_HANDLE_CAP_WAIT)==FALSE) { return(WAIT_FAILED); } if (_wapi_handle_test_capabilities (wait, WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE) { g_warning ("%s: handle %p has special wait, implement me!!", __func__, wait); return (WAIT_FAILED); } #ifdef DEBUG g_message ("%s: locking handle %p", __func__, wait); #endif pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle, wait); thr_ret = _wapi_handle_lock_handle (wait); g_assert (thr_ret == 0); _wapi_handle_ops_signal (signal_handle); if (_wapi_handle_test_capabilities (wait, WAPI_HANDLE_CAP_OWN)==TRUE) { if (own_if_owned (wait)) { #ifdef DEBUG g_message ("%s: handle %p already owned", __func__, wait); #endif ret = WAIT_OBJECT_0; goto done; } } if (alertable && _wapi_thread_apc_pending (current_thread)) { apc_pending = TRUE; ret = WAIT_IO_COMPLETION; goto done; } if (own_if_signalled (wait)) { #ifdef DEBUG g_message ("%s: handle %p already signalled", __func__, wait); #endif ret = WAIT_OBJECT_0; goto done; } /* Have to wait for it */ if (timeout != INFINITE) { _wapi_calc_timeout (&abstime, timeout); } do { /* Check before waiting on the condition, just in case */ if (own_if_signalled (wait)) { #ifdef DEBUG g_message ("%s: handle %p signalled", __func__, wait); #endif ret = WAIT_OBJECT_0; goto done; } if (timeout == INFINITE) { waited = _wapi_handle_wait_signal_handle (wait); } else { waited = _wapi_handle_timedwait_signal_handle (wait, &abstime); } if (alertable) { apc_pending = _wapi_thread_apc_pending (current_thread); } if (waited==0 && !apc_pending) { /* Condition was signalled, so hopefully * handle is signalled now. (It might not be * if someone else got in before us.) */ if (own_if_signalled (wait)) { #ifdef DEBUG g_message ("%s: handle %p signalled", __func__, wait); #endif ret = WAIT_OBJECT_0; goto done; } /* Better luck next time */ } } while(waited == 0 && !apc_pending); /* Timeout or other error */ #ifdef DEBUG g_message ("%s: wait on handle %p error: %s", __func__, wait, strerror (ret)); #endif ret = WAIT_TIMEOUT; done: #ifdef DEBUG g_message ("%s: unlocking handle %p", __func__, wait); #endif thr_ret = _wapi_handle_unlock_handle (wait); g_assert (thr_ret == 0); pthread_cleanup_pop (0); if (apc_pending) { _wapi_thread_dispatch_apc_queue (current_thread); ret = WAIT_IO_COMPLETION; } return(ret); }