diff options
Diffstat (limited to 'boehm-gc')
-rw-r--r-- | boehm-gc/ChangeLog | 12 | ||||
-rw-r--r-- | boehm-gc/include/gc.h | 10 | ||||
-rw-r--r-- | boehm-gc/include/private/pthread_support.h | 1 | ||||
-rw-r--r-- | boehm-gc/pthread_stop_world.c | 65 |
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() |