static gpointer event_handle_create (struct _WapiHandle_event *event_handle, MonoW32HandleType type, gboolean manual, gboolean initial) { gpointer handle; int thr_ret; event_handle->manual = manual; event_handle->set_count = (initial && !manual) ? 1 : 0; handle = mono_w32handle_new (type, event_handle); if (handle == INVALID_HANDLE_VALUE) { g_warning ("%s: error creating %s handle", __func__, event_handle_type_to_string (type)); SetLastError (ERROR_GEN_FAILURE); return NULL; } thr_ret = mono_w32handle_lock_handle (handle); g_assert (thr_ret == 0); if (initial) mono_w32handle_set_signal_state (handle, TRUE, FALSE); thr_ret = mono_w32handle_unlock_handle (handle); g_assert (thr_ret == 0); MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: created %s handle %p", __func__, event_handle_type_to_string (type), handle); return handle; }
static gpointer mutex_handle_create (MonoW32HandleMutex *mutex_handle, MonoW32HandleType type, gboolean owned) { gpointer handle; gboolean abandoned; mutex_handle->tid = 0; mutex_handle->recursion = 0; mutex_handle->abandoned = FALSE; handle = mono_w32handle_new (type, mutex_handle); if (handle == INVALID_HANDLE_VALUE) { g_warning ("%s: error creating %s handle", __func__, mono_w32handle_get_typename (type)); mono_w32error_set_last (ERROR_GEN_FAILURE); return NULL; } mono_w32handle_lock_handle (handle); if (owned) mutex_handle_own (handle, type, &abandoned); else mono_w32handle_set_signal_state (handle, TRUE, FALSE); mono_w32handle_unlock_handle (handle); mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: created %s handle %p", __func__, mono_w32handle_get_typename (type), handle); return handle; }
static gpointer sem_handle_create (MonoW32HandleSemaphore *sem_handle, MonoW32HandleType type, gint32 initial, gint32 max) { gpointer handle; int thr_ret; sem_handle->val = initial; sem_handle->max = max; handle = mono_w32handle_new (type, sem_handle); if (handle == INVALID_HANDLE_VALUE) { g_warning ("%s: error creating %s handle", __func__, mono_w32handle_ops_typename (type)); SetLastError (ERROR_GEN_FAILURE); return NULL; } thr_ret = mono_w32handle_lock_handle (handle); g_assert (thr_ret == 0); if (initial != 0) mono_w32handle_set_signal_state (handle, TRUE, FALSE); thr_ret = mono_w32handle_unlock_handle (handle); g_assert (thr_ret == 0); mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: created %s handle %p", __func__, mono_w32handle_ops_typename (type), handle); return handle; }
static gpointer event_handle_create (MonoW32HandleEvent *event_handle, MonoW32HandleType type, gboolean manual, gboolean initial) { gpointer handle; event_handle->manual = manual; event_handle->set_count = (initial && !manual) ? 1 : 0; handle = mono_w32handle_new (type, event_handle); if (handle == INVALID_HANDLE_VALUE) { g_warning ("%s: error creating %s handle", __func__, mono_w32handle_ops_typename (type)); SetLastError (ERROR_GEN_FAILURE); return NULL; } mono_w32handle_lock_handle (handle); if (initial) mono_w32handle_set_signal_state (handle, TRUE, FALSE); mono_w32handle_unlock_handle (handle); mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: created %s handle %p", __func__, mono_w32handle_ops_typename (type), handle); return handle; }
MonoBoolean ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (gpointer handle, gint32 releaseCount, gint32 *prevcount) { MonoW32HandleType type; MonoW32HandleSemaphore *sem_handle; int thr_ret; MonoBoolean ret; if (!handle) { SetLastError (ERROR_INVALID_HANDLE); return FALSE; } switch (type = mono_w32handle_get_type (handle)) { case MONO_W32HANDLE_SEM: case MONO_W32HANDLE_NAMEDSEM: break; default: SetLastError (ERROR_INVALID_HANDLE); return FALSE; } if (!mono_w32handle_lookup (handle, type, (gpointer *)&sem_handle)) { g_warning ("%s: error looking up sem handle %p", __func__, handle); return FALSE; } mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: releasing %s handle %p", __func__, mono_w32handle_ops_typename (type), handle); thr_ret = mono_w32handle_lock_handle (handle); g_assert (thr_ret == 0); /* Do this before checking for count overflow, because overflowing * max is a listed technique for finding the current value */ if (prevcount) *prevcount = sem_handle->val; /* No idea why max is signed, but thats the spec :-( */ if (sem_handle->val + releaseCount > (guint32)sem_handle->max) { mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p val %d count %d max %d, max value would be exceeded", __func__, mono_w32handle_ops_typename (type), handle, sem_handle->val, releaseCount, sem_handle->max); ret = FALSE; } else { mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p val %d count %d max %d", __func__, mono_w32handle_ops_typename (type), handle, sem_handle->val, releaseCount, sem_handle->max); sem_handle->val += releaseCount; mono_w32handle_set_signal_state (handle, TRUE, TRUE); ret = TRUE; } thr_ret = mono_w32handle_unlock_handle (handle); g_assert (thr_ret == 0); return ret; }
void mono_w32mutex_abandon (void) { MonoInternalThread *internal; g_assert (mono_thread_internal_current_is_attached ()); internal = mono_thread_internal_current (); g_assert (internal); if (!internal->owned_mutexes) return; while (internal->owned_mutexes->len) { MonoW32HandleType type; MonoW32HandleMutex *mutex_handle; MonoNativeThreadId tid; gpointer handle; handle = g_ptr_array_index (internal->owned_mutexes, 0); switch (type = mono_w32handle_get_type (handle)) { case MONO_W32HANDLE_MUTEX: case MONO_W32HANDLE_NAMEDMUTEX: break; default: g_assert_not_reached (); } if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) { g_error ("%s: error looking up %s handle %p", __func__, mono_w32handle_get_typename (type), handle); } mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: abandoning %s handle %p", __func__, mono_w32handle_get_typename (type), handle); tid = MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid); if (!pthread_equal (mutex_handle->tid, tid)) g_error ("%s: trying to release mutex %p acquired by thread %p from thread %p", __func__, handle, (gpointer) mutex_handle->tid, (gpointer) tid); mono_w32handle_lock_handle (handle); mutex_handle->recursion = 0; mutex_handle->tid = 0; mutex_handle->abandoned = TRUE; mono_w32handle_set_signal_state (handle, TRUE, FALSE); thread_disown_mutex (internal, handle); mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: abandoned %s handle %p", __func__, mono_w32handle_get_typename (type), handle); mono_w32handle_unlock_handle (handle); } g_ptr_array_free (internal->owned_mutexes, TRUE); internal->owned_mutexes = NULL; }
MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (gpointer handle) { MonoW32HandleType type; MonoW32HandleMutex *mutex_handle; pthread_t tid; gboolean ret; if (handle == NULL) { mono_w32error_set_last (ERROR_INVALID_HANDLE); return FALSE; } switch (type = mono_w32handle_get_type (handle)) { case MONO_W32HANDLE_MUTEX: case MONO_W32HANDLE_NAMEDMUTEX: break; default: mono_w32error_set_last (ERROR_INVALID_HANDLE); return FALSE; } if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) { g_warning ("%s: error looking up %s handle %p", __func__, mono_w32handle_get_typename (type), handle); return FALSE; } mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: releasing %s handle %p, tid: %p recursion: %d", __func__, mono_w32handle_get_typename (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion); mono_w32handle_lock_handle (handle); tid = pthread_self (); if (mutex_handle->abandoned) { // The Win32 ReleaseMutex() function returns TRUE for abandoned mutexes ret = TRUE; } else if (!pthread_equal (mutex_handle->tid, tid)) { ret = FALSE; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: we don't own %s handle %p (owned by %ld, me %ld)", __func__, mono_w32handle_get_typename (type), handle, (long)mutex_handle->tid, (long)tid); } else { ret = TRUE; /* OK, we own this mutex */ mutex_handle->recursion--; if (mutex_handle->recursion == 0) { thread_disown_mutex (mono_thread_internal_current (), handle); mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking %s handle %p, tid: %p recusion : %d", __func__, mono_w32handle_get_typename (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion); mutex_handle->tid = 0; mono_w32handle_set_signal_state (handle, TRUE, FALSE); } } mono_w32handle_unlock_handle (handle); 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; int thr_ret; gboolean apc_pending = FALSE; gpointer current_thread = wapi_get_current_thread_handle (); gint64 wait_start, timeout_in_ticks; 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 (mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_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); } mono_w32handle_ops_prewait (handle); if (mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_SPECIAL_WAIT) == TRUE) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p has special wait", __func__, handle); ret = mono_w32handle_ops_specialwait (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 = mono_w32handle_lock_handle (handle); g_assert (thr_ret == 0); if (mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_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) { wait_start = mono_100ns_ticks (); timeout_in_ticks = (gint64)timeout * 10 * 1000; //can't overflow as timeout is 32bits } do { /* Check before waiting on the condition, just in case */ mono_w32handle_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 = mono_w32handle_timedwait_signal_handle (handle, INFINITE, FALSE, alertable ? &apc_pending : NULL); } else { gint64 elapsed = mono_100ns_ticks () - wait_start; if (elapsed >= timeout_in_ticks) { ret = WAIT_TIMEOUT; goto done; } waited = mono_w32handle_timedwait_signal_handle (handle, (timeout_in_ticks - elapsed) / 10 / 1000, FALSE, alertable ? &apc_pending : NULL); } 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 = mono_w32handle_unlock_handle (handle); g_assert (thr_ret == 0); return(ret); }