From: Hidetoshi NAGAI Date: 2003-11-19T17:39:41+09:00 Subject: [ruby-dev:21961] Re: pthread trouble on tcltklib 永井@知能.九工大です. From: Tietew Subject: [ruby-dev:21960] Re: pthread trouble on tcltklib Date: Wed, 19 Nov 2003 16:08:41 +0900 Message-ID: <20031119155353.75E3.TIETEW-ML-RUBY-DEV@tietew.net> > これは tk でもことですよね。今後 pthread を使うライブラリが出た > として,問題が起こらないことは保証できません。それならばいっそ, > bug で落とした方がよいです。 わかりました. では pthread 絡みのトラブルはすべて拡張ライブラリ側で 何とかするということで. 拡張ライブラリ側での対処をやりやすくするように, current native thread が ruby の native thread かを 返す関数を用意することにしましょう. patch を添えますので,ご確認ください. > というか,tk でも固まらなくなったのは「たまたま」で,やっぱり問 > 題が起こらないとは言い切れないですし。この場合,ext/tk > (ext/tcltklib?) をシリアライズするよう修正すべきです。 修正するまでは Tcl_eval の呼び出しでは忘れていましたが, ruby からの呼び出しはシリアライズしています. で,イベントループも Tcl 側ではなく,tcltklib 側で管理して 複数イベントが同時には処理されないようにしてました. でも起きてしまったというのが頭の痛いところです. もちろん,debug 中には Tcl 側からの ruby 呼び出しが 複数スレッドから一切行われないようにすることも試しましたが, それでは解決しませんでしたし,実際,複数の native thread から 呼び出しが生じること自体ありませんでした. ですので,tcltklib での問題はそういうことではないと思います. # シグナル処理かなぁ... -- 永井 秀利 (九工大 知能情報) nagai@ai.kyutech.ac.jp Index: ruby.h =================================================================== RCS file: /src/ruby/ruby.h,v retrieving revision 1.90 diff -u -r1.90 ruby.h --- ruby.h 14 Oct 2003 02:53:53 -0000 1.90 +++ ruby.h 19 Nov 2003 08:39:03 -0000 @@ -671,6 +671,21 @@ static char *dln_libs_to_be_linked[] = { EXTLIB, 0 }; #endif +#if defined(HAVE_LIBPTHREAD) +typedef pthread_t rb_nativethread_t; +# define NATIVETHREAD_CURRENT() pthread_self() +# define NATIVETHREAD_EQUAL(t1,t2) pthread_equal((t1),(t2)) +# define HAVE_NATIVETHREAD +#elif defined(_WIN32) || defined(_WIN32_WCE) || defined(__CYGWIN__) +typedef DWORD rb_nativethread_t; +# define NATIVETHREAD_CURRENT() GetCurrentThreadId() +# define NATIVETHREAD_EQUAL(t1,t2) ((t1) == (t2)) +# define HAVE_NATIVETHREAD +#endif +#ifdef HAVE_NATIVETHREAD +RUBY_EXTERN int is_ruby_native_thread(); +#endif + #if defined(__cplusplus) } /* extern "C" { */ #endif Index: eval.c =================================================================== RCS file: /src/ruby/eval.c,v retrieving revision 1.590 diff -u -r1.590 eval.c --- eval.c 16 Nov 2003 09:11:01 -0000 1.590 +++ eval.c 19 Nov 2003 08:39:05 -0000 @@ -33,10 +33,6 @@ #include "st.h" #include "dln.h" -#if defined(HAVE_LIBPTHREAD) && defined(USE_PTHREAD_EXTLIB) -#include -#endif - #ifdef __APPLE__ #include #endif @@ -1161,6 +1157,14 @@ void Init_heap _((void)); void Init_ext _((void)); +#ifdef HAVE_NATIVETHREAD +rb_nativethread_t ruby_thid; +int +is_ruby_native_thread() { + return NATIVETHREAD_EQUAL(ruby_thid, NATIVETHREAD_CURRENT()); +} +#endif + void ruby_init() { @@ -1172,6 +1176,9 @@ if (initialized) return; initialized = 1; +#ifdef HAVE_NATIVETHREAD + ruby_thid = NATIVETHREAD_CURRENT(); +#endif ruby_frame = top_frame = &frame; ruby_iter = &iter; @@ -8647,11 +8654,6 @@ return test; } -#if defined(HAVE_LIBPTHREAD) && defined(USE_PTHREAD_EXTLIB) -static pthread_t thid; -static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; -#endif - void rb_thread_schedule() { @@ -8668,10 +8670,12 @@ int n, max; int need_select = 0; int select_timeout = 0; -#if defined(HAVE_LIBPTHREAD) && defined(USE_PTHREAD_EXTLIB) - int st; -#endif +#ifdef HAVE_NATIVETHREAD + if (!is_ruby_native_thread()) { + rb_bug("cross-thread violation on rb_thread_schedule()"); + } +#endif rb_thread_pending = 0; if (curr_thread == curr_thread->next && curr_thread->status == THREAD_RUNNABLE) @@ -8680,16 +8684,6 @@ next = 0; curr = curr_thread; /* starting thread */ -#if defined(HAVE_LIBPTHREAD) && defined(USE_PTHREAD_EXTLIB) - if ((st = pthread_mutex_trylock(&mtx)) == EBUSY) { - if (pthread_self() != thid) { - return; - } - } else { - thid = pthread_self(); - } -#endif - while (curr->status == THREAD_KILLED) { curr = curr->prev; } @@ -8887,22 +8881,12 @@ } next->wait_for = 0; if (next->status == THREAD_RUNNABLE && next == curr_thread) { -#if defined(HAVE_LIBPTHREAD) && defined(USE_PTHREAD_EXTLIB) - if (st != EBUSY) { - pthread_mutex_unlock(& mtx); - } -#endif return; } /* context switch */ if (curr == curr_thread) { if (THREAD_SAVE_CONTEXT(curr)) { -#if defined(HAVE_LIBPTHREAD) && defined(USE_PTHREAD_EXTLIB) - if (st != EBUSY) { - pthread_mutex_unlock(& mtx); - } -#endif return; } } @@ -8912,19 +8896,9 @@ if (!(next->flags & THREAD_TERMINATING)) { next->flags |= THREAD_TERMINATING; /* terminate; execute ensure-clause if any */ -#if defined(HAVE_LIBPTHREAD) && defined(USE_PTHREAD_EXTLIB) - if (st != EBUSY) { - pthread_mutex_unlock(& mtx); - } -#endif rb_thread_restore_context(next, RESTORE_FATAL); } } -#if defined(HAVE_LIBPTHREAD) && defined(USE_PTHREAD_EXTLIB) - if (st != EBUSY) { - pthread_mutex_unlock(& mtx); - } -#endif rb_thread_restore_context(next, RESTORE_NORMAL); } Index: gc.c =================================================================== RCS file: /src/ruby/gc.c,v retrieving revision 1.160 diff -u -r1.160 gc.c --- gc.c 20 Oct 2003 02:06:39 -0000 1.160 +++ gc.c 19 Nov 2003 08:39:05 -0000 @@ -1216,6 +1216,11 @@ jmp_buf save_regs_gc_mark; SET_STACK_END; +#ifdef HAVE_NATIVETHREAD + if (!is_ruby_native_thread()) { + rb_bug("cross-thread violation on rb_gc()"); + } +#endif if (dont_gc || during_gc) { if (!freelist) { add_heap(); Index: configure.in =================================================================== RCS file: /src/ruby/configure.in,v retrieving revision 1.191 diff -u -r1.191 configure.in --- configure.in 8 Nov 2003 04:53:14 -0000 1.191 +++ configure.in 19 Nov 2003 08:39:05 -0000 @@ -662,52 +662,58 @@ ], rb_cv_stack_grow_dir=-1, rb_cv_stack_grow_dir=+1, rb_cv_stack_grow_dir=0)]) AC_DEFINE_UNQUOTED(STACK_GROW_DIRECTION, $rb_cv_stack_grow_dir) -dnl default value for $KANJI -DEFAULT_KCODE="KCODE_NONE" - -AC_ARG_WITH(pthread-ext, - [ --with-pthread-ext use pthread library on external modules ], - [AC_DEFINE(USE_PTHREAD_EXTLIB) - AC_CHECK_LIB(pthread, pthread_mutex_init, - rb_use_pthread_ext=yes, rb_use_pthread_ext=no) - if test "$rb_use_pthread_ext" = "no"; then - AC_CHECK_LIB(pthread, __pthread_mutex_init, - rb_use_pthread_ext=yes, rb_use_pthread_ext=no) - fi - if test "$rb_use_pthread_ext" = "yes"; then - LIBS="-lpthread $LIBS" - AC_DEFINE(_REENTRANT) - AC_DEFINE(_THREAD_SAFE) - AC_DEFINE(HAVE_LIBPTHREAD) - else - AC_CHECK_LIB(pthreads, pthread_mutex_init, - rb_use_pthread_ext=yes, rb_use_pthread_ext=no) - if test "$rb_use_pthread_ext" = "yes"; then - LIBS="-lpthreads $LIBS" +AC_CHECK_LIB(pthread, pthread_mutex_init, + rb_with_pthread=yes, rb_with_pthread=no) +if test "$rb_with_pthread" = "no"; then + AC_CHECK_LIB(pthread, __pthread_mutex_init, + rb_with_pthread=yes, rb_with_pthread=no) +fi +if test "$rb_with_pthread" = "yes"; then + LIBS="-lpthread $LIBS" + AC_DEFINE(_REENTRANT) + AC_DEFINE(_THREAD_SAFE) + AC_DEFINE(HAVE_LIBPTHREAD) +else + AC_CHECK_LIB(pthreads, pthread_mutex_init, + rb_with_pthread=yes, rb_with_pthread=no) + if test "$rb_with_pthread" = "yes"; then + LIBS="-lpthreads $LIBS" + AC_DEFINE(_REENTRANT) + AC_DEFINE(_THREAD_SAFE) + AC_DEFINE(HAVE_LIBPTHREAD) + else + AC_CHECK_LIB(c, pthread_mutex_init, + rb_with_pthread=yes, rb_with_pthread=no) + if test "$rb_with_pthread" = "yes"; then + AC_DEFINE(_REENTRANT) + AC_DEFINE(_THREAD_SAFE) + AC_DEFINE(HAVE_LIBPTHREAD) + else + AC_CHECK_LIB(c_r, pthread_mutex_init, + rb_with_pthread=yes, rb_with_pthread=no) + if test "$rb_with_pthread" = "yes"; then + if test "$with_libc_r" = "yes"; then + if test "$rb_cv_supplementary_lib_c_r" = "yes"; then + AC_DEFINE(_REENTRANT) + AC_DEFINE(_THREAD_SAFE) + AC_DEFINE(HAVE_LIBPTHREAD) + MAINLIBS="-pthread $MAINLIBS" + fi + else + MAINLIBS="-pthread $MAINLIBS" AC_DEFINE(_REENTRANT) AC_DEFINE(_THREAD_SAFE) AC_DEFINE(HAVE_LIBPTHREAD) - else - AC_CHECK_LIB(c_r, pthread_mutex_init, - rb_use_pthread_ext=yes, rb_use_pthread_ext=no) - if test "$rb_use_pthread_ext" = "yes"; then - if test "$with_libc_r" = "yes"; then - if test "$rb_cv_supplementary_lib_c_r" = "yes"; then - AC_DEFINE(_REENTRANT) - AC_DEFINE(_THREAD_SAFE) - AC_DEFINE(HAVE_LIBPTHREAD) - MAINLIBS="-pthread $MAINLIBS" - fi - else - MAINLIBS="-pthread $MAINLIBS" - AC_DEFINE(_REENTRANT) - AC_DEFINE(_THREAD_SAFE) - AC_DEFINE(HAVE_LIBPTHREAD) - fi - fi fi + else + AC_MSG_WARN("Don't know how to find pthread library on your system -- thread support disabled") fi - ]) + fi + fi +fi + +dnl default value for $KANJI +DEFAULT_KCODE="KCODE_NONE" AC_ARG_WITH(default-kcode, [ --with-default-kcode=CODE specify default value for \$KCODE (utf8|euc|sjis|none)],