summaryrefslogtreecommitdiff
path: root/boehm-gc
diff options
context:
space:
mode:
Diffstat (limited to 'boehm-gc')
-rw-r--r--boehm-gc/ChangeLog12
-rw-r--r--boehm-gc/include/gc.h10
-rw-r--r--boehm-gc/include/private/pthread_support.h1
-rw-r--r--boehm-gc/pthread_stop_world.c65
4 files changed, 82 insertions, 6 deletions
diff --git a/boehm-gc/ChangeLog b/boehm-gc/ChangeLog
index ca5f33ce613..6e2b3a86112 100644
--- a/boehm-gc/ChangeLog
+++ b/boehm-gc/ChangeLog
@@ -1,3 +1,15 @@
+2006-06-21 Keith Seitz <keiths@redhat.com>
+
+ * pthread_stop_world.c (GC_suspend_handler): Redirect to suspension
+ routine if signal is received and thread is flagged SUSPENDED.
+ (suspend_self): New function.
+ (GC_suspend_thread): New function.
+ (GC_resume_thread): New function.
+ * include/gc.h (GC_suspend_thread): Declare.
+ (GC_resumet_thread): Declare.
+ * include/private/pthread_support.h (SUSPENDED): New GC_thread
+ flag.
+
2006-06-20 Ranjit Mathew <rmathew@gcc.gnu.org>
Backport Windows 9x/ME VirtualQuery() fix from GC 6.7.
diff --git a/boehm-gc/include/gc.h b/boehm-gc/include/gc.h
index 3507db74dc5..e6ab2c608c4 100644
--- a/boehm-gc/include/gc.h
+++ b/boehm-gc/include/gc.h
@@ -1040,4 +1040,14 @@ GC_API void GC_register_has_static_roots_callback
} /* end of extern "C" */
#endif
+/* External thread suspension support. These functions do not implement
+ * suspension counts or any other higher-level abstraction. Threads which
+ * have been suspended numerous times will resume with the very first call
+ * to GC_resume_thread.
+ */
+#if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
+ && !defined(GC_WIN32_THREADS) && !defined(GC_DARWIN_THREADS)
+GC_API void GC_suspend_thread GC_PROTO((pthread_t));
+GC_API void GC_resume_thread GC_PROTO((pthread_t));
+#endif
#endif /* _GC_H */
diff --git a/boehm-gc/include/private/pthread_support.h b/boehm-gc/include/private/pthread_support.h
index 469021b4071..2186c079039 100644
--- a/boehm-gc/include/private/pthread_support.h
+++ b/boehm-gc/include/private/pthread_support.h
@@ -33,6 +33,7 @@ typedef struct GC_Thread_Rep {
# define FINISHED 1 /* Thread has exited. */
# define DETACHED 2 /* Thread is intended to be detached. */
# define MAIN_THREAD 4 /* True for the original thread only. */
+# define SUSPENDED 8 /* True if thread was suspended externally */
short thread_blocked; /* Protected by GC lock. */
/* Treated as a boolean value. If set, */
/* thread will acquire GC lock before */
diff --git a/boehm-gc/pthread_stop_world.c b/boehm-gc/pthread_stop_world.c
index b9034dc7f5b..de647769c7c 100644
--- a/boehm-gc/pthread_stop_world.c
+++ b/boehm-gc/pthread_stop_world.c
@@ -13,6 +13,8 @@
/* Doesn't exist on HP/UX 11.11. */
#endif
+void suspend_self();
+
#if DEBUG_THREADS
#ifndef NSIG
@@ -127,9 +129,14 @@ extern void GC_with_callee_saves_pushed();
void GC_suspend_handler(int sig)
{
- int old_errno = errno;
- GC_with_callee_saves_pushed(GC_suspend_handler_inner, (ptr_t)(word)sig);
- errno = old_errno;
+ GC_thread me = GC_lookup_thread (pthread_self());
+ if (me -> flags & SUSPENDED)
+ suspend_self();
+ else {
+ int old_errno = errno;
+ GC_with_callee_saves_pushed(GC_suspend_handler_inner, (ptr_t)(word)sig);
+ errno = old_errno;
+ }
}
#else
@@ -137,9 +144,14 @@ void GC_suspend_handler(int sig)
/* in the signal handler frame. */
void GC_suspend_handler(int sig)
{
- int old_errno = errno;
- GC_suspend_handler_inner((ptr_t)(word)sig);
- errno = old_errno;
+ GC_thread me = GC_lookup_thread(pthread_self());
+ if (me -> flags & SUSPENDED)
+ suspend_self();
+ else {
+ int old_errno = errno;
+ GC_suspend_handler_inner((ptr_t)(word)sig);
+ errno = old_errno;
+ }
}
#endif
@@ -430,6 +442,47 @@ void GC_stop_world()
GC_stopping_thread = 0; /* debugging only */
}
+void suspend_self() {
+ GC_thread me = GC_lookup_thread(pthread_self());
+ if (me == NULL)
+ ABORT("attempting to suspend unknown thread");
+
+ me -> flags |= SUSPENDED;
+ GC_start_blocking();
+ while (me -> flags & SUSPENDED)
+ GC_brief_async_signal_safe_sleep();
+ GC_end_blocking();
+}
+
+void GC_suspend_thread(pthread_t thread) {
+ if (thread == pthread_self())
+ suspend_self();
+ else {
+ int result;
+ GC_thread t = GC_lookup_thread(thread);
+ if (t == NULL)
+ ABORT("attempting to suspend unknown thread");
+
+ t -> flags |= SUSPENDED;
+ result = pthread_kill (t -> id, SIG_SUSPEND);
+ switch (result) {
+ case ESRCH:
+ case 0:
+ break;
+ default:
+ ABORT("pthread_kill failed");
+ }
+ }
+}
+
+void GC_resume_thread(pthread_t thread) {
+ GC_thread t = GC_lookup_thread(thread);
+ if (t == NULL)
+ ABORT("attempting to resume unknown thread");
+
+ t -> flags &= ~SUSPENDED;
+}
+
/* Caller holds allocation lock, and has held it continuously since */
/* the world stopped. */
void GC_start_world()