/* It's safe to call original pthread_sigmask() here. */
#undef pthread_sigmask
-void suspend_self();
+#ifdef GC_ENABLE_SUSPEND_THREAD
+ static void *GC_CALLBACK suspend_self_inner(void *client_data);
+#endif
#ifdef DEBUG_THREADS
# ifndef NSIG
#endif
{
int old_errno = errno;
- GC_thread me = GC_lookup_thread (pthread_self());
- if (me -> flags & SUSPENDED_EXT) {
- suspend_self();
- return;
- }
if (sig != GC_sig_suspend) {
# if defined(GC_FREEBSD_THREADS)
/* of a thread which holds the allocation lock in order */
/* to stop the world. Thus concurrent modification of the */
/* data structure is impossible. */
+
+# ifdef GC_ENABLE_SUSPEND_THREAD
+ if ((me -> flags & SUSPENDED_EXT) != 0) {
+ /* TODO: GC_with_callee_saves_pushed is redundant here. */
+ (void)GC_do_blocking(suspend_self_inner, me);
+# ifdef DEBUG_THREADS
+ GC_log_printf("Continuing %p on GC_resume_thread\n", (void *)self);
+# endif
+ RESTORE_CANCEL(cancel_state);
+ return;
+ }
+# endif
+
if (me -> stop_info.last_stop_count == my_stop_count) {
/* Duplicate signal. OK if we are retrying. */
if (!GC_retry_signals) {
# endif
}
-#ifndef GC_TIME_LIMIT
-# define GC_TIME_LIMIT 50
-#endif
-
-void GC_brief_async_signal_safe_sleep()
-{
- struct timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 1000 * GC_TIME_LIMIT / 2;
- select(0, 0, 0, 0, &tv);
-}
-
-static void *GC_CALLBACK suspend_self_inner(void *client_data) {
- GC_thread me = (GC_thread)client_data;
-
- while (me -> flags & SUSPENDED_EXT)
- GC_brief_async_signal_safe_sleep();
- return NULL;
-}
+# ifdef GC_ENABLE_SUSPEND_THREAD
+# ifndef GC_TIME_LIMIT
+# define GC_TIME_LIMIT 50
+# endif
-void suspend_self() {
- GC_thread me = GC_lookup_thread(pthread_self());
- if (me == NULL)
- ABORT("attempting to suspend unknown thread");
+ STATIC void GC_brief_async_signal_safe_sleep(void)
+ {
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000 * GC_TIME_LIMIT / 2;
+ select(0, 0, 0, 0, &tv);
+ }
- me -> flags |= SUSPENDED_EXT;
- (void)GC_do_blocking(suspend_self_inner, me);
-}
+ static void *GC_CALLBACK suspend_self_inner(void *client_data) {
+ GC_thread me = (GC_thread)client_data;
-#ifdef USE_TKILL_ON_ANDROID
- static int android_thread_kill(pid_t tid, int sig);
-#endif
-
-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");
+ while ((me -> flags & SUSPENDED_EXT) != 0) {
+ /* TODO: Use sigsuspend() instead. */
+ GC_brief_async_signal_safe_sleep();
+ }
+ return NULL;
+ }
- t -> flags |= SUSPENDED_EXT;
-# ifndef USE_TKILL_ON_ANDROID
- result = pthread_kill(t -> id, GC_sig_suspend);
-# else
- result = android_thread_kill(t -> kernel_id, GC_sig_suspend);
+# ifdef USE_TKILL_ON_ANDROID
+ static int android_thread_kill(pid_t tid, int sig);
# endif
- 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");
+ GC_API void GC_CALL GC_suspend_thread(GC_SUSPEND_THREAD_ID thread) {
+ GC_thread t;
+ int result;
+ DCL_LOCK_STATE;
+
+ LOCK();
+ t = GC_lookup_thread((pthread_t)thread);
+ if (t != NULL) {
+ t -> flags |= SUSPENDED_EXT;
+ if ((pthread_t)thread == pthread_self()) {
+ (void)GC_do_blocking(suspend_self_inner, t);
+ } else {
+# ifndef USE_TKILL_ON_ANDROID
+ result = pthread_kill(t -> id, GC_sig_suspend);
+# else
+ result = android_thread_kill(t -> kernel_id, GC_sig_suspend);
+# endif
+ switch (result) {
+ case ESRCH:
+ case 0:
+ break;
+ default:
+ ABORT("pthread_kill failed");
+ }
+ }
+ }
+ UNLOCK();
+ }
- t -> flags &= ~SUSPENDED_EXT;
-}
+ GC_API void GC_CALL GC_resume_thread(GC_SUSPEND_THREAD_ID thread) {
+ GC_thread t;
+ DCL_LOCK_STATE;
-int GC_is_thread_suspended(pthread_t thread) {
- GC_thread t = GC_lookup_thread(thread);
- if (t == NULL)
- ABORT("querying suspension state of unknown thread");
+ LOCK();
+ t = GC_lookup_thread((pthread_t)thread);
+ if (t != NULL)
+ t -> flags &= ~SUSPENDED_EXT;
+ UNLOCK();
+ }
- return (t -> flags & SUSPENDED_EXT);
-}
+ GC_API int GC_CALL GC_is_thread_suspended(GC_SUSPEND_THREAD_ID thread) {
+ GC_thread t;
+ int flags = 0;
+ DCL_LOCK_STATE;
+
+ LOCK();
+ t = GC_lookup_thread((pthread_t)thread);
+ if (t != NULL)
+ flags = t -> flags;
+ UNLOCK();
+ return (flags & SUSPENDED_EXT) != 0;
+ }
+# endif /* GC_ENABLE_SUSPEND_THREAD */
#endif /* !GC_OPENBSD_UTHREADS && !NACL */