永井@知能.九工大です.

tcltklib.c 側での対処をあきらめて,
Ruby 本体の eval.c と signal.c への patch として作ってみました.
これで GC や Thread switching が生じても落ちずに済んでいるようです.
とりあえずのテスト用なので,#ifdef などではくくっていません.
試してみていただけないでしょうか.

# もしかすると,これで pthread 依存のライブラリへの耐性が
# 少し上がっているかも...ってほどは世の中甘くないか.(^_^)

Index: Makefile.in
===================================================================
RCS file: /src/ruby/Makefile.in,v
retrieving revision 1.50
diff -u -r1.50 Makefile.in
--- Makefile.in	5 Nov 2003 02:15:26 -0000	1.50
+++ Makefile.in	5 Nov 2003 03:33:23 -0000
@@ -26,7 +26,7 @@
 LDFLAGS = @STATIC@ $(CFLAGS) @LDFLAGS@
 EXTLDFLAGS = 
 XLDFLAGS = @XLDFLAGS@ $(EXTLDFLAGS)
-EXTLIBS = 
+EXTLIBS = -lpthread
 LIBS = @LIBS@ $(EXTLIBS)
 MISSING = @LIBOBJS@ @ALLOCA@
 LDSHARED = @LIBRUBY_LDSHARED@
Index: eval.c
===================================================================
RCS file: /src/ruby/eval.c,v
retrieving revision 1.583
diff -u -r1.583 eval.c
--- eval.c	4 Nov 2003 09:13:56 -0000	1.583
+++ eval.c	5 Nov 2003 03:33:27 -0000
@@ -32,6 +32,7 @@
 #include <setjmp.h>
 #include "st.h"
 #include "dln.h"
+#include <pthread.h>
 
 #ifdef __APPLE__
 #include <crt_externs.h>
@@ -8604,6 +8615,9 @@
     return test;
 }
 
+static pthread_t thid;
+static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
+
 void
 rb_thread_schedule()
 {
@@ -8621,6 +8635,8 @@
     int need_select = 0;
     int select_timeout = 0;
 
+    int st;
+
     rb_thread_pending = 0;
     if (curr_thread == curr_thread->next
 	&& curr_thread->status == THREAD_RUNNABLE)
@@ -8629,6 +8645,14 @@
     next = 0;
     curr = curr_thread;		/* starting thread */
 
+    if ((st = pthread_mutex_trylock(&mtx)) == EBUSY) {
+	if (pthread_self() != thid) {
+	    return;
+	}
+    } else {
+	thid = pthread_self();
+    }
+
     while (curr->status == THREAD_KILLED) {
 	curr = curr->prev;
     }
@@ -8826,12 +8850,18 @@
     }
     next->wait_for = 0;
     if (next->status == THREAD_RUNNABLE && next == curr_thread) {
+	if (st != EBUSY) {
+	    pthread_mutex_unlock(& mtx);
+	}
 	return;
     }
 
     /* context switch */
     if (curr == curr_thread) {
 	if (THREAD_SAVE_CONTEXT(curr)) {
+	    if (st != EBUSY) {
+		pthread_mutex_unlock(& mtx);
+	    }
 	    return;
 	}
     }
@@ -8841,8 +8871,14 @@
 	if (!(next->flags & THREAD_TERMINATING)) {
 	    next->flags |= THREAD_TERMINATING;
 	    /* terminate; execute ensure-clause if any */
+	    if (st != EBUSY) {
+		pthread_mutex_unlock(& mtx);
+	    }
 	    rb_thread_restore_context(next, RESTORE_FATAL);
 	}
+    }
+    if (st != EBUSY) {
+	pthread_mutex_unlock(& mtx);
     }
     rb_thread_restore_context(next, RESTORE_NORMAL);
 }
Index: signal.c
===================================================================
RCS file: /src/ruby/signal.c,v
retrieving revision 1.48
diff -u -r1.48 signal.c
--- signal.c	1 Oct 2003 15:14:22 -0000	1.48
+++ signal.c	5 Nov 2003 03:33:27 -0000
@@ -711,6 +711,7 @@
 {
 #ifndef MACOS_UNUSE_SIGNAL
     VALUE mSignal = rb_define_module("Signal");
+    VALUE oldsig;
 
     rb_define_global_function("trap", sig_trap, -1);
     rb_define_module_function(mSignal, "trap", sig_trap, -1);
@@ -741,6 +742,21 @@
 #endif
 #ifdef SIGPIPE
     install_sighandler(SIGPIPE, sigpipe);
+#endif
+
+#ifdef SIGCLD
+    oldsig = rb_funcall(rb_mKernel, rb_intern("trap"), 2, 
+			INT2FIX(SIGCLD), rb_str_new2("SIG_DFL"));
+    if (oldsig != Qnil) {
+      rb_funcall(rb_mKernel, rb_intern("trap"), 2, INT2FIX(SIGCLD), oldsig);
+    }
+#endif
+#ifdef SIGCHLD
+    oldsig = rb_funcall(rb_mKernel, rb_intern("trap"), 2, 
+			INT2FIX(SIGCHLD), rb_str_new2("SIG_DFL"));
+    if (oldsig != Qnil) {
+      rb_funcall(rb_mKernel, rb_intern("trap"), 2, INT2FIX(SIGCHLD), oldsig);
+    }
 #endif
 #endif /* MACOS_UNUSE_SIGNAL */
 }

-- 
                                         永井 秀利 (九工大 知能情報)
                                             nagai / ai.kyutech.ac.jp