#include <errno.h>
#include <unistd.h>
+/* work around a dlopen issue (bug #75390), undefs to avoid warnings with redefinitions */
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+#include "mono/utils/mono-compiler.h"
+
+#ifdef MONO_DEBUGGER_SUPPORTED
+#include "include/libgc-mono-debugger.h"
+#endif
+
#if DEBUG_THREADS
#ifndef NSIG
sem_t GC_suspend_ack_sem;
-void GC_suspend_handler(int sig)
+static void _GC_suspend_handler(int sig)
{
int dummy;
pthread_t my_thread = pthread_self();
/* to accidentally leave a RESTART signal pending, thus causing us to */
/* continue prematurely in a future round. */
+ /* Tell the thread that wants to start the world that this */
+ /* thread has been started. Note that sem_post() is */
+ /* the only async-signal-safe primitive in LinuxThreads. */
+ sem_post(&GC_suspend_ack_sem);
+
+
#if DEBUG_THREADS
GC_printf1("Continuing 0x%lx\n", my_thread);
#endif
}
-void GC_restart_handler(int sig)
+void GC_suspend_handler(int sig)
+{
+ int old_errno = errno;
+ _GC_suspend_handler(sig);
+ errno = old_errno;
+}
+
+static void _GC_restart_handler(int sig)
{
pthread_t my_thread = pthread_self();
GC_thread me;
ABORT("Collecting from unknown thread.");
}
+void GC_restart_handler(int sig)
+{
+ int old_errno = errno;
+ _GC_restart_handler (sig);
+ errno = old_errno;
+}
+
/* We hold allocation lock. Should do exactly the right thing if the */
/* world is stopped. Should not fail if it isn't. */
void GC_push_all_stacks()
{
- gc_thread_vtable->push_all_stacks();
+ pthread_push_all_stacks();
}
/* There seems to be a very rare thread stopping problem. To help us */
#if DEBUG_THREADS
GC_printf1("Stopping the world from 0x%lx\n", pthread_self());
#endif
-
+
n_live_threads = GC_suspend_all();
if (GC_retry_signals) {
}
}
for (i = 0; i < n_live_threads; i++) {
- if (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
- GC_err_printf1("Sem_wait returned %ld\n", (unsigned long)code);
- ABORT("sem_wait for handler failed");
+ while (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
+ if (errno != EINTR) {
+ GC_err_printf1("Sem_wait returned %ld\n", (unsigned long)code);
+ ABORT("sem_wait for handler failed");
+ }
}
}
#if DEBUG_THREADS
/* Caller holds allocation lock. */
void GC_stop_world()
{
+ if (GC_notify_event)
+ GC_notify_event (GC_EVENT_PRE_STOP_WORLD);
/* Make sure all free list construction has stopped before we start. */
/* No new construction can start, since free list construction is */
/* required to acquire and release the GC lock before it starts, */
/* We should have previously waited for it to become zero. */
# endif /* PARALLEL_MARK */
++GC_stop_count;
- gc_thread_vtable->stop_world ();
+#ifdef MONO_DEBUGGER_SUPPORTED
+ if (gc_thread_vtable && gc_thread_vtable->stop_world)
+ gc_thread_vtable->stop_world ();
+ else
+#endif
+ pthread_stop_world ();
# ifdef PARALLEL_MARK
GC_release_mark_lock();
# endif
+ if (GC_notify_event)
+ GC_notify_event (GC_EVENT_POST_STOP_WORLD);
}
/* Caller holds allocation lock, and has held it continuously since */
register GC_thread p;
register int n_live_threads = 0;
register int result;
+ int code;
# if DEBUG_THREADS
GC_printf0("World starting\n");
# endif
+ if (GC_notify_event)
+ GC_notify_event (GC_EVENT_PRE_START_WORLD);
for (i = 0; i < THREAD_TABLE_SZ; i++) {
for (p = GC_threads[i]; p != 0; p = p -> next) {
}
}
}
+
+ #if DEBUG_THREADS
+ GC_printf0 ("All threads signaled");
+ #endif
+
+ for (i = 0; i < n_live_threads; i++) {
+ while (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
+ if (errno != EINTR) {
+ GC_err_printf1("Sem_wait returned %ld\n", (unsigned long)code);
+ ABORT("sem_wait for handler failed");
+ }
+ }
+ }
+
+ if (GC_notify_event)
+ GC_notify_event (GC_EVENT_POST_START_WORLD);
#if DEBUG_THREADS
GC_printf0("World started\n");
#endif
void GC_start_world()
{
- gc_thread_vtable->start_world();
+#ifdef MONO_DEBUGGER_SUPPORTED
+ if (gc_thread_vtable && gc_thread_vtable->start_world)
+ gc_thread_vtable->start_world();
+ else
+#endif
+ pthread_start_world ();
}
static void pthread_stop_init() {
/* We hold the allocation lock. */
void GC_stop_init()
{
- gc_thread_vtable->initialize ();
+#ifdef MONO_DEBUGGER_SUPPORTED
+ if (gc_thread_vtable && gc_thread_vtable->initialize)
+ gc_thread_vtable->initialize ();
+ else
+#endif
+ pthread_stop_init ();
}
-/*
- * This is used by the Mono Debugger to stop/start the world.
- */
-GCThreadFunctions pthread_thread_vtable = {
- pthread_stop_init,
-
- pthread_stop_world,
- pthread_push_all_stacks,
- pthread_start_world
-};
-
-GCThreadFunctions *gc_thread_vtable = &pthread_thread_vtable;
+#ifdef MONO_DEBUGGER_SUPPORTED
+
+GCThreadFunctions *gc_thread_vtable = NULL;
+
+void *
+GC_mono_debugger_get_stack_ptr (void)
+{
+ GC_thread me;
+
+ me = GC_lookup_thread (pthread_self ());
+ return &me->stop_info.stack_ptr;
+}
+
+#endif
#endif