1.9のスレッドがあやしいらしい

http://www.rubyist.net/~matz/20070525.html#p04
http://ujihisa.nowa.jp/entry/c419349c59

怪しいところがあったので書いておく。


これだけじゃよく分からないので試してみる。

require 'thread'

Thread.abort_on_exception = true
$val = 1

for i in 0..100
  Thread.start(i) do |thread_num|
    Thread.current[:name] = "Thread_#{thread_num}"
    srand
    while 1
      val = rand
      puts "Before:#{Thread.current[:name]}: g:#{$val} l:#{val}"
      $val = val
      puts "After :#{Thread.current[:name]}: g:#{$val} l:#{val}"
      #Thread.pass
    end
  end
end

while 1
  sleep 10
end


1.8系では落ちない。
というか生成されるスレッド数が少ないし、スレッド遷移が遅すぎ。
1.9系ではスレッド数は多いし、スレッド遷移もスムーズ。
まあ、1.9はネイティブスレッドなので当たり前だけど。


で1.9ではCtrl-Cで止めるとcore dumpする。
coreを見ようとlsしてもない。
どうやらulimit -c 0されている。
最近はこれがデフォルト?


でcoreを作ってgdbで見ると、SIGSEV。

(gdb) bt
#0  0x080f30a3 in err_position_0 (buf=0xb7d1f068 "", len=8192, file=0x811fbcb "{}[]<>()~&|\\$;'`\"\n",
    line=0) at error.c:42
#1  0x080f30fd in err_position (buf=0x0, len=0) at error.c:48
#2  0x080f43ce in rb_bug (fmt=0x8122bf5 ";\v\b\221=\v\b�=\v\b+=\v\b�>\v\bSignal") at error.c:216
#3  0x080b51a6 in sigsegv (sig=11) at signal.c:533
#4  
#5  0xb7f7a3af in pthread_kill () from /lib/tls/i686/cmov/libpthread.so.0
#6  0x080dcf4d in ubf_select_each (th=) at thread_pthread.ci:316
#7  0x080de23c in thread_timer (dummy=0x0) at thread_pthread.ci:491
#8  0xb7f7531b in start_thread () from /lib/tls/i686/cmov/libpthread.so.0
#9  0xb7ea457e in clone () from /lib/tls/i686/cmov/libc.so.6


なんとなくthread_pthread.ciのFGLOCK()辺りが怪しい。

〜省略〜
GLOCK(&signal_thread_list_lock, {
〜省略〜


//GLOCKの実体
#define FGLOCK(lock, body) do { \
    native_mutex_lock(lock); \
    { \
  body; \
    } \
    native_mutex_unlock(lock); \
} while (0)


でsignal_thread_list_lockって何者かというと、グローバル変数

static rb_thread_lock_t signal_thread_list_lock;


native_mutex_lock()はthread_mutex_lock()の単なるラッパ。
まあ、Pthread(というかスレッド)はグローバル変数は全スレッド共有。
すごい便利だけど、すごく危険。
まあ、こういう怪しいグローバル変数にはとりあえずvolatileを付ければいい。
(本当はPthreadの規格にはvolatileを付けろとは書いてないバッドノウハウ)

volatile static rb_thread_lock_t signal_thread_list_lock;

こんな感じで再コンパイルすると、とりあえずcore dumpしない。
まじめに直すならこの変数が関わるところを見直しが必要かな。
このままだと、コンパイル出来るけどvolatileのせいで、警告もでるし。


ついでにもう少しスレッド系を見てみる。

pthread_mutex_lock(&thread_cache_lock);

戻り値見ないと危ないよ。
ロック対象のデータが壊れている可能性有り。
エラーならこれ以降処理しないように。

//thread_win32.ci
int native_mutex_lock(rb_thread_lock_t *lock)

//thread_pthread.ci
void native_mutex_lock(pthread_mutex_t *lock)

native_mutex_lock()っておそらくWindowsUnix系でスレッド実装が違うから
こういうのがあるんだと思う。
でも戻り値も引数も違うのはいいのだろうか?


始めの問題だけなら、軽くパッチでも作って送ろうと思ったけど、
ちょっと見ただけでこれではパッチがすごい多そうなので止めておく。
メーリングリストにも入っていないし。


誰かが気づいて修正してくれるのを期待しておこう。