Skip to content

Instantly share code, notes, and snippets.

@shirok
Created June 1, 2012 01:28
Show Gist options
  • Select an option

  • Save shirok/2847902 to your computer and use it in GitHub Desktop.

Select an option

Save shirok/2847902 to your computer and use it in GitHub Desktop.
diff --git a/ChangeLog b/ChangeLog
index 6b06cc3..344d74f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2012-05-31 Shiro Kawai <shiro@acm.org>
+
+ * ext/threads/thread.c (Scm_ThreadTerminate): Fixed SEGV bug when
+ thread-terminate! is called on a thread that's not running.
+
2012-05-28 Shiro Kawai <shiro@acm.org>
* gc/dyn_load.c: Backport a patch for NetBSD 6.
@@ -6,8 +11,8 @@
2012-05-27 Shiro Kawai <shiro@acm.org>
- * src/port.c (Scm__SetupPortsForWindows): Protect the origina
- scm_stdout and scm_stderr to be GC-ed, for not having fd 1 and 2
+ * src/port.c (Scm__SetupPortsForWindows): Protect the original
+ scm_stdout and scm_stderr from being GC-ed, for not having fd 1 and 2
open causes problems when spawning child processes and communicate
with them via pipes. Thanks to @natsutan for tracking the problem.
* src/main.c (init_console): make sure fd 0, 1, and 2 are redirected
diff --git a/ext/threads/test.scm b/ext/threads/test.scm
index 9ef7f29..da43cdb 100644
--- a/ext/threads/test.scm
+++ b/ext/threads/test.scm
@@ -100,6 +100,18 @@
(thread-terminate! t1)
(thread-join! t1))))
+;; this SEGVs on 0.9.3.3. test code from @cryks.
+(test* "thread termination before running" 'terminated
+ (let1 t1 (make-thread (^[] #f))
+ (thread-terminate! t1)
+ (thread-state t1)))
+
+(test* "thread termination while being stopped" 'terminated
+ (let1 t1 (thread-start! (make-thread (^[] (let loop () (loop)))))
+ (thread-stop! t1)
+ (thread-terminate! t1)
+ (thread-state t1)))
+
;;---------------------------------------------------------------------
(test-section "thread and error")
diff --git a/ext/threads/threads.c b/ext/threads/threads.c
index e60a91e..1ab1aac 100644
--- a/ext/threads/threads.c
+++ b/ext/threads/threads.c
@@ -432,36 +432,41 @@ ScmObj Scm_ThreadTerminate(ScmVM *target)
}
(void)SCM_INTERNAL_MUTEX_LOCK(target->vmlock);
- do {
- /* This ensures only the first call of thread-terminate! on a thread
- is in effect. */
- if (target->canceller == NULL) {
- target->canceller = vm;
-
- /* First try */
- target->stopRequest = SCM_VM_REQUEST_TERMINATE;
- target->attentionRequest = TRUE;
- if (wait_for_termination(target)) break;
-
- /* Second try */
+ if (target->state == SCM_VM_RUNNABLE || target->state == SCM_VM_STOPPED) {
+ do {
+ /* This ensures only the first call of thread-terminate! on a
+ thread is in effect. */
+ if (target->canceller == NULL) {
+ target->canceller = vm;
+
+ /* First try */
+ target->stopRequest = SCM_VM_REQUEST_TERMINATE;
+ target->attentionRequest = TRUE;
+ if (wait_for_termination(target)) break;
+
+ /* Second try */
+ SCM_ASSERT(target->thread);
#if defined(GAUCHE_USE_PTHREADS)
# if defined(GAUCHE_PTHREAD_SIGNAL)
- pthread_kill(target->thread, GAUCHE_PTHREAD_SIGNAL);
+ pthread_kill(target->thread, GAUCHE_PTHREAD_SIGNAL);
# endif /*defined(GAUCHE_PTHREAD_SIGNAL)*/
#elif defined(GAUCHE_USE_WTHREADS)
- /* TODO: implement signal mechanism using an event */
+ /* TODO: implement signal mechanism using an event */
#endif /* defined(GAUCHE_USE_WTHREADS) */
- if (wait_for_termination(target)) break;
+ if (wait_for_termination(target)) break;
- /* Last resort */
- thread_cleanup_inner(target);
+ /* Last resort */
+ thread_cleanup_inner(target);
#if defined(GAUCHE_USE_PTHREADS)
- pthread_cancel(target->thread);
+ pthread_cancel(target->thread);
#elif defined(GAUCHE_USE_WTHREADS)
- TerminateThread(target->thread, 0);
+ TerminateThread(target->thread, 0);
#endif
- }
- } while (0);
+ }
+ } while (0);
+ }
+ /* target either is terminated or hasn't been run */
+ target->state = SCM_VM_TERMINATED;
(void)SCM_INTERNAL_MUTEX_UNLOCK(target->vmlock);
return SCM_UNDEFINED;
}
diff --git a/test/control.scm b/test/control.scm
index bd280df..72754b9 100644
--- a/test/control.scm
+++ b/test/control.scm
@@ -72,7 +72,7 @@
;;
(cond-expand
- [gauche.sys.pthreads
+ [gauche.sys.threads
(test-section "control.thread-pool")
(use control.thread-pool)
(test-module 'control.thread-pool)
@@ -173,7 +173,15 @@
(let1 xjob (add-job! pool work)
(terminate-all! pool :force-timeout 0.05)
(job-status xjob))))
- ]
+
+ ;; This SEGVs on 0.9.3.3 (test code by @cryks)
+ (test* "thread pool termination" 'terminated
+ (let ([t (thread-start! (make-thread (cut undefined)))]
+ [pool (make-thread-pool 10)])
+ (terminate-all! pool)
+ (thread-terminate! t)
+ (thread-state t)))
+ ] ; gauche.sys.pthreads
[else])
(test-end)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment