gdouble fval;
} LongDoubleUnion;
-typedef struct _MonoThreadDomainTls MonoThreadDomainTls;
-struct _MonoThreadDomainTls {
- MonoThreadDomainTls *next;
+typedef struct _StaticDataFreeList StaticDataFreeList;
+struct _StaticDataFreeList {
+ StaticDataFreeList *next;
guint32 offset;
guint32 size;
};
typedef struct {
int idx;
int offset;
- MonoThreadDomainTls *freelist;
+ StaticDataFreeList *freelist;
} StaticDataInfo;
/* Number of cached culture objects in the MonoThread->cached_culture_info array
static void mono_threads_unlock (void);
static mono_mutex_t threads_mutex;
-/* Controls access to context static data */
-#define mono_contexts_lock() mono_mutex_lock (&contexts_mutex)
-#define mono_contexts_unlock() mono_mutex_unlock (&contexts_mutex)
-static mono_mutex_t contexts_mutex;
-
/* Controls access to the 'joinable_threads' hash table */
#define joinable_threads_lock() mono_mutex_lock (&joinable_threads_mutex)
#define joinable_threads_unlock() mono_mutex_unlock (&joinable_threads_mutex)
*/
static MonoGHashTable *threads=NULL;
+/* List of app context GC handles.
+ * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
+ */
+static GHashTable *contexts = NULL;
+
/*
* Threads which are starting up and they are not in the 'threads' hash yet.
* When handle_store is called for a thread, it will be removed from this hash table.
#define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
static void thread_adjust_static_data (MonoInternalThread *thread);
-static void mono_free_static_data (gpointer* static_data, gboolean threadlocal);
+static void context_adjust_static_data (MonoAppContext *ctx);
+static void mono_free_static_data (gpointer* static_data);
static void mono_init_static_data_info (StaticDataInfo *static_data);
static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
static gboolean mono_thread_resume (MonoInternalThread* thread);
thread->cached_culture_info = NULL;
- mono_free_static_data (thread->static_data, TRUE);
+ mono_free_static_data (thread->static_data);
thread->static_data = NULL;
ref_stack_destroy (thread->appdomain_refs);
thread->appdomain_refs = NULL;
return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
}
+static gpointer
+get_context_static_data (MonoAppContext *ctx, guint32 offset)
+{
+ g_assert ((offset & 0x80000000) != 0);
+
+ offset &= 0x7fffffff;
+ int idx = (offset >> 24) - 1;
+
+ return ((char *) ctx->static_data [idx]) + (offset & 0xffffff);
+}
+
static MonoThread**
get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
{
mono_gc_wbarrier_generic_store_atomic (ptr, value);
}
+void
+ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
+{
+ mono_threads_lock ();
+
+ //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
+
+ if (!contexts)
+ contexts = g_hash_table_new (NULL, NULL);
+
+ context_adjust_static_data (ctx);
+ gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
+ g_hash_table_insert (contexts, gch, gch);
+
+ mono_threads_unlock ();
+}
+
void
mono_thread_init_tls (void)
{
{
mono_mutex_init_recursive(&threads_mutex);
mono_mutex_init_recursive(&interlocked_mutex);
- mono_mutex_init_recursive(&contexts_mutex);
mono_mutex_init_recursive(&joinable_threads_mutex);
background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
*/
mono_mutex_destroy (&threads_mutex);
mono_mutex_destroy (&interlocked_mutex);
- mono_mutex_destroy (&contexts_mutex);
mono_mutex_destroy (&delayed_free_table_mutex);
mono_mutex_destroy (&small_id_mutex);
CloseHandle (background_change_event);
};
#endif
-static MonoBitSet* static_reference_bitmaps [NUM_STATIC_DATA_IDX];
+static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
+static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
static void
-mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
+mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
{
gpointer *static_data = addr;
if (!ptr)
continue;
- MONO_BITSET_FOREACH (static_reference_bitmaps [i], idx, {
+ MONO_BITSET_FOREACH (bitmaps [i], idx, {
void **p = ptr + idx;
if (*p)
}
}
+static void
+mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
+{
+ mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
+}
+
+static void
+mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
+{
+ mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
+}
+
/*
* mono_alloc_static_data
*
gpointer* static_data = *static_data_ptr;
if (!static_data) {
- static void* tls_desc = NULL;
- if (mono_gc_user_markers_supported () && !tls_desc)
- tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
- static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal?tls_desc:NULL);
+ static void *tls_desc = NULL;
+ static void *ctx_desc = NULL;
+
+ if (mono_gc_user_markers_supported ()) {
+ if (!tls_desc)
+ tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
+
+ if (!ctx_desc)
+ ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
+ }
+
+ static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc);
*static_data_ptr = static_data;
static_data [0] = static_data;
}
for (i = 1; i <= idx; ++i) {
if (static_data [i])
continue;
- if (mono_gc_user_markers_supported () && threadlocal)
+
+ if (mono_gc_user_markers_supported ())
static_data [i] = g_malloc0 (static_data_size [i]);
else
static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
}
static void
-mono_free_static_data (gpointer* static_data, gboolean threadlocal)
+mono_free_static_data (gpointer* static_data)
{
int i;
for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
* At this point, the static data pointer array is still registered with the
* GC, so must ensure that mark_tls_slots() will not encounter any invalid
* data. Freeing the individual arrays without first nulling their slots
- * would make it possible for mark_tls_slots() to encounter a pointer to
+ * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
* such an already freed array. See bug #13813.
*/
static_data [i] = NULL;
mono_memory_write_barrier ();
- if (mono_gc_user_markers_supported () && threadlocal)
+ if (mono_gc_user_markers_supported ())
g_free (p);
else
mono_gc_free_fixed (p);
mono_threads_unlock ();
}
+static void
+context_adjust_static_data (MonoAppContext *ctx)
+{
+ guint32 offset;
+
+ mono_threads_lock ();
+
+ if (context_static_info.offset || context_static_info.idx > 0) {
+ offset = context_static_info.offset | ((context_static_info.idx + 1) << 24);
+ mono_alloc_static_data (&ctx->static_data, offset, FALSE);
+ }
+
+ mono_threads_unlock ();
+}
+
+/*
+ * LOCKING: requires that threads_mutex is held
+ */
static void
alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
{
mono_alloc_static_data (&(thread->static_data), offset, TRUE);
}
-static MonoThreadDomainTls*
-search_tls_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
+/*
+ * LOCKING: requires that threads_mutex is held
+ */
+static void
+alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
{
- MonoThreadDomainTls* prev = NULL;
- MonoThreadDomainTls* tmp = static_data->freelist;
+ uint32_t gch = GPOINTER_TO_INT (key);
+ MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
+
+ if (!ctx) {
+ g_hash_table_remove (contexts, key);
+ mono_gchandle_free (gch);
+ return;
+ }
+
+ guint32 offset = GPOINTER_TO_UINT (user);
+ mono_alloc_static_data (&ctx->static_data, offset, FALSE);
+}
+
+static StaticDataFreeList*
+search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
+{
+ StaticDataFreeList* prev = NULL;
+ StaticDataFreeList* tmp = static_data->freelist;
while (tmp) {
if (tmp->size == size) {
if (prev)
#endif
static void
-update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int numbits)
+update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
{
- int i;
int idx = (offset >> 24) - 1;
- if (!static_reference_bitmaps [idx])
- static_reference_bitmaps [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
- MonoBitSet *rb = static_reference_bitmaps [idx];
+ if (!sets [idx])
+ sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
+ MonoBitSet *rb = sets [idx];
offset &= 0xffffff;
- offset /= sizeof (gpointer);
+ offset /= sizeof (uintptr_t);
/* offset is now the bitmap offset */
- for (i = 0; i < numbits; ++i) {
+ for (int i = 0; i < numbits; ++i) {
if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
mono_bitset_set_fast (rb, offset + i);
}
}
static void
-clear_reference_bitmap (guint32 offset, guint32 size)
+clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
{
int idx = (offset >> 24) - 1;
- MonoBitSet *rb = static_reference_bitmaps [idx];
+ MonoBitSet *rb = sets [idx];
offset &= 0xffffff;
- offset /= sizeof (gpointer);
- size /= sizeof (gpointer);
- size += offset;
+ offset /= sizeof (uintptr_t);
/* offset is now the bitmap offset */
- for (; offset < size; ++offset)
- mono_bitset_clear_fast (rb, offset);
+ for (int i = 0; i < size / sizeof (uintptr_t); i++)
+ mono_bitset_clear_fast (rb, offset + i);
}
/*
guint32
mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
{
+ g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
+
+ StaticDataInfo *info;
+ MonoBitSet **sets;
+
+ if (static_type == SPECIAL_STATIC_THREAD) {
+ info = &thread_static_info;
+ sets = thread_reference_bitmaps;
+ } else {
+ info = &context_static_info;
+ sets = context_reference_bitmaps;
+ }
+
+ mono_threads_lock ();
+
+ StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
guint32 offset;
+
+ if (item) {
+ offset = item->offset;
+ g_free (item);
+ } else {
+ offset = mono_alloc_static_data_slot (info, size, align);
+ }
+
+ update_reference_bitmap (sets, offset, bitmap, numbits);
+
if (static_type == SPECIAL_STATIC_THREAD) {
- MonoThreadDomainTls *item;
- mono_threads_lock ();
- item = search_tls_slot_in_freelist (&thread_static_info, size, align);
- /*g_print ("TLS alloc: %d in domain %p (total: %d), cached: %p\n", size, mono_domain_get (), thread_static_info.offset, item);*/
- if (item) {
- offset = item->offset;
- g_free (item);
- } else {
- offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
- }
- update_tls_reference_bitmap (offset, bitmap, numbits);
/* This can be called during startup */
if (threads != NULL)
mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
- mono_threads_unlock ();
} else {
- g_assert (static_type == SPECIAL_STATIC_CONTEXT);
- mono_contexts_lock ();
- offset = mono_alloc_static_data_slot (&context_static_info, size, align);
- mono_contexts_unlock ();
- offset |= 0x80000000; /* Set the high bit to indicate context static data */
+ if (contexts != NULL)
+ g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
+
+ offset |= 0x80000000; /* Set the high bit to indicate context static data */
}
+
+ mono_threads_unlock ();
+
return offset;
}
/* The high bit means either thread (0) or static (1) data. */
guint32 static_type = (offset & 0x80000000);
- int idx;
-
- offset &= 0x7fffffff;
- idx = (offset >> 24) - 1;
if (static_type == 0) {
return get_thread_static_data (thread, offset);
} else {
- /* Allocate static data block under demand, since we don't have a list
- // of contexts
- */
- MonoAppContext *context = mono_context_get ();
- if (!context->static_data || !context->static_data [idx]) {
- mono_contexts_lock ();
- mono_alloc_static_data (&(context->static_data), offset, FALSE);
- mono_contexts_unlock ();
- }
- return ((char*) context->static_data [idx]) + (offset & 0xffffff);
+ return get_context_static_data (thread->current_appcontext, offset);
}
}
typedef struct {
guint32 offset;
guint32 size;
-} TlsOffsetSize;
+} OffsetSize;
+/*
+ * LOCKING: requires that threads_mutex is held
+ */
static void
free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
{
MonoInternalThread *thread = value;
- TlsOffsetSize *data = user;
+ OffsetSize *data = user;
int idx = (data->offset >> 24) - 1;
char *ptr;
mono_gc_bzero_atomic (ptr, data->size);
}
+/*
+ * LOCKING: requires that threads_mutex is held
+ */
+static void
+free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
+{
+ uint32_t gch = GPOINTER_TO_INT (key);
+ MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
+
+ if (!ctx) {
+ g_hash_table_remove (contexts, key);
+ mono_gchandle_free (gch);
+ return;
+ }
+
+ OffsetSize *data = user;
+ int idx = (data->offset >> 24) - 1;
+ char *ptr;
+
+ if (!ctx->static_data || !ctx->static_data [idx])
+ return;
+
+ ptr = ((char*) ctx->static_data [idx]) + (data->offset & 0xffffff);
+ mono_gc_bzero_atomic (ptr, data->size);
+}
+
static void
do_free_special_slot (guint32 offset, guint32 size)
{
guint32 static_type = (offset & 0x80000000);
- /*g_print ("free %s , size: %d, offset: %x\n", field->name, size, offset);*/
+ MonoBitSet **sets;
+ StaticDataInfo *info;
+
+ if (static_type == 0) {
+ info = &thread_static_info;
+ sets = thread_reference_bitmaps;
+ } else {
+ info = &context_static_info;
+ sets = context_reference_bitmaps;
+ }
+
+ OffsetSize data = { offset & 0x7fffffff, size };
+ clear_reference_bitmap (sets, data.offset, data.size);
+
if (static_type == 0) {
- TlsOffsetSize data;
- MonoThreadDomainTls *item = g_new0 (MonoThreadDomainTls, 1);
- data.offset = offset & 0x7fffffff;
- data.size = size;
- clear_reference_bitmap (data.offset, data.size);
if (threads != NULL)
mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
+ } else {
+ if (contexts != NULL)
+ g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
+ }
+
+ if (!mono_runtime_is_shutting_down ()) {
+ StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
+
item->offset = offset;
item->size = size;
- if (!mono_runtime_is_shutting_down ()) {
- item->next = thread_static_info.freelist;
- thread_static_info.freelist = item;
- } else {
- /* We could be called during shutdown after mono_thread_cleanup () is called */
- g_free (item);
- }
- } else {
- /* FIXME: free context static data as well */
+ item->next = info->freelist;
+ info->freelist = item;
}
}
mono_alloc_special_static_data_free (GHashTable *special_static_fields)
{
mono_threads_lock ();
+
g_hash_table_foreach (special_static_fields, do_free_special, NULL);
+
mono_threads_unlock ();
}
-void
+static void
mono_special_static_data_free_slot (guint32 offset, guint32 size)
{
+ /* Only ever called for ThreadLocal instances */
+ g_assert ((offset & 0x80000000) == 0);
+
mono_threads_lock ();
do_free_special_slot (offset, size);
mono_threads_unlock ();