/*#define LIBGC_DEBUG(a) do { a; } while (0)*/
#define LIBGC_DEBUG(a)
+/* Provide this for systems with glib < 2.6 */
+#ifndef G_GSIZE_FORMAT
+# if GLIB_SIZEOF_LONG == 8
+# define G_GSIZE_FORMAT "lu"
+# else
+# define G_GSIZE_FORMAT "u"
+# endif
+#endif
+
struct StartInfo
{
guint32 (*func)(void *);
static MonoThreadAttachCB mono_thread_attach_cb = NULL;
/* function called at thread cleanup */
-static MonoThreadCleanupFunc mono_thread_cleanup = NULL;
+static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
/* The default stack size for each thread */
static guint32 default_stacksize = 0;
*/
}
-/*
- * Tell the Mono Debugger about a newly created thread.
- * mono_debugger_event() is a no-op if we're not running inside the debugger.
- */
-static void debugger_thread_created (MonoThread *thread)
-{
- mono_debugger_event (MONO_DEBUGGER_EVENT_THREAD_CREATED,
- (guint64) (gsize) &thread->end_stack, thread->tid);
-}
-
-/*
- * Tell the Mono Debugger that a thrad is about to exit.
- * mono_debugger_event() is a no-op if we're not running inside the debugger.
- */
-static void debugger_thread_exited (MonoThread *thread)
-{
- mono_debugger_event (MONO_DEBUGGER_EVENT_THREAD_EXITED,
- (guint64) (gsize) &thread->end_stack, thread->tid);
-}
-
static void thread_cleanup (MonoThread *thread)
{
g_assert (thread != NULL);
thread->cached_culture_info = NULL;
- debugger_thread_exited (thread);
-
- if (mono_thread_cleanup)
- mono_thread_cleanup (thread);
+ if (mono_thread_cleanup_fn)
+ mono_thread_cleanup_fn (thread);
}
static guint32 WINAPI start_wrapper(void *data)
struct StartInfo *start_info=(struct StartInfo *)data;
guint32 (*start_func)(void *);
void *start_arg;
- guint32 tid;
+ gsize tid;
MonoThread *thread=start_info->obj;
MonoObject *start_delegate = start_info->delegate;
THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
-
+
/* We can be sure start_info->obj->tid and
* start_info->obj->handle have been set, because the thread
* was created suspended, and these values were set before the
mono_thread_new_init (tid, &tid, start_func);
thread->stack_ptr = &tid;
- debugger_thread_created (thread);
-
LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
HANDLE thread_handle;
struct StartInfo *start_info;
gsize tid;
-
+
thread=(MonoThread *)mono_object_new (domain,
mono_defaults.thread_class);
SET_CURRENT_OBJECT (thread);
mono_domain_set (domain, TRUE);
- debugger_thread_created (thread);
-
thread_adjust_static_data (thread);
if (mono_thread_attach_cb) {
GetCurrentProcess ();
}
+void mono_thread_cleanup (void)
+{
+#if !defined(PLATFORM_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 exits, but if it's not running in a subthread it
+ * won't exit in time.
+ */
+ /* Using non-w32 API is a nasty kludge, but I couldn't find
+ * anything in the documentation that would let me do this
+ * here yet still be safe to call on windows.
+ */
+ _wapi_thread_signal_self (mono_environment_exitcode_get ());
+#endif
+
+#if 0
+ /* This stuff needs more testing, it seems one of these
+ * critical sections can be locked when mono_thread_cleanup is
+ * called.
+ */
+ DeleteCriticalSection (&threads_mutex);
+ DeleteCriticalSection (&interlocked_mutex);
+ DeleteCriticalSection (&contexts_mutex);
+ CloseHandle (background_change_event);
+#endif
+}
+
void
mono_threads_install_cleanup (MonoThreadCleanupFunc func)
{
- mono_thread_cleanup = func;
+ mono_thread_cleanup_fn = func;
}
G_GNUC_UNUSED
/* Ignore background threads, we abort them later */
mono_monitor_enter (thread->synch_lock);
if (thread->state & ThreadState_Background) {
+ THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
mono_monitor_exit (thread->synch_lock);
return; /* just leave, ignore */
}
mono_monitor_exit (thread->synch_lock);
- if (mono_gc_is_finalizer_thread (thread))
+ if (mono_gc_is_finalizer_thread (thread)) {
+ THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
return;
+ }
- if (thread == mono_thread_current ())
+ if (thread == mono_thread_current ()) {
+ THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
return;
+ }
- if (thread == mono_thread_get_main ())
+ if (thread == mono_thread_get_main ()) {
+ THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
return;
+ }
handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
- if (handle == NULL)
+ if (handle == NULL) {
+ THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
return;
+ }
wait->handles[wait->num]=handle;
wait->threads[wait->num]=thread;
wait->num++;
+
+ THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
} else {
/* Just ignore the rest, we can't do anything with
* them yet
wait_for_tids (wait, INFINITE);
}
} while (wait->num > 0);
-
-#if !defined(PLATFORM_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 exits, but if it's not running in a subthread it
- * won't exit in time.
- */
- /* Using non-w32 API is a nasty kludge, but I couldn't find
- * anything in the documentation that would let me do this
- * here yet still be safe to call on windows.
- */
- _wapi_thread_abandon_mutexes (NULL);
-#endif
/*
* give the subthreads a chance to really quit (this is mainly needed
{
return &thread_interruption_requested;
}
-
-#if MONO_DEBUGGER_SUPPORTED
-
-extern void GC_push_all_stack (gpointer b, gpointer t);
-
-static void
-debugger_gc_push_stack (gpointer key, gpointer value, gpointer user)
-{
- MonoThread *thread = (MonoThread*)value;
- gpointer end_stack;
-
- /*
- * The debugger stops all other threads for us in debugger_gc_stop_world() and
- * then sets `thread->end_stack' for each of them.
- */
-
- end_stack = (thread->tid == GetCurrentThreadId ()) ? &key : thread->end_stack;
-
- if (!end_stack || !thread->stack_ptr) {
- g_warning (G_STRLOC ": Cannot push stack of thread %Lx", thread->tid);
- return;
- }
-
- GC_push_all_stack (end_stack, thread->stack_ptr);
-}
-
-/*
- * We're called with the thread lock.
- */
-static void
-debugger_gc_push_all_stacks (void)
-{
- if (threads != NULL)
- mono_g_hash_table_foreach (threads, debugger_gc_push_stack, NULL);
-}
-
-static void
-debugger_gc_stop_world (void)
-{
- /*
- * Acquire the thread lock and tell the debugger to stop all other threads.
- */
- mono_threads_lock ();
- mono_debugger_event (
- MONO_DEBUGGER_EVENT_ACQUIRE_GLOBAL_THREAD_LOCK, 0, 0);
-}
-
-static void
-debugger_gc_start_world (void)
-{
- /*
- * Tell the debugger to resume all other threads and release the lock.
- */
- mono_debugger_event (
- MONO_DEBUGGER_EVENT_RELEASE_GLOBAL_THREAD_LOCK, 0, 0);
- mono_threads_unlock ();
-}
-
-static void
-debugger_gc_init (void)
-{ }
-
-static GCThreadFunctions debugger_thread_vtable = {
- debugger_gc_init,
-
- debugger_gc_stop_world,
- debugger_gc_push_all_stacks,
- debugger_gc_start_world
-};
-
-static GCThreadFunctions *old_gc_thread_vtable = NULL;
-
-/**
- * mono_debugger_init_threads:
- *
- * This is used when running inside the Mono Debugger.
- */
-void
-mono_debugger_init_threads (void)
-{
- old_gc_thread_vtable = gc_thread_vtable;
- gc_thread_vtable = &debugger_thread_vtable;
- debugger_thread_created (mono_thread_current ());
-}
-
-/**
- * mono_debugger_finalize_threads:
- *
- * This is used when running inside the Mono Debugger.
- * Undo the effects of mono_debugger_init_threads(); this is called
- * prior to detaching from a process.
- */
-void
-mono_debugger_finalize_threads (void)
-{
- gc_thread_vtable = old_gc_thread_vtable;
-}
-
-#else /* WITH_INCLUDED_LIBGC */
-
-void
-mono_debugger_init_threads (void)
-{
- g_assert_not_reached ();
-}
-
-void
-mono_debugger_finalize_threads (void)
-{
- g_assert_not_reached ();
-}
-
-#endif