/* must be a power of 2 */
#define HANDLE_PER_SLOT (256)
-#define INFINITE 0xFFFFFFFF
-
typedef struct {
MonoW32HandleType type;
guint ref;
}
/*
- * wapi_init:
+ * mono_w32handle_init:
*
* Initialize the io-layer.
*/
mono_w32handle_ref_core (gpointer handle, MonoW32HandleBase *handle_data);
static gboolean
-mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data, guint minimum);
+mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data);
+
+static void
+w32handle_destroy (gpointer handle);
void
mono_w32handle_foreach (gboolean (*on_each)(gpointer handle, gpointer data, gpointer user_data), gpointer user_data)
{
+ GPtrArray *handles_to_destroy;
guint32 i, k;
+ handles_to_destroy = NULL;
+
mono_os_mutex_lock (&scan_mutex);
for (i = SLOT_INDEX (0); i < private_handles_slots_count; i++) {
finished = on_each (handle, handle_data->specific, user_data);
- /* we do not want to have to destroy the handle here,
- * as it would means the ref/unref are unbalanced */
- destroy = mono_w32handle_unref_core (handle, handle_data, 2);
- g_assert (!destroy);
+ /* we might have to destroy the handle here, as
+ * it could have been unrefed in another thread */
+ destroy = mono_w32handle_unref_core (handle, handle_data);
+ if (destroy) {
+ /* we do not destroy it while holding the scan_mutex
+ * lock, because w32handle_destroy also needs to take
+ * the lock, and it calls user code which might lead
+ * to a deadlock */
+ if (!handles_to_destroy)
+ handles_to_destroy = g_ptr_array_sized_new (4);
+ g_ptr_array_add (handles_to_destroy, handle);
+ }
if (finished)
goto done;
done:
mono_os_mutex_unlock (&scan_mutex);
+
+ if (handles_to_destroy) {
+ for (i = 0; i < handles_to_destroy->len; ++i)
+ w32handle_destroy (handles_to_destroy->pdata [i]);
+
+ g_ptr_array_free (handles_to_destroy, TRUE);
+ }
}
static gboolean
}
static gboolean
-mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data, guint minimum)
+mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data)
{
MonoW32HandleType type;
guint old, new;
do {
old = handle_data->ref;
- if (!(old >= minimum))
- g_error ("%s: handle %p has ref %d, it should be >= %d", __func__, handle, old, minimum);
+ if (!(old >= 1))
+ g_error ("%s: handle %p has ref %d, it should be >= 1", __func__, handle, old);
new = old - 1;
} while (InterlockedCompareExchange ((gint32*) &handle_data->ref, new, old) != old);
static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer, gpointer);
-/* The handle must not be locked on entry to this function */
-void
-mono_w32handle_unref (gpointer handle)
+static void
+w32handle_destroy (gpointer handle)
{
+ /* Need to copy the handle info, reset the slot in the
+ * array, and _only then_ call the close function to
+ * avoid race conditions (eg file descriptors being
+ * closed, and another file being opened getting the
+ * same fd racing the memset())
+ */
MonoW32HandleBase *handle_data;
- gboolean destroy;
+ MonoW32HandleType type;
+ gpointer handle_specific;
+ void (*close_func)(gpointer, gpointer);
- if (!mono_w32handle_lookup_data (handle, &handle_data)) {
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to unref handle %p, unknown handle",
- __func__, handle);
- return;
- }
+ if (!mono_w32handle_lookup_data (handle, &handle_data))
+ g_error ("%s: unknown handle %p", __func__, handle);
- destroy = mono_w32handle_unref_core (handle, handle_data, 1);
+ type = handle_data->type;
+ handle_specific = handle_data->specific;
- if (destroy) {
- /* Need to copy the handle info, reset the slot in the
- * array, and _only then_ call the close function to
- * avoid race conditions (eg file descriptors being
- * closed, and another file being opened getting the
- * same fd racing the memset())
- */
- MonoW32HandleType type;
- gpointer handle_specific;
- void (*close_func)(gpointer, gpointer);
+ mono_os_mutex_lock (&scan_mutex);
- type = handle_data->type;
- handle_specific = handle_data->specific;
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: destroy %s handle %p", __func__, mono_w32handle_ops_typename (type), handle);
- mono_os_mutex_lock (&scan_mutex);
+ mono_os_mutex_destroy (&handle_data->signal_mutex);
+ mono_os_cond_destroy (&handle_data->signal_cond);
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: destroy %s handle %p", __func__, mono_w32handle_ops_typename (type), handle);
+ memset (handle_data, 0, sizeof (MonoW32HandleBase));
- mono_os_mutex_destroy (&handle_data->signal_mutex);
- mono_os_cond_destroy (&handle_data->signal_cond);
+ mono_os_mutex_unlock (&scan_mutex);
- memset (handle_data, 0, sizeof (MonoW32HandleBase));
+ close_func = _wapi_handle_ops_get_close_func (type);
+ if (close_func != NULL) {
+ close_func (handle, handle_specific);
+ }
- mono_os_mutex_unlock (&scan_mutex);
+ g_free (handle_specific);
+}
- close_func = _wapi_handle_ops_get_close_func (type);
- if (close_func != NULL) {
- close_func (handle, handle_specific);
- }
+/* The handle must not be locked on entry to this function */
+void
+mono_w32handle_unref (gpointer handle)
+{
+ MonoW32HandleBase *handle_data;
+ gboolean destroy;
- g_free (handle_specific);
+ if (!mono_w32handle_lookup_data (handle, &handle_data)) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to unref handle %p, unknown handle",
+ __func__, handle);
+ return;
}
+
+ destroy = mono_w32handle_unref_core (handle, handle_data);
+ if (destroy)
+ w32handle_destroy (handle);
}
static void
}
static gboolean
-mono_w32handle_ops_own (gpointer handle, guint32 *statuscode)
+mono_w32handle_ops_own (gpointer handle, gboolean *abandoned)
{
MonoW32HandleBase *handle_data;
MonoW32HandleType type;
type = handle_data->type;
if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
- return(handle_ops[type]->own_handle (handle, statuscode));
+ return(handle_ops[type]->own_handle (handle, abandoned));
} else {
return(FALSE);
}
MonoW32HandleType type;
if (!mono_w32handle_lookup_data (handle, &handle_data)) {
- return(WAIT_FAILED);
+ return MONO_W32HANDLE_WAIT_RET_FAILED;
}
type = handle_data->type;
handle_ops[type]->special_wait != NULL) {
return(handle_ops[type]->special_wait (handle, timeout, alerted));
} else {
- return(WAIT_FAILED);
+ return MONO_W32HANDLE_WAIT_RET_FAILED;
}
}
if (!mono_w32handle_trylock_handle (handle)) {
/* Bummer */
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: attempt failed for %p: %s", __func__,
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: attempt failed for %p.", __func__,
handle);
while (i--) {
}
static gboolean
-own_if_signalled (gpointer handle, guint32 *statuscode)
+own_if_signalled (gpointer handle, gboolean *abandoned)
{
if (!mono_w32handle_issignalled (handle))
return FALSE;
- *statuscode = WAIT_OBJECT_0;
- mono_w32handle_ops_own (handle, statuscode);
+ *abandoned = FALSE;
+ mono_w32handle_ops_own (handle, abandoned);
return TRUE;
}
static gboolean
-own_if_owned( gpointer handle, guint32 *statuscode)
+own_if_owned( gpointer handle, gboolean *abandoned)
{
if (!mono_w32handle_ops_isowned (handle))
return FALSE;
- *statuscode = WAIT_OBJECT_0;
- mono_w32handle_ops_own (handle, statuscode);
+ *abandoned = FALSE;
+ mono_w32handle_ops_own (handle, abandoned);
return TRUE;
}
MonoW32HandleWaitRet ret;
gboolean alerted;
gint64 start;
- guint32 statuscode = 0;
+ gboolean abandoned = FALSE;
alerted = FALSE;
mono_w32handle_lock_handle (handle);
if (mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_OWN)) {
- if (own_if_owned (handle, &statuscode)) {
+ if (own_if_owned (handle, &abandoned)) {
mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p already owned",
__func__, handle);
- ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
+ ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
goto done;
}
}
- if (timeout != INFINITE)
+ if (timeout != MONO_INFINITE_WAIT)
start = mono_msec_ticks ();
for (;;) {
gint waited;
- if (own_if_signalled (handle, &statuscode)) {
+ if (own_if_signalled (handle, &abandoned)) {
mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p signalled",
__func__, handle);
- ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
+ ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
goto done;
}
mono_w32handle_ops_prewait (handle);
- if (timeout == INFINITE) {
- waited = mono_w32handle_timedwait_signal_handle (handle, INFINITE, FALSE, alertable ? &alerted : NULL);
+ if (timeout == MONO_INFINITE_WAIT) {
+ waited = mono_w32handle_timedwait_signal_handle (handle, MONO_INFINITE_WAIT, FALSE, alertable ? &alerted : NULL);
} else {
gint64 elapsed;
gint i;
gint64 start;
gpointer handles_sorted [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
- guint32 statuscodes [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS] = {0};
+ gboolean abandoned [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS] = {0};
if (nhandles == 0)
return MONO_W32HANDLE_WAIT_RET_FAILED;
}
}
- if (timeout != INFINITE)
+ if (timeout != MONO_INFINITE_WAIT)
start = mono_msec_ticks ();
for (i = 0; i < nhandles; ++i) {
if (signalled) {
for (i = 0; i < nhandles; i++)
- own_if_signalled (handles [i], &statuscodes [i]);
+ own_if_signalled (handles [i], &abandoned [i]);
}
mono_w32handle_unlock_handles (handles, nhandles);
if (signalled) {
ret = MONO_W32HANDLE_WAIT_RET_SUCCESS_0 + lowest;
for (i = lowest; i < nhandles; i++) {
- if (statuscodes [i] == WAIT_ABANDONED_0) {
+ if (abandoned [i]) {
ret = MONO_W32HANDLE_WAIT_RET_ABANDONED_0 + lowest;
break;
}
waited = 0;
if (!signalled) {
- if (timeout == INFINITE) {
- waited = mono_w32handle_timedwait_signal (INFINITE, poll, alertable ? &alerted : NULL);
+ if (timeout == MONO_INFINITE_WAIT) {
+ waited = mono_w32handle_timedwait_signal (MONO_INFINITE_WAIT, poll, alertable ? &alerted : NULL);
} else {
gint64 elapsed;
MonoW32HandleWaitRet ret;
gint64 start;
gboolean alerted;
- guint32 statuscode = 0;
+ gboolean abandoned = FALSE;
gpointer handles [2];
alerted = FALSE;
mono_w32handle_unlock_handle (signal_handle);
if (mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_OWN)) {
- if (own_if_owned (wait_handle, &statuscode)) {
+ if (own_if_owned (wait_handle, &abandoned)) {
mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p already owned",
__func__, wait_handle);
- ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
+ ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
goto done;
}
}
- if (timeout != INFINITE)
+ if (timeout != MONO_INFINITE_WAIT)
start = mono_msec_ticks ();
for (;;) {
gint waited;
- if (own_if_signalled (wait_handle, &statuscode)) {
+ if (own_if_signalled (wait_handle, &abandoned)) {
mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p signalled",
__func__, wait_handle);
- ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
+ ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
goto done;
}
mono_w32handle_ops_prewait (wait_handle);
- if (timeout == INFINITE) {
- waited = mono_w32handle_timedwait_signal_handle (wait_handle, INFINITE, FALSE, alertable ? &alerted : NULL);
+ if (timeout == MONO_INFINITE_WAIT) {
+ waited = mono_w32handle_timedwait_signal_handle (wait_handle, MONO_INFINITE_WAIT, FALSE, alertable ? &alerted : NULL);
} else {
gint64 elapsed;