MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (gpointer handle) { MonoW32Handle *handle_data; MonoW32HandleMutex *mutex_handle; pthread_t tid; gboolean ret; if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) { g_warning ("%s: unkown handle %p", __func__, handle); mono_w32error_set_last (ERROR_INVALID_HANDLE); return FALSE; } if (handle_data->type != MONO_W32TYPE_MUTEX && handle_data->type != MONO_W32TYPE_NAMEDMUTEX) { g_warning ("%s: unknown mutex handle %p", __func__, handle); mono_w32error_set_last (ERROR_INVALID_HANDLE); mono_w32handle_unref (handle_data); return FALSE; } mutex_handle = (MonoW32HandleMutex*) handle_data->specific; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: releasing %s handle %p, tid: %p recursion: %d", __func__, mono_w32handle_get_typename (handle_data->type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion); mono_w32handle_lock (handle_data); 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_MUTEX, "%s: we don't own %s handle %p (owned by %ld, me %ld)", __func__, mono_w32handle_get_typename (handle_data->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 (), handle); mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: unlocking %s handle %p, tid: %p recusion : %d", __func__, mono_w32handle_get_typename (handle_data->type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion); mutex_handle->tid = 0; mono_w32handle_set_signal_state (handle_data, TRUE, FALSE); } } mono_w32handle_unlock (handle_data); mono_w32handle_unref (handle_data); return ret; }
void mono_w32mutex_abandon (MonoInternalThread *internal_raw) { HANDLE_FUNCTION_ENTER () MONO_HANDLE_DCL (MonoInternalThread, internal); g_assert (mono_thread_internal_is_current_handle (internal)); if (!MONO_HANDLE_GETVAL (internal, owned_mutexes)) goto exit; while (MONO_HANDLE_GETVAL (internal, owned_mutexes)->len) { MonoW32Handle *handle_data; MonoW32HandleMutex *mutex_handle; MonoNativeThreadId tid; gpointer handle; handle = g_ptr_array_index (MONO_HANDLE_GETVAL (internal, owned_mutexes), 0); if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) g_error ("%s: unkown handle %p", __func__, handle); if (handle_data->type != MONO_W32TYPE_MUTEX && handle_data->type != MONO_W32TYPE_NAMEDMUTEX) g_error ("%s: unkown mutex handle %p", __func__, handle); mutex_handle = (MonoW32HandleMutex*) handle_data->specific; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: abandoning %s handle %p", __func__, mono_w32handle_get_typename (handle_data->type), handle); tid = MONO_UINT_TO_NATIVE_THREAD_ID (MONO_HANDLE_GETVAL (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_data); mutex_handle->recursion = 0; mutex_handle->tid = 0; mutex_handle->abandoned = TRUE; mono_w32handle_set_signal_state (handle_data, TRUE, FALSE); thread_disown_mutex (internal, handle); mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: abandoned %s handle %p", __func__, mono_w32handle_get_typename (handle_data->type), handle); mono_w32handle_unlock (handle_data); mono_w32handle_unref (handle_data); } g_ptr_array_free (MONO_HANDLE_GETVAL (internal, owned_mutexes), TRUE); MONO_HANDLE_SETVAL(internal, owned_mutexes, GPtrArray*, NULL); exit: HANDLE_FUNCTION_RETURN (); }
void mono_w32handle_cleanup (void) { int i, j, k; g_assert (!shutting_down); shutting_down = TRUE; /* Every shared handle we were using ought really to be closed * by now, but to make sure just blow them all away. The * exiting finalizer thread in particular races us to the * program exit and doesn't always win, so it can be left * cluttering up the shared file. Anything else left over is * really a bug. */ for(i = SLOT_INDEX (0); private_handles[i] != NULL; i++) { for(j = SLOT_OFFSET (0); j < HANDLE_PER_SLOT; j++) { MonoW32HandleBase *handle_data = &private_handles[i][j]; gpointer handle = GINT_TO_POINTER (i*HANDLE_PER_SLOT+j); for(k = handle_data->ref; k > 0; k--) { mono_w32handle_unref (handle); } } } for (i = 0; i < SLOT_MAX; ++i) g_free (private_handles [i]); }
int closesocket(guint32 fd) { gpointer handle = GUINT_TO_POINTER (fd); if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(0); } mono_w32handle_unref (handle); return(0); }
void mono_w32mutex_abandon (MonoInternalThread *internal) { g_assert (mono_thread_internal_is_current (internal)); if (!internal->owned_mutexes) return; while (internal->owned_mutexes->len) { MonoW32Handle *handle_data; MonoW32HandleMutex *mutex_handle; MonoNativeThreadId tid; gpointer handle; handle = g_ptr_array_index (internal->owned_mutexes, 0); if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) g_error ("%s: unkown handle %p", __func__, handle); if (handle_data->type != MONO_W32TYPE_MUTEX && handle_data->type != MONO_W32TYPE_NAMEDMUTEX) g_error ("%s: unkown mutex handle %p", __func__, handle); mutex_handle = (MonoW32HandleMutex*) handle_data->specific; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: abandoning %s handle %p", __func__, mono_w32handle_get_typename (handle_data->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_data); mutex_handle->recursion = 0; mutex_handle->tid = 0; mutex_handle->abandoned = TRUE; mono_w32handle_set_signal_state (handle_data, TRUE, FALSE); thread_disown_mutex (internal, handle); mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: abandoned %s handle %p", __func__, mono_w32handle_get_typename (handle_data->type), handle); mono_w32handle_unlock (handle_data); mono_w32handle_unref (handle_data); } g_ptr_array_free (internal->owned_mutexes, TRUE); internal->owned_mutexes = NULL; }
static void thread_disown_mutex (MonoInternalThread *internal, gpointer handle) { gboolean removed; g_assert (mono_thread_internal_is_current (internal)); g_assert (internal->owned_mutexes); removed = g_ptr_array_remove (internal->owned_mutexes, handle); g_assert (removed); mono_w32handle_unref (handle); }
int mono_w32handle_unlock_handle (gpointer handle) { MonoW32HandleBase *handle_data; #ifdef DEBUG g_message ("%s: unlocking handle %p", __func__, handle); #endif if (!mono_w32handle_lookup_data (handle, &handle_data)) { return(0); } mono_os_mutex_unlock (&handle_data->signal_mutex); mono_w32handle_unref (handle); return 0; }
static gpointer mutex_handle_create (MonoW32HandleMutex *mutex_handle, MonoW32Type type, gboolean owned) { MonoW32Handle *handle_data; 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; } if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) g_error ("%s: unkown handle %p", __func__, handle); if (handle_data->type != type) g_error ("%s: unknown mutex handle %p", __func__, handle); mono_w32handle_lock (handle_data); if (owned) mutex_handle_own (handle_data, &abandoned); else mono_w32handle_set_signal_state (handle_data, TRUE, FALSE); mono_w32handle_unlock (handle_data); /* Balance mono_w32handle_lookup_and_ref */ mono_w32handle_unref (handle_data); mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: created %s handle %p", __func__, mono_w32handle_get_typename (type), handle); return handle; }
int mono_w32handle_trylock_handle (gpointer handle) { MonoW32HandleBase *handle_data; int ret; #ifdef DEBUG g_message ("%s: locking handle %p", __func__, handle); #endif if (!mono_w32handle_lookup_data (handle, &handle_data)) { return(0); } mono_w32handle_ref (handle); ret = mono_os_mutex_trylock (&handle_data->signal_mutex); if (ret != 0) { mono_w32handle_unref (handle); } return(ret); }
static gpointer event_handle_create (MonoW32HandleEvent *event_handle, MonoW32Type type, gboolean manual, gboolean initial) { MonoW32Handle *handle_data; 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_get_typename (type)); mono_w32error_set_last (ERROR_GEN_FAILURE); return NULL; } if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) g_error ("%s: unkown handle %p", __func__, handle); if (handle_data->type != type) g_error ("%s: unknown event handle %p", __func__, handle); mono_w32handle_lock (handle_data); if (initial) mono_w32handle_set_signal_state (handle_data, TRUE, FALSE); mono_w32handle_unlock (handle_data); mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_EVENT, "%s: created %s handle %p", __func__, mono_w32handle_get_typename (type), handle); mono_w32handle_unref (handle_data); return handle; }
/** * WaitForMultipleObjectsEx: * @numobjects: The number of objects in @handles. The maximum allowed * is %MAXIMUM_WAIT_OBJECTS. * @handles: An array of object handles. Duplicates are not allowed. * @waitall: If %TRUE, this function waits until all of the handles * are signalled. If %FALSE, this function returns when any object is * signalled. * @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 one or more of @handles is * signalled, or @timeout ms elapses. If @timeout is zero, the state * of each item of @handles is tested and the function returns * immediately. If @timeout is %INFINITE, the function waits forever. * * Return value: %WAIT_OBJECT_0 to %WAIT_OBJECT_0 + @numobjects - 1 - * if @waitall is %TRUE, indicates that all objects are signalled. If * @waitall is %FALSE, the return value minus %WAIT_OBJECT_0 indicates * the first index into @handles of the objects that are signalled. * %WAIT_ABANDONED_0 to %WAIT_ABANDONED_0 + @numobjects - 1 - if * @waitall is %TRUE, indicates that all objects are signalled, and at * least one object is an abandoned mutex object (See * WaitForSingleObject() for a description of abandoned mutexes.) If * @waitall is %FALSE, the return value minus %WAIT_ABANDONED_0 * indicates the first index into @handles of an abandoned mutex. * %WAIT_TIMEOUT - The @timeout interval elapsed and no objects in * @handles are signalled. %WAIT_FAILED - an error occurred. * %WAIT_IO_COMPLETION - the wait was ended by an APC. */ guint32 WaitForMultipleObjectsEx(guint32 numobjects, gpointer *handles, gboolean waitall, guint32 timeout, gboolean alertable) { gboolean duplicate = FALSE, bogustype = FALSE, done; guint32 count, lowest; guint i; guint32 ret; int thr_ret; gpointer current_thread = wapi_get_current_thread_handle (); guint32 retval; gboolean poll; gpointer sorted_handles [MAXIMUM_WAIT_OBJECTS]; gboolean apc_pending = FALSE; gint64 wait_start, timeout_in_ticks; if (current_thread == NULL) { SetLastError (ERROR_INVALID_HANDLE); return(WAIT_FAILED); } if (numobjects > MAXIMUM_WAIT_OBJECTS) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Too many handles: %d", __func__, numobjects); return(WAIT_FAILED); } if (numobjects == 1) { return WaitForSingleObjectEx (handles [0], timeout, alertable); } /* Check for duplicates */ for (i = 0; i < numobjects; i++) { if (handles[i] == _WAPI_THREAD_CURRENT) { handles[i] = wapi_get_current_thread_handle (); if (handles[i] == NULL) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Handle %d bogus", __func__, i); bogustype = TRUE; break; } } if ((GPOINTER_TO_UINT (handles[i]) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Handle %d pseudo process", __func__, i); bogustype = TRUE; break; } if (mono_w32handle_test_capabilities (handles[i], MONO_W32HANDLE_CAP_WAIT) == FALSE) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Handle %p can't be waited for", __func__, handles[i]); bogustype = TRUE; break; } sorted_handles [i] = handles [i]; mono_w32handle_ops_prewait (handles[i]); } qsort (sorted_handles, numobjects, sizeof (gpointer), g_direct_equal); for (i = 1; i < numobjects; i++) { if (sorted_handles [i - 1] == sorted_handles [i]) { duplicate = TRUE; break; } } if (duplicate == TRUE) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning due to duplicates", __func__); return(WAIT_FAILED); } if (bogustype == TRUE) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning due to bogus type", __func__); return(WAIT_FAILED); } poll = FALSE; for (i = 0; i < numobjects; ++i) if (mono_w32handle_get_type (handles [i]) == MONO_W32HANDLE_PROCESS) /* Can't wait for a process handle + another handle without polling */ poll = TRUE; done = test_and_own (numobjects, handles, waitall, &count, &lowest); if (done == TRUE) { return(WAIT_OBJECT_0+lowest); } if (timeout == 0) { return WAIT_TIMEOUT; } if (timeout != INFINITE) { wait_start = mono_100ns_ticks (); timeout_in_ticks = (gint64)timeout * 10 * 1000; //can't overflow as timeout is 32bits } /* Have to wait for some or all handles to become signalled */ for (i = 0; i < numobjects; i++) { /* Add a reference, as we need to ensure the handle wont * disappear from under us while we're waiting in the loop * (not lock, as we don't want exclusive access here) */ mono_w32handle_ref (handles[i]); } while(1) { /* Prod all handles with prewait methods and * special-wait handles that aren't already signalled */ for (i = 0; i < numobjects; i++) { mono_w32handle_ops_prewait (handles[i]); if (mono_w32handle_test_capabilities (handles[i], MONO_W32HANDLE_CAP_SPECIAL_WAIT) == TRUE && mono_w32handle_issignalled (handles[i]) == FALSE) { mono_w32handle_ops_specialwait (handles[i], 0, alertable); } } MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: locking signal mutex", __func__); thr_ret = mono_w32handle_lock_signal_mutex (); g_assert (thr_ret == 0); /* Check the signalled state of handles inside the critical section */ if (waitall) { done = TRUE; for (i = 0; i < numobjects; i++) if (!mono_w32handle_issignalled (handles [i])) done = FALSE; } else { done = FALSE; for (i = 0; i < numobjects; i++) if (mono_w32handle_issignalled (handles [i])) done = TRUE; } if (!done) { /* Enter the wait */ if (timeout == INFINITE) { ret = mono_w32handle_timedwait_signal (INFINITE, poll, &apc_pending); } else { gint64 elapsed = mono_100ns_ticks () - wait_start; if (elapsed >= timeout_in_ticks) { ret = WAIT_TIMEOUT; } else { ret = mono_w32handle_timedwait_signal ((timeout_in_ticks - elapsed) / 10 / 1000, poll, &apc_pending); } } } else { /* No need to wait */ ret = 0; } MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking signal mutex", __func__); thr_ret = mono_w32handle_unlock_signal_mutex (); g_assert (thr_ret == 0); if (alertable && apc_pending) { retval = WAIT_IO_COMPLETION; break; } /* Check if everything is signalled, as we can't * guarantee to notice a shared signal even if the * wait timed out */ done = test_and_own (numobjects, handles, waitall, &count, &lowest); if (done == TRUE) { retval = WAIT_OBJECT_0+lowest; break; } else if (ret != 0) { /* Didn't get all handles, and there was a * timeout or other error */ MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: wait returned error: %s", __func__, strerror (ret)); if(ret==ETIMEDOUT) { retval = WAIT_TIMEOUT; } else { retval = WAIT_FAILED; } break; } } for (i = 0; i < numobjects; i++) { /* Unref everything we reffed above */ mono_w32handle_unref (handles[i]); } return retval; }