return small_id;
}
+static void
+thread_handle_destroy (gpointer data)
+{
+ MonoThreadHandle *thread_handle;
+
+ thread_handle = (MonoThreadHandle*) data;
+
+ mono_os_event_destroy (&thread_handle->event);
+ g_free (thread_handle);
+}
+
static void*
register_thread (MonoThreadInfo *info, gpointer baseptr)
{
info->small_id = small_id;
info->handle = g_new0 (MonoThreadHandle, 1);
- info->handle->ref = 1;
+ mono_refcount_init (info->handle, thread_handle_destroy);
mono_os_event_init (&info->handle->event, FALSE);
mono_os_sem_init (&info->resume_semaphore, 0);
}
typedef struct {
- gint32 ref;
+ MonoRefCount ref;
MonoThreadStart start_routine;
gpointer start_routine_arg;
- gint32 priority;
MonoCoopSem registered;
MonoThreadHandle *handle;
} CreateThreadData;
+static void
+create_thread_data_destroy (gpointer data)
+{
+ CreateThreadData *thread_data;
+
+ thread_data = (CreateThreadData*) data;
+
+ mono_coop_sem_destroy (&thread_data->registered);
+ g_free (thread_data);
+}
+
static gsize WINAPI
inner_start_thread (gpointer data)
{
mono_coop_sem_post (&thread_data->registered);
- if (InterlockedDecrement (&thread_data->ref) == 0) {
- mono_coop_sem_destroy (&thread_data->registered);
- g_free (thread_data);
- }
+ mono_refcount_dec (thread_data);
/* thread_data is not valid anymore */
thread_data = NULL;
MonoThreadHandle *ret;
thread_data = g_new0 (CreateThreadData, 1);
- thread_data->ref = 2;
+ mono_refcount_init (thread_data, create_thread_data_destroy);
thread_data->start_routine = start;
thread_data->start_routine_arg = arg;
mono_coop_sem_init (&thread_data->registered, 0);
- res = mono_threads_platform_create_thread (inner_start_thread, (gpointer) thread_data, stack_size, out_tid);
+ res = mono_threads_platform_create_thread (inner_start_thread, (gpointer) mono_refcount_inc (thread_data), stack_size, out_tid);
if (res != 0) {
/* ref is not going to be decremented in inner_start_thread */
- InterlockedDecrement (&thread_data->ref);
+ mono_refcount_dec (thread_data);
ret = NULL;
goto done;
}
g_assert (ret);
done:
- if (InterlockedDecrement (&thread_data->ref) == 0) {
- mono_coop_sem_destroy (&thread_data->registered);
- g_free (thread_data);
- }
+ mono_refcount_dec (thread_data);
return ret;
}
MonoThreadHandle*
mono_threads_open_thread_handle (MonoThreadHandle *thread_handle)
{
- guint32 oldref, newref;
-
- g_assert (thread_handle);
-
- do {
- oldref = thread_handle->ref;
- if (!(oldref >= 1))
- g_error ("%s: thread_handle %p has ref %u, it should be >= 1", __func__, thread_handle, oldref);
-
- newref = oldref + 1;
- } while (InterlockedCompareExchange ((gint32*) &thread_handle->ref, newref, oldref) != oldref);
-
- return thread_handle;
+ return mono_refcount_inc (thread_handle);
}
void
mono_threads_close_thread_handle (MonoThreadHandle *thread_handle)
{
- guint32 oldref, newref;
-
- g_assert (thread_handle);
-
- do {
- oldref = thread_handle->ref;
- if (!(oldref >= 1))
- g_error ("%s: thread_handle %p has ref %u, it should be >= 1", __func__, thread_handle, oldref);
-
- newref = oldref - 1;
- } while (InterlockedCompareExchange ((gint32*) &thread_handle->ref, newref, oldref) != oldref);
-
- if (newref == 0) {
- mono_os_event_destroy (&thread_handle->event);
- g_free (thread_handle);
- }
+ mono_refcount_dec (thread_handle);
}
static void
--- /dev/null
+
+#ifndef __MONO_UTILS_REFCOUNT_H__
+#define __MONO_UTILS_REFCOUNT_H__
+
+#include <glib.h>
+#include <config.h>
+
+#include "atomic.h"
+
+/*
+ * Mechanism for ref-counting which tries to be as user-friendly as possible. Instead of being a wrapper around
+ * user-provided data, it is embedded into the user data.
+ *
+ * This introduces some constraints on the MonoRefCount field:
+ * - it needs to be called "ref"
+ * - it cannot be a pointer
+ */
+
+typedef struct {
+ guint32 ref;
+ void (*destructor) (gpointer data);
+} MonoRefCount;
+
+#define mono_refcount_init(v,destructor) do { mono_refcount_initialize (&(v)->ref, (destructor)); } while (0)
+#define mono_refcount_inc(v) (mono_refcount_increment (&(v)->ref),(v))
+#define mono_refcount_dec(v) do { mono_refcount_decrement (&(v)->ref); } while (0)
+
+static inline void
+mono_refcount_initialize (MonoRefCount *refcount, void (*destructor) (gpointer data))
+{
+ refcount->ref = 1;
+ refcount->destructor = destructor;
+}
+
+static inline void
+mono_refcount_increment (MonoRefCount *refcount)
+{
+ guint32 oldref, newref;
+
+ g_assert (refcount);
+
+ do {
+ oldref = refcount->ref;
+ if (oldref == 0)
+ g_error ("%s: cannot increment a ref with value 0", __func__);
+
+ newref = oldref + 1;
+ } while (InterlockedCompareExchange ((gint32*) &refcount->ref, newref, oldref) != oldref);
+}
+
+static inline void
+mono_refcount_decrement (MonoRefCount *refcount)
+{
+ guint32 oldref, newref;
+
+ g_assert (refcount);
+
+ do {
+ oldref = refcount->ref;
+ if (oldref == 0)
+ g_error ("%s: cannot decrement a ref with value 0", __func__);
+
+ newref = oldref - 1;
+ } while (InterlockedCompareExchange ((gint32*) &refcount->ref, newref, oldref) != oldref);
+
+ if (newref == 0 && refcount->destructor)
+ refcount->destructor ((gpointer) refcount);
+}
+
+#endif /* __MONO_UTILS_REFCOUNT_H__ */