#include <signal.h>
#include <string.h>
+#if defined(__OpenBSD__)
+#include <pthread.h>
+#include <pthread_np.h>
+#endif
+
#include <mono/metadata/object.h>
#include <mono/metadata/domain-internals.h>
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/gc-internal.h>
#include <mono/metadata/marshal.h>
#include <mono/io-layer/io-layer.h>
-#ifndef PLATFORM_WIN32
+#ifndef HOST_WIN32
#include <mono/io-layer/threads.h>
#endif
#include <mono/metadata/object-internals.h>
#include <mono/metadata/gc-internal.h>
+#ifdef PLATFORM_ANDROID
+#include <errno.h>
+
+extern int tkill (pid_t tid, int signal);
+#endif
+
/*#define THREAD_DEBUG(a) do { a; } while (0)*/
#define THREAD_DEBUG(a)
/*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
/*#define LIBGC_DEBUG(a) do { a; } while (0)*/
#define LIBGC_DEBUG(a)
+#define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
+#define SPIN_LOCK(i) do { \
+ if (SPIN_TRYLOCK (i)) \
+ break; \
+ } while (1)
+
+#define SPIN_UNLOCK(i) i = 0
+
/* Provide this for systems with glib < 2.6 */
#ifndef G_GSIZE_FORMAT
# if GLIB_SIZEOF_LONG == 8
#define GET_CURRENT_OBJECT() tls_current_object
#else
#define SET_CURRENT_OBJECT(x) TlsSetValue (current_object_key, x)
-#define GET_CURRENT_OBJECT() (MonoThread*) TlsGetValue (current_object_key)
+#define GET_CURRENT_OBJECT() (MonoInternalThread*) TlsGetValue (current_object_key)
#endif
/* function called at thread start */
#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 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);
static MonoInternalThread **small_id_table = NULL;
/* The hazard table */
+#if MONO_SMALL_CONFIG
+#define HAZARD_TABLE_MAX_SIZE 256
+#else
#define HAZARD_TABLE_MAX_SIZE 16384 /* There cannot be more threads than this number. */
+#endif
static volatile int hazard_table_size = 0;
static MonoThreadHazardPointers * volatile hazard_table = NULL;
}
if(threads==NULL) {
- MONO_GC_REGISTER_ROOT (threads);
+ MONO_GC_REGISTER_ROOT_FIXED (threads);
threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
}
if (!small_id_table) {
small_id_table_size = 2;
+ /*
+ * Enabling this causes problems, because SGEN doesn't track/update the TLS slot holding
+ * the current thread.
+ */
+ //small_id_table = mono_gc_alloc_fixed (small_id_table_size * sizeof (MonoInternalThread*), mono_gc_make_root_descr_all_refs (small_id_table_size));
small_id_table = mono_gc_alloc_fixed (small_id_table_size * sizeof (MonoInternalThread*), NULL);
}
for (i = small_id_next; i < small_id_table_size; ++i) {
if (new_size >= (1 << 16))
g_assert_not_reached ();
id = small_id_table_size;
+ //new_table = mono_gc_alloc_fixed (new_size * sizeof (MonoInternalThread*), mono_gc_make_root_descr_all_refs (new_size));
new_table = mono_gc_alloc_fixed (new_size * sizeof (MonoInternalThread*), NULL);
memcpy (new_table, small_id_table, small_id_table_size * sizeof (void*));
mono_gc_free_fixed (small_id_table);
if (small_id_next > small_id_table_size)
small_id_next = 0;
+ g_assert (id < HAZARD_TABLE_MAX_SIZE);
if (id >= hazard_table_size) {
+#if MONO_SMALL_CONFIG
+ hazard_table = g_malloc0 (sizeof (MonoThreadHazardPointers) * HAZARD_TABLE_MAX_SIZE);
+ hazard_table_size = HAZARD_TABLE_MAX_SIZE;
+#else
gpointer page_addr;
int pagesize = mono_pagesize ();
int num_pages = (hazard_table_size * sizeof (MonoThreadHazardPointers) + pagesize - 1) / pagesize;
g_assert (hazard_table != NULL);
page_addr = (guint8*)hazard_table + num_pages * pagesize;
- g_assert (id < HAZARD_TABLE_MAX_SIZE);
-
mono_mprotect (page_addr, pagesize, MONO_MMAP_READ | MONO_MMAP_WRITE);
++num_pages;
hazard_table_size = num_pages * pagesize / sizeof (MonoThreadHazardPointers);
+#endif
g_assert (id < hazard_table_size);
-
hazard_table [id].hazard_pointers [0] = NULL;
hazard_table [id].hazard_pointers [1] = NULL;
}
g_assert (thread != NULL);
if (thread->abort_state_handle) {
- g_assert (thread->abort_exc);
mono_gchandle_free (thread->abort_state_handle);
thread->abort_state_handle = 0;
}
}
/* if the thread is not in the hash it has been removed already */
- if (!handle_remove (thread))
+ if (!handle_remove (thread)) {
+ /* This needs to be called even if handle_remove () fails */
+ if (mono_thread_cleanup_fn)
+ mono_thread_cleanup_fn (thread);
return;
+ }
mono_release_type_locks (thread);
EnterCriticalSection (thread->synch_cs);
if (thread == mono_thread_internal_current ())
mono_thread_pop_appdomain_ref ();
- if (thread->serialized_culture_info)
- g_free (thread->serialized_culture_info);
-
- if (thread->serialized_ui_culture_info)
- g_free (thread->serialized_ui_culture_info);
-
thread->cached_culture_info = NULL;
- mono_gc_free_fixed (thread->static_data);
+ mono_free_static_data (thread->static_data, TRUE);
thread->static_data = NULL;
if (mono_thread_cleanup_fn)
- mono_thread_cleanup_fn (thread->root_domain_thread);
+ mono_thread_cleanup_fn (thread);
small_id_free (thread->small_id);
thread->small_id = -2;
+
}
static gpointer
*current_thread_ptr = current;
}
+static MonoInternalThread*
+create_internal_thread_object (void)
+{
+ MonoVTable *vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
+ return (MonoInternalThread*)mono_gc_alloc_mature (vt);
+}
+
+static MonoThread*
+create_thread_object (MonoDomain *domain)
+{
+ MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
+ return (MonoThread*)mono_gc_alloc_mature (vt);
+}
+
static MonoThread*
new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
{
- MonoThread *thread = (MonoThread*) mono_object_new (domain, mono_defaults.thread_class);
- thread->internal_thread = internal;
+ MonoThread *thread = create_thread_object (domain);
+ MONO_OBJECT_SETREF (thread, internal_thread, internal);
return thread;
}
candidate = new_thread_with_internal (domain, thread);
set_current_thread_for_domain (domain, thread, candidate);
g_assert (!thread->root_domain_thread);
- thread->root_domain_thread = candidate;
+ MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
}
-static guint32 WINAPI start_wrapper(void *data)
+static guint32 WINAPI start_wrapper_internal(void *data)
{
struct StartInfo *start_info=(struct StartInfo *)data;
guint32 (*start_func)(void *);
void *start_arg;
gsize tid;
- MonoThread *thread=start_info->obj;
- MonoInternalThread *internal = thread->internal_thread;
+ /*
+ * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
+ * GC stack walk.
+ */
+ MonoInternalThread *internal = start_info->obj->internal_thread;
MonoObject *start_delegate = start_info->delegate;
+ MonoDomain *domain = start_info->obj->obj.vtable->domain;
THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
mono_monitor_init_tls ();
/* Every thread references the appdomain which created it */
- mono_thread_push_appdomain_ref (thread->obj.vtable->domain);
+ mono_thread_push_appdomain_ref (domain);
- if (!mono_domain_set (thread->obj.vtable->domain, FALSE)) {
+ if (!mono_domain_set (domain, FALSE)) {
/* No point in raising an appdomain_unloaded exception here */
/* FIXME: Cleanup here */
mono_thread_pop_appdomain_ref ();
/* We have to do this here because mono_thread_new_init()
requires that root_domain_thread is set up. */
thread_adjust_static_data (internal);
- init_root_domain_thread (internal, thread);
+ init_root_domain_thread (internal, start_info->obj);
/* This MUST be called before any managed code can be
* executed, as it calls the callback function that (for the
THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
- mono_profiler_thread_start (tid);
-
/* On 2.0 profile (and higher), set explicitly since state might have been
Unknown */
- if (mono_framework_version () != 1) {
- if (internal->apartment_state == ThreadApartmentState_Unknown)
- internal->apartment_state = ThreadApartmentState_MTA;
- }
+ if (internal->apartment_state == ThreadApartmentState_Unknown)
+ internal->apartment_state = ThreadApartmentState_MTA;
mono_thread_init_apartment_state ();
}
mono_threads_lock ();
- mono_g_hash_table_remove (thread_start_args, thread);
+ mono_g_hash_table_remove (thread_start_args, start_info->obj);
mono_threads_unlock ();
+ mono_thread_set_execution_context (start_info->obj->ec_to_set);
+ start_info->obj->ec_to_set = NULL;
+
g_free (start_info);
#ifdef DEBUG
g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
thread->tid);
#endif
- mono_thread_set_execution_context (thread->ec_to_set);
- thread->ec_to_set = NULL;
+ /*
+ * Call this after calling start_notify, since the profiler callback might want
+ * to lock the thread, and the lock is held by thread_start () which waits for
+ * start_notify.
+ */
+ mono_profiler_thread_start (tid);
/* start_func is set only for unmanaged start functions */
if (start_func) {
* to TLS data.)
*/
SET_CURRENT_OBJECT (NULL);
+ mono_domain_unset ();
return(0);
}
-void mono_thread_new_init (gsize tid, gpointer stack_start, gpointer func)
+static guint32 WINAPI start_wrapper(void *data)
+{
+#ifdef HAVE_SGEN_GC
+ volatile int dummy;
+
+ /* Avoid scanning the frames above this frame during a GC */
+ mono_gc_set_stack_end ((void*)&dummy);
+#endif
+
+ return start_wrapper_internal (data);
+}
+
+void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
{
if (mono_thread_start_cb) {
mono_thread_start_cb (tid, stack_start, func);
{
gpointer res;
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
DWORD real_tid;
res = CreateThread (security, stacksize, start, param, create, &real_tid);
return res;
}
+/*
+ * The thread start argument may be an object reference, and there is
+ * no ref to keep it alive when the new thread is started but not yet
+ * registered with the collector. So we store it in a GC tracked hash
+ * table.
+ *
+ * LOCKING: Assumes the threads lock is held.
+ */
+static void
+register_thread_start_argument (MonoThread *thread, struct StartInfo *start_info)
+{
+ if (thread_start_args == NULL) {
+ MONO_GC_REGISTER_ROOT_FIXED (thread_start_args);
+ thread_start_args = mono_g_hash_table_new (NULL, NULL);
+ }
+ mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
+}
+
MonoInternalThread* mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread)
{
MonoThread *thread;
struct StartInfo *start_info;
gsize tid;
- thread=(MonoThread *)mono_object_new (domain,
- mono_defaults.thread_class);
- internal = (MonoInternalThread*)mono_object_new (mono_get_root_domain (),
- mono_defaults.internal_thread_class);
- thread->internal_thread = internal;
+ thread = create_thread_object (domain);
+ internal = create_internal_thread_object ();
+ MONO_OBJECT_SETREF (thread, internal_thread, internal);
start_info=g_new0 (struct StartInfo, 1);
start_info->func = func;
return NULL;
}
if (threads_starting_up == NULL) {
- MONO_GC_REGISTER_ROOT (threads_starting_up);
- threads_starting_up = mono_g_hash_table_new (NULL, NULL);
- }
- if (thread_start_args == NULL) {
- MONO_GC_REGISTER_ROOT (thread_start_args);
- thread_start_args = mono_g_hash_table_new (NULL, NULL);
+ MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
+ threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
}
+
+ register_thread_start_argument (thread, start_info);
mono_g_hash_table_insert (threads_starting_up, thread, thread);
- /*
- * The argument may be an object reference, and there is no ref to keep it alive
- * when the new thread is started but not yet registered with the collector. So
- * we store it in a GC tracked hash table.
- */
- mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
mono_threads_unlock ();
/* Create suspended, so we can do some housekeeping before the thread
*staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
return;
/* FIXME: simplify the mess below */
-#elif !defined(PLATFORM_WIN32)
+#elif !defined(HOST_WIN32)
pthread_attr_t attr;
guint8 *current = (guint8*)&attr;
# elif defined(sun)
*staddr = NULL;
pthread_attr_getstacksize (&attr, &stsize);
+# elif defined(__OpenBSD__)
+ stack_t ss;
+ int rslt;
+
+ rslt = pthread_stackseg_np(pthread_self(), &ss);
+ g_assert (rslt == 0);
+
+ *staddr = (guint8*)((size_t)ss.ss_sp - ss.ss_size);
+ *stsize = ss.ss_size;
# else
*staddr = NULL;
*stsize = 0;
# endif
# endif
-# ifndef sun
+# if !defined(sun)
+# if !defined(__OpenBSD__)
pthread_attr_getstack (&attr, (void**)staddr, stsize);
+# endif
if (*staddr)
g_assert ((current > *staddr) && (current < *staddr + *stsize));
# endif
- pthread_attr_destroy (&attr);
+ pthread_attr_destroy (&attr);
+#else
+ *staddr = NULL;
+ *stsize = (size_t)-1;
#endif
/* When running under emacs, sometimes staddr is not aligned to a page size */
g_error ("Thread %"G_GSIZE_FORMAT" calling into managed code is not registered with the GC. On UNIX, this can be fixed by #include-ing <gc.h> before <pthread.h> in the file containing the thread creation code.", GetCurrentThreadId ());
}
- thread = (MonoInternalThread *)mono_object_new (domain, mono_defaults.internal_thread_class);
+ thread = create_internal_thread_object ();
thread_handle = GetCurrentThread ();
g_assert (thread_handle);
thread->handle=thread_handle;
thread->tid=tid;
+#ifdef PLATFORM_ANDROID
+ thread->android_tid = (gpointer) gettid ();
+#endif
thread->apartment_state=ThreadApartmentState_Unknown;
small_id_alloc (thread);
thread->stack_ptr = &tid;
mono_thread_attach_cb (tid, staddr + stsize);
}
+ // FIXME: Need a separate callback
+ mono_profiler_thread_start (tid);
+
return current_thread;
}
thread_cleanup (thread->internal_thread);
SET_CURRENT_OBJECT (NULL);
+ mono_domain_unset ();
/* Don't need to CloseHandle this thread, even though we took a
* reference in mono_thread_attach (), because the GC will do it
thread_cleanup (thread);
SET_CURRENT_OBJECT (NULL);
+ mono_domain_unset ();
/* we could add a callback here for embedders to use. */
- if (thread == mono_thread_get_main ()->internal_thread)
+ if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
exit (mono_environment_exitcode_get ());
ExitThread (-1);
}
void
ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this)
{
- MonoInternalThread *internal = (MonoInternalThread*)mono_object_new (mono_get_root_domain (), mono_defaults.internal_thread_class);
+ MonoInternalThread *internal = create_internal_thread_object ();
+
internal->state = ThreadState_Unstarted;
internal->apartment_state = ThreadApartmentState_Unknown;
}
mono_threads_lock ();
+ register_thread_start_argument (this, start_info);
if (threads_starting_up == NULL) {
- MONO_GC_REGISTER_ROOT (threads_starting_up);
- threads_starting_up = mono_g_hash_table_new (NULL, NULL);
+ MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
+ threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
}
mono_g_hash_table_insert (threads_starting_up, this, this);
mono_threads_unlock ();
this->synch_cs = NULL;
}
- g_assert (!this->abort_exc && !this->abort_state_handle);
-
g_free (this->name);
}
return mono_domain_get()->domain_id;
}
+gboolean
+ves_icall_System_Threading_Thread_Yield (void)
+{
+#ifdef HOST_WIN32
+ return SwitchToThread ();
+#else
+ return sched_yield () == 0;
+#endif
+}
+
+/*
+ * mono_thread_get_name:
+ *
+ * Return the name of the thread. NAME_LEN is set to the length of the name.
+ * Return NULL if the thread has no name. The returned memory is owned by the
+ * caller.
+ */
+gunichar2*
+mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
+{
+ gunichar2 *res;
+
+ ensure_synch_cs_set (this_obj);
+
+ EnterCriticalSection (this_obj->synch_cs);
+
+ if (!this_obj->name) {
+ *name_len = 0;
+ res = NULL;
+ } else {
+ *name_len = this_obj->name_len;
+ res = g_new (gunichar2, this_obj->name_len);
+ memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
+ }
+
+ LeaveCriticalSection (this_obj->synch_cs);
+
+ return res;
+}
+
MonoString*
ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
{
this_obj->name = NULL;
LeaveCriticalSection (this_obj->synch_cs);
-}
-
-static MonoObject*
-lookup_cached_culture (MonoInternalThread *this, MonoDomain *domain, int start_idx)
-{
- MonoObject *res;
- int i;
-
- if (this->cached_culture_info) {
- domain = mono_domain_get ();
- for (i = start_idx; i < start_idx + NUM_CACHED_CULTURES; ++i) {
- res = mono_array_get (this->cached_culture_info, MonoObject*, i);
- if (res && res->vtable->domain == domain)
- return res;
- }
+ if (this_obj->name) {
+ char *tname = mono_string_to_utf8 (name);
+ mono_profiler_thread_name (this_obj->tid, tname);
+ mono_free (tname);
}
-
- return NULL;
}
/* If the array is already in the requested domain, we just return it,
return byte_array_to_domain (arr, mono_domain_get ());
}
-MonoObject*
-ves_icall_System_Threading_Thread_GetCachedCurrentCulture (MonoInternalThread *this)
-{
- return lookup_cached_culture (this, mono_domain_get (), CULTURES_START_IDX);
-}
-
-MonoArray*
-ves_icall_System_Threading_Thread_GetSerializedCurrentCulture (MonoInternalThread *this)
-{
- MonoArray *res;
-
- ensure_synch_cs_set (this);
-
- EnterCriticalSection (this->synch_cs);
-
- if (this->serialized_culture_info) {
- res = mono_array_new (mono_domain_get (), mono_defaults.byte_class, this->serialized_culture_info_len);
- memcpy (mono_array_addr (res, guint8, 0), this->serialized_culture_info, this->serialized_culture_info_len);
- } else {
- res = NULL;
- }
-
- LeaveCriticalSection (this->synch_cs);
-
- return res;
-}
-
-static void
-cache_culture (MonoInternalThread *this, MonoObject *culture, int start_idx)
-{
- int i;
- MonoDomain *domain = mono_domain_get ();
- MonoObject *obj;
- int free_slot = -1;
- int same_domain_slot = -1;
-
- ensure_synch_cs_set (this);
-
- EnterCriticalSection (this->synch_cs);
-
- if (!this->cached_culture_info)
- MONO_OBJECT_SETREF (this, cached_culture_info, mono_array_new_cached (mono_get_root_domain (), mono_defaults.object_class, NUM_CACHED_CULTURES * 2));
-
- for (i = start_idx; i < start_idx + NUM_CACHED_CULTURES; ++i) {
- obj = mono_array_get (this->cached_culture_info, MonoObject*, i);
- /* Free entry */
- if (!obj) {
- free_slot = i;
- /* we continue, because there may be a slot used with the same domain */
- continue;
- }
- /* Replace */
- if (obj->vtable->domain == domain) {
- same_domain_slot = i;
- break;
- }
- }
- if (same_domain_slot >= 0)
- mono_array_setref (this->cached_culture_info, same_domain_slot, culture);
- else if (free_slot >= 0)
- mono_array_setref (this->cached_culture_info, free_slot, culture);
- /* we may want to replace an existing entry here, even when no suitable slot is found */
-
- LeaveCriticalSection (this->synch_cs);
-}
-
-void
-ves_icall_System_Threading_Thread_SetCachedCurrentCulture (MonoThread *this, MonoObject *culture)
-{
- MonoDomain *domain = mono_object_get_domain (&this->obj);
- g_assert (domain == mono_domain_get ());
- cache_culture (this->internal_thread, culture, CULTURES_START_IDX);
-}
-
-void
-ves_icall_System_Threading_Thread_SetSerializedCurrentCulture (MonoInternalThread *this, MonoArray *arr)
-{
- ensure_synch_cs_set (this);
-
- EnterCriticalSection (this->synch_cs);
-
- if (this->serialized_culture_info)
- g_free (this->serialized_culture_info);
- this->serialized_culture_info = g_new0 (guint8, mono_array_length (arr));
- this->serialized_culture_info_len = mono_array_length (arr);
- memcpy (this->serialized_culture_info, mono_array_addr (arr, guint8, 0), mono_array_length (arr));
-
- LeaveCriticalSection (this->synch_cs);
-}
-
-
-MonoObject*
-ves_icall_System_Threading_Thread_GetCachedCurrentUICulture (MonoInternalThread *this)
-{
- return lookup_cached_culture (this, mono_domain_get (), UICULTURES_START_IDX);
-}
-
-MonoArray*
-ves_icall_System_Threading_Thread_GetSerializedCurrentUICulture (MonoInternalThread *this)
-{
- MonoArray *res;
-
- ensure_synch_cs_set (this);
-
- EnterCriticalSection (this->synch_cs);
-
- if (this->serialized_ui_culture_info) {
- res = mono_array_new (mono_domain_get (), mono_defaults.byte_class, this->serialized_ui_culture_info_len);
- memcpy (mono_array_addr (res, guint8, 0), this->serialized_ui_culture_info, this->serialized_ui_culture_info_len);
- } else {
- res = NULL;
- }
-
- LeaveCriticalSection (this->synch_cs);
-
- return res;
-}
-
-void
-ves_icall_System_Threading_Thread_SetCachedCurrentUICulture (MonoThread *this, MonoObject *culture)
-{
- MonoDomain *domain = mono_object_get_domain (&this->obj);
- g_assert (domain == mono_domain_get ());
- cache_culture (this->internal_thread, culture, UICULTURES_START_IDX);
-}
-
-void
-ves_icall_System_Threading_Thread_SetSerializedCurrentUICulture (MonoInternalThread *this, MonoArray *arr)
-{
- ensure_synch_cs_set (this);
-
- EnterCriticalSection (this->synch_cs);
-
- if (this->serialized_ui_culture_info)
- g_free (this->serialized_ui_culture_info);
- this->serialized_ui_culture_info = g_new0 (guint8, mono_array_length (arr));
- this->serialized_ui_culture_info_len = mono_array_length (arr);
- memcpy (this->serialized_ui_culture_info, mono_array_addr (arr, guint8, 0), mono_array_length (arr));
-
- LeaveCriticalSection (this->synch_cs);
-}
-
MonoThread *
mono_thread_current (void)
{
/* FIXME: exitContext isnt documented */
gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
{
- HANDLE *handles;
+ HANDLE handles [MAXIMUM_WAIT_OBJECTS];
guint32 numhandles;
guint32 ret;
guint32 i;
MonoObject *waitHandle;
MonoInternalThread *thread = mono_thread_internal_current ();
+ guint32 start;
/* Do this WaitSleepJoin check before creating objects */
mono_thread_current_check_pending_interrupt ();
numhandles = mono_array_length(mono_handles);
- handles = g_new0(HANDLE, numhandles);
+ if (numhandles > MAXIMUM_WAIT_OBJECTS)
+ return WAIT_FAILED;
for(i = 0; i < numhandles; i++) {
waitHandle = mono_array_get(mono_handles, MonoObject*, i);
}
mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
-
- ret=WaitForMultipleObjectsEx(numhandles, handles, FALSE, ms, TRUE);
+
+ start = (ms == -1) ? 0 : mono_msec_ticks ();
+ do {
+ ret = WaitForMultipleObjectsEx (numhandles, handles, FALSE, ms, TRUE);
+ if (ret != WAIT_IO_COMPLETION)
+ break;
+ if (ms != -1) {
+ guint32 diff;
+
+ diff = mono_msec_ticks () - start;
+ ms -= diff;
+ if (ms <= 0)
+ break;
+ }
+ } while (ms == -1 || ms > 0);
mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
-
- g_free(handles);
THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
int
mono_thread_get_abort_signal (void)
{
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
return -1;
#else
#ifndef SIGRTMIN
/* fallback to the old way */
return SIGRTMIN;
#endif
-#endif /* PLATFORM_WIN32 */
+#endif /* HOST_WIN32 */
}
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
static void CALLBACK interruption_request_apc (ULONG_PTR param)
{
MonoException* exc = mono_thread_request_interruption (FALSE);
if (exc) mono_raise_exception (exc);
}
-#endif /* PLATFORM_WIN32 */
+#endif /* HOST_WIN32 */
/*
* signal_thread_state_change
mono_raise_exception (exc);
}
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, NULL);
#else
/* fixme: store the state somewhere */
-#ifdef PTHREAD_POINTER_ID
- pthread_kill ((gpointer)(gsize)(thread->tid), mono_thread_get_abort_signal ());
-#else
- pthread_kill (thread->tid, mono_thread_get_abort_signal ());
-#endif
+ mono_thread_kill (thread, mono_thread_get_abort_signal ());
/*
* This will cause waits to be broken.
* make it return.
*/
wapi_interrupt_thread (thread->handle);
-#endif /* PLATFORM_WIN32 */
+#endif /* HOST_WIN32 */
}
void
}
thread->abort_exc = NULL;
+ /*
+ * abort_exc is set in mono_thread_execute_interruption(),
+ * triggered by the call to signal_thread_state_change(),
+ * below. There's a point between where we have
+ * abort_state_handle set, but abort_exc NULL, but that's not
+ * a problem.
+ */
+
LeaveCriticalSection (thread->synch_cs);
THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
ves_icall_System_Threading_Thread_ResetAbort (void)
{
MonoInternalThread *thread = mono_thread_internal_current ();
+ gboolean was_aborting;
ensure_synch_cs_set (thread);
EnterCriticalSection (thread->synch_cs);
-
+ was_aborting = thread->state & ThreadState_AbortRequested;
thread->state &= ~ThreadState_AbortRequested;
-
- if (!thread->abort_exc) {
- const char *msg = "Unable to reset abort because no abort was requested";
- LeaveCriticalSection (thread->synch_cs);
- mono_raise_exception (mono_get_exception_thread_state (msg));
- } else {
- thread->abort_exc = NULL;
- if (thread->abort_state_handle) {
- mono_gchandle_free (thread->abort_state_handle);
- /* This is actually not necessary - the handle
- only counts if the exception is set */
- thread->abort_state_handle = 0;
- }
- }
-
LeaveCriticalSection (thread->synch_cs);
-}
-
-static MonoObject*
-serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
-{
- static MonoMethod *serialize_method;
-
- void *params [1];
- MonoObject *array;
-
- if (!serialize_method) {
- MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
- serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
- }
-
- if (!serialize_method) {
- *failure = TRUE;
- return NULL;
- }
-
- g_assert (!obj->vtable->klass->marshalbyref);
-
- params [0] = obj;
- *exc = NULL;
- array = mono_runtime_invoke (serialize_method, NULL, params, exc);
- if (*exc)
- *failure = TRUE;
-
- return array;
-}
-static MonoObject*
-deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
-{
- static MonoMethod *deserialize_method;
-
- void *params [1];
- MonoObject *result;
-
- if (!deserialize_method) {
- MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
- deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
+ if (!was_aborting) {
+ const char *msg = "Unable to reset abort because no abort was requested";
+ mono_raise_exception (mono_get_exception_thread_state (msg));
}
- if (!deserialize_method) {
- *failure = TRUE;
- return NULL;
+ thread->abort_exc = NULL;
+ if (thread->abort_state_handle) {
+ mono_gchandle_free (thread->abort_state_handle);
+ /* This is actually not necessary - the handle
+ only counts if the exception is set */
+ thread->abort_state_handle = 0;
}
-
- params [0] = obj;
- *exc = NULL;
- result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
- if (*exc)
- *failure = TRUE;
-
- return result;
}
-static MonoObject*
-make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
+void
+mono_thread_internal_reset_abort (MonoInternalThread *thread)
{
- static MonoMethod *get_proxy_method;
-
- MonoDomain *domain = mono_domain_get ();
- MonoRealProxy *real_proxy;
- MonoReflectionType *reflection_type;
- MonoTransparentProxy *transparent_proxy;
-
- if (!get_proxy_method)
- get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
-
- g_assert (obj->vtable->klass->marshalbyref);
+ ensure_synch_cs_set (thread);
- real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
- reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
+ EnterCriticalSection (thread->synch_cs);
- real_proxy->class_to_proxy = reflection_type;
- real_proxy->unwrapped_server = obj;
+ thread->state &= ~ThreadState_AbortRequested;
- *exc = NULL;
- transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
- if (*exc)
- *failure = TRUE;
+ if (thread->abort_exc) {
+ thread->abort_exc = NULL;
+ if (thread->abort_state_handle) {
+ mono_gchandle_free (thread->abort_state_handle);
+ /* This is actually not necessary - the handle
+ only counts if the exception is set */
+ thread->abort_state_handle = 0;
+ }
+ }
- return (MonoObject*) transparent_proxy;
+ LeaveCriticalSection (thread->synch_cs);
}
MonoObject*
ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this)
{
MonoInternalThread *thread = this->internal_thread;
- MonoObject *state, *serialized, *deserialized = NULL, *exc;
+ MonoObject *state, *deserialized = NULL, *exc;
MonoDomain *domain;
- gboolean failure = FALSE;
if (!thread->abort_state_handle)
return NULL;
g_assert (state);
domain = mono_domain_get ();
- if (state->vtable->domain == domain)
+ if (mono_object_domain (state) == domain)
return state;
- if (state->vtable->klass->marshalbyref) {
- deserialized = make_transparent_proxy (state, &failure, &exc);
- } else {
- mono_domain_set_internal_with_options (state->vtable->domain, FALSE);
- serialized = serialize_object (state, &failure, &exc);
- mono_domain_set_internal_with_options (domain, FALSE);
- if (!failure)
- deserialized = deserialize_object (serialized, &failure, &exc);
- }
+ deserialized = mono_object_xdomain_representation (state, domain, &exc);
- if (failure) {
+ if (!deserialized) {
MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
if (exc)
MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
void mono_thread_init (MonoThreadStartCB start_cb,
MonoThreadAttachCB attach_cb)
{
- MONO_GC_REGISTER_ROOT (small_id_table);
+ MONO_GC_REGISTER_ROOT_FIXED (small_id_table);
InitializeCriticalSection(&threads_mutex);
InitializeCriticalSection(&interlocked_mutex);
InitializeCriticalSection(&contexts_mutex);
{
mono_thread_hazardous_try_free_all ();
-#if !defined(PLATFORM_WIN32) && !defined(RUN_IN_SUBTHREAD)
+#if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
/* The main thread must abandon any held mutexes (particularly
* important for named mutexes as they are shared across
* processes, see bug 74680.) This will happen when the
THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
- ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, FALSE);
+ ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
if(ret==WAIT_FAILED) {
/* See the comment in build_wait_tids() */
count++;
}
- ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, FALSE);
+ ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
if(ret==WAIT_FAILED) {
/* See the comment in build_wait_tids() */
return;
}
- if (thread == mono_thread_get_main ()->internal_thread) {
+ if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
return;
}
+ if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
+ THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
+ return;
+ }
+
handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
if (handle == NULL) {
THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
return FALSE;
/* The finalizer thread is not a background thread */
- if (thread->tid != self && (thread->state & ThreadState_Background) != 0) {
+ if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
+ !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
if (handle == NULL)
LeaveCriticalSection (current_thread->synch_cs);
}
+ /*since we're killing the thread, unset the current domain.*/
+ mono_domain_unset ();
+
/* Wake up other threads potentially waiting for us */
ExitThread (0);
} else {
void mono_thread_manage (void)
{
- struct wait_data *wait=g_new0 (struct wait_data, 1);
+ struct wait_data wait_data;
+ struct wait_data *wait = &wait_data;
+ memset (wait, 0, sizeof (struct wait_data));
/* join each thread that's still running */
THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
if(threads==NULL) {
THREAD_DEBUG (g_message("%s: No threads", __func__));
mono_threads_unlock ();
- g_free (wait);
return;
}
mono_threads_unlock ();
ResetEvent (background_change_event);
wait->num=0;
+ /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
+ memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
mono_g_hash_table_foreach (threads, build_wait_tids, wait);
mono_threads_unlock ();
if(wait->num>0) {
mono_threads_lock ();
wait->num = 0;
+ /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
+ memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
mono_threads_unlock ();
* to get correct user and system times from getrusage/wait/time(1)).
* This could be removed if we avoid pthread_detach() and use pthread_join().
*/
-#ifndef PLATFORM_WIN32
+#ifndef HOST_WIN32
sched_yield ();
#endif
-
- g_free (wait);
}
static void terminate_thread (gpointer key, gpointer value, gpointer user)
*/
void mono_thread_suspend_all_other_threads (void)
{
- struct wait_data *wait = g_new0 (struct wait_data, 1);
+ struct wait_data wait_data;
+ struct wait_data *wait = &wait_data;
int i;
gsize self = GetCurrentThreadId ();
gpointer *events;
guint32 eventidx = 0;
gboolean starting, finished;
+ memset (wait, 0, sizeof (struct wait_data));
/*
* The other threads could be in an arbitrary state at this point, i.e.
* they could be starting up, shutting down etc. This means that there could be
* threads while threads_mutex is held.
*/
wait->num = 0;
+ /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
+ memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
mono_threads_lock ();
mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
mono_threads_unlock ();
MonoInternalThread *thread = wait->threads [i];
gboolean signal_suspend = FALSE;
- if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread)) {
+ if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
//CloseHandle (wait->handles [i]);
wait->threads [i] = NULL; /* ignore this thread in next loop */
continue;
if (thread == NULL)
continue;
+
+ ensure_synch_cs_set (thread);
EnterCriticalSection (thread->synch_cs);
if ((thread->state & ThreadState_Suspended) != 0) {
g_free (events);
}
-
- g_free (wait);
}
static void
void
mono_threads_request_thread_dump (void)
{
- struct wait_data *wait = g_new0 (struct wait_data, 1);
+ struct wait_data wait_data;
+ struct wait_data *wait = &wait_data;
int i;
+ memset (wait, 0, sizeof (struct wait_data));
+
/*
* Make a copy of the hashtable since we can't do anything with
* threads while threads_mutex is held.
if (thread) {
/* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
- mono_threads_lock ();
+ SPIN_LOCK (thread->lock_thread_id);
thread->appdomain_refs = g_slist_prepend (thread->appdomain_refs, domain);
- mono_threads_unlock ();
+ SPIN_UNLOCK (thread->lock_thread_id);
}
}
if (thread) {
/* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
- mono_threads_lock ();
/* FIXME: How can the list be empty ? */
+ SPIN_LOCK (thread->lock_thread_id);
if (thread->appdomain_refs)
thread->appdomain_refs = g_slist_remove (thread->appdomain_refs, thread->appdomain_refs->data);
- mono_threads_unlock ();
+ SPIN_UNLOCK (thread->lock_thread_id);
}
}
mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
{
gboolean res;
- mono_threads_lock ();
+ SPIN_LOCK (thread->lock_thread_id);
res = g_slist_find (thread->appdomain_refs, domain) != NULL;
- mono_threads_unlock ();
+ SPIN_UNLOCK (thread->lock_thread_id);
return res;
}
return NULL;
}
+#if MONO_SMALL_CONFIG
+#define NUM_STATIC_DATA_IDX 4
+static const int static_data_size [NUM_STATIC_DATA_IDX] = {
+ 64, 256, 1024, 4096
+};
+#else
#define NUM_STATIC_DATA_IDX 8
static const int static_data_size [NUM_STATIC_DATA_IDX] = {
1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
};
+#endif
+static uintptr_t* static_reference_bitmaps [NUM_STATIC_DATA_IDX];
+
+#ifdef HAVE_SGEN_GC
+static void
+mark_tls_slots (void *addr, MonoGCMarkFunc mark_func)
+{
+ int i;
+ gpointer *static_data = addr;
+ for (i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
+ int j, numwords;
+ void **ptr;
+ if (!static_data [i])
+ continue;
+ numwords = 1 + static_data_size [i] / sizeof (gpointer) / (sizeof(uintptr_t) * 8);
+ ptr = static_data [i];
+ for (j = 0; j < numwords; ++j, ptr += sizeof (uintptr_t) * 8) {
+ uintptr_t bmap = static_reference_bitmaps [i][j];
+ void ** p = ptr;
+ while (bmap) {
+ if ((bmap & 1) && *p) {
+ mark_func (p);
+ }
+ p++;
+ bmap >>= 1;
+ }
+ }
+ }
+}
+#endif
/*
* mono_alloc_static_data
* Allocate memory blocks for storing threads or context static data
*/
static void
-mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset)
+mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
{
guint idx = (offset >> 24) - 1;
int i;
gpointer* static_data = *static_data_ptr;
if (!static_data) {
- static_data = mono_gc_alloc_fixed (static_data_size [0], NULL);
+ static void* tls_desc = NULL;
+#ifdef HAVE_SGEN_GC
+ if (!tls_desc)
+ tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
+#endif
+ static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal?tls_desc:NULL);
*static_data_ptr = static_data;
static_data [0] = static_data;
}
for (i = 1; i <= idx; ++i) {
if (static_data [i])
continue;
+#ifdef HAVE_SGEN_GC
+ static_data [i] = threadlocal?g_malloc0 (static_data_size [i]):mono_gc_alloc_fixed (static_data_size [i], NULL);
+#else
static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
+#endif
}
}
+static void
+mono_free_static_data (gpointer* static_data, gboolean threadlocal)
+{
+ int i;
+ for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
+ if (!static_data [i])
+ continue;
+#ifdef HAVE_SGEN_GC
+ if (threadlocal)
+ g_free (static_data [i]);
+ else
+ mono_gc_free_fixed (static_data [i]);
+#else
+ mono_gc_free_fixed (static_data [i]);
+#endif
+ }
+ mono_gc_free_fixed (static_data);
+}
+
/*
* mono_init_static_data_info
*
if (thread_static_info.offset || thread_static_info.idx > 0) {
/* get the current allocated size */
offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
- mono_alloc_static_data (&(thread->static_data), offset);
+ mono_alloc_static_data (&(thread->static_data), offset, TRUE);
}
mono_threads_unlock ();
}
MonoInternalThread *thread = value;
guint32 offset = GPOINTER_TO_UINT (user);
- mono_alloc_static_data (&(thread->static_data), offset);
+ mono_alloc_static_data (&(thread->static_data), offset, TRUE);
}
static MonoThreadDomainTls*
return NULL;
}
+static void
+update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int max_set)
+{
+ int i;
+ int idx = (offset >> 24) - 1;
+ uintptr_t *rb;
+ if (!static_reference_bitmaps [idx])
+ static_reference_bitmaps [idx] = g_new0 (uintptr_t, 1 + static_data_size [idx] / sizeof(gpointer) / (sizeof(uintptr_t) * 8));
+ rb = static_reference_bitmaps [idx];
+ offset &= 0xffffff;
+ offset /= sizeof (gpointer);
+ /* offset is now the bitmap offset */
+ for (i = 0; i < max_set; ++i) {
+ if (bitmap [i / sizeof (uintptr_t)] & (1L << (i & (sizeof (uintptr_t) * 8 -1))))
+ rb [(offset + i) / (sizeof (uintptr_t) * 8)] |= (1L << ((offset + i) & (sizeof (uintptr_t) * 8 -1)));
+ }
+}
+
+static void
+clear_reference_bitmap (guint32 offset, guint32 size)
+{
+ int idx = (offset >> 24) - 1;
+ uintptr_t *rb;
+ rb = static_reference_bitmaps [idx];
+ offset &= 0xffffff;
+ offset /= sizeof (gpointer);
+ size /= sizeof (gpointer);
+ size += offset;
+ /* offset is now the bitmap offset */
+ for (; offset < size; ++offset)
+ rb [offset / (sizeof (uintptr_t) * 8)] &= ~(1L << (offset & (sizeof (uintptr_t) * 8 -1)));
+}
+
/*
* The offset for a special static variable is composed of three parts:
* a bit that indicates the type of static data (0:thread, 1:context),
*/
guint32
-mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align)
+mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int max_set)
{
guint32 offset;
- if (static_type == SPECIAL_STATIC_THREAD)
- {
+ if (static_type == SPECIAL_STATIC_THREAD) {
MonoThreadDomainTls *item;
mono_threads_lock ();
item = search_tls_slot_in_freelist (&thread_static_info, size, align);
} else {
offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
}
+ update_tls_reference_bitmap (offset, bitmap, max_set);
/* 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
- {
+ } else {
g_assert (static_type == SPECIAL_STATIC_CONTEXT);
mono_contexts_lock ();
offset = mono_alloc_static_data_slot (&context_static_info, size, align);
}
gpointer
-mono_get_special_static_data (guint32 offset)
+mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
{
/* The high bit means either thread (0) or static (1) data. */
idx = (offset >> 24) - 1;
if (static_type == 0) {
- return get_thread_static_data (mono_thread_internal_current (), offset);
+ 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);
+ mono_alloc_static_data (&(context->static_data), offset, FALSE);
mono_contexts_unlock ();
}
return ((char*) context->static_data [idx]) + (offset & 0xffffff);
}
}
+gpointer
+mono_get_special_static_data (guint32 offset)
+{
+ return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
+}
+
typedef struct {
guint32 offset;
guint32 size;
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);
item->offset = offset;
item->size = size;
- item->next = thread_static_info.freelist;
- thread_static_info.freelist = item;
+
+ 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 */
}
}
}
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
static void CALLBACK dummy_apc (ULONG_PTR param)
{
}
/* this will consume pending APC calls */
WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
InterlockedDecrement (&thread_interruption_requested);
-#ifndef PLATFORM_WIN32
+#ifndef HOST_WIN32
/* Clear the interrupted flag of the thread so it can wait again */
wapi_clear_interruption ();
#endif
if (thread == NULL)
return NULL;
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
if (thread->interrupt_on_stop &&
thread->state & ThreadState_StopRequested &&
thread->state & ThreadState_Background)
}
}
+/*This function should be called by a thread after it has exited all of
+ * its handle blocks at interruption time.*/
+MonoException*
+mono_thread_resume_interruption (void)
+{
+ MonoInternalThread *thread = mono_thread_internal_current ();
+ gboolean still_aborting;
+
+ /* The thread may already be stopping */
+ if (thread == NULL)
+ return NULL;
+
+ ensure_synch_cs_set (thread);
+ EnterCriticalSection (thread->synch_cs);
+ still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
+ LeaveCriticalSection (thread->synch_cs);
+
+ /*This can happen if the protected block called Thread::ResetAbort*/
+ if (!still_aborting)
+ return FALSE;
+
+ if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
+ return NULL;
+ InterlockedIncrement (&thread_interruption_requested);
+
+#ifndef HOST_WIN32
+ wapi_self_interrupt ();
+#endif
+ return mono_thread_execute_interruption (thread);
+}
+
gboolean mono_thread_interruption_requested ()
{
if (thread_interruption_requested) {
void
mono_thread_init_apartment_state (void)
{
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
MonoInternalThread* thread = mono_thread_internal_current ();
/* Positive return value indicates success, either
void
mono_thread_cleanup_apartment_state (void)
{
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
MonoInternalThread* thread = mono_thread_internal_current ();
if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
{
return has_tls_get;
}
+
+int
+mono_thread_kill (MonoInternalThread *thread, int signal)
+{
+#ifdef HOST_WIN32
+ /* Win32 uses QueueUserAPC and callers of this are guarded */
+ g_assert_not_reached ();
+#else
+# ifdef PTHREAD_POINTER_ID
+ return pthread_kill ((gpointer)(gsize)(thread->tid), mono_thread_get_abort_signal ());
+# else
+# ifdef PLATFORM_ANDROID
+ if (thread->android_tid != 0) {
+ int ret;
+ int old_errno = errno;
+
+ ret = tkill ((pid_t) thread->android_tid, signal);
+ if (ret < 0) {
+ ret = errno;
+ errno = old_errno;
+ }
+
+ return ret;
+ }
+ else
+ return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
+# else
+ return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
+# endif
+# endif
+#endif
+}