ruby-trunk-changes r37844 - r37865

今日は Bignum の計算に割り込まれた時に計算をやりなおす修正やそもそも割り込みが有効にならない可能性があったことの修正や、シグナルのトラップハンドラが再入されないようになったなど、シグナルと割り込みのしくみの変更、修正がありました。

nagachika:r37844 2012-11-26 01:59:07 +0900

r37825 で追加した Process.setsid のテストで、親プロセスで IO.popen で作った子プロセスの pid に対して Process.getsid を呼ぶ時に既に子プロセスが終了しているからか Errno::ESRCH が発生していたので、子プロセス内で Process.getsid($$) の結果も取得して返しておくようにしています。

svn:r37845 2012-11-26 01:59:13 +0900

version.h の日付更新。

kosaki:r37846 2012-11-26 10:57:41 +0900

r37844 の Process.setsid のテストの修正の再修正。子プロセスで Process.getsid するようにしたのを、やはり親プロセスで Process.getsid するようにして、子プロセスに sleep を入れて対処しています。また親プロセス側で終了時に Process.kill で止めるようにしています。ただ SIGKILL は Windows 版で動かないかも。

nobu:r37847 2012-11-26 12:11:12 +0900

r37821 に抜けてた win32/Makefile.sub の DLNOBJ 変数の設定を追加しています。

nobu:r37848 2012-11-26 12:12:25 +0900

r37838 で変更した rb_str_enumerate_{lines, chars, codepoints} で未初期化変数の参照の警告が出ていたのを抑制しています。

kosaki:r37849 2012-11-26 15:49:48 +0900

bignum.c で Bignum の除算/剰余の計算に使う struct big_div_struct の割り込みフラグのメンバに volatile を付けています。volatile がないと最適化によりメモリを読みにいかず割り込みがきかないことがあったみたいです。

kosaki:r37850 2012-11-26 16:00:04 +0900

同じく Bignum の除算/剰余計算の bigdivrem1() で割り込みを受けた時に stop の値をチェックして計算をやりなおすようにしています。大きな数値の場合は時間がかかるので bigdivrem1() は GVL を解放して(つまり別のスレッドの実行権を明け渡して)計算するようにできています。

naruse:r37851 2012-11-26 16:37:25 +0900

ARGF には each_{byte, char, line} や bytes, chars, lines はあるのに each_codepoint, codepoints は存在していなかったので String などと同じく each_codepoint, codepoints も追加しています。 両者は同じ実装(ブロック省略時には Enumerator を返す)です。 [ruby-core:50152] [Bug #7438]

kosaki:r37852 2012-11-26 17:05:49 +0900

Signal.trap で定義したトラップハンドラ内で Thread#join を実行すると再入した時にデッドロックが発生する問題の対処として rb_thread_t::in_trap というメンバを追加して、トラップハンドラ内であることを保持するようにして、トラップハンドラ内での Thread#join は ThreadError を発生させるようにしています。 [ruby-core:44956] [Bug #6416]
このようにトラップハンドラ内で禁止される操作が定義されていくんでしょうか。トラップハンドラの再入を禁止するという方法もあるなと思うのですが。と思っていたら r37861 でトラップハンドラに再入しないようにされてました。

kosaki:r37853 2012-11-26 17:13:19 +0900

r37848 で rb_str_enumerate_{chars, codepoints} の ary の初期化を追加しましたが、その位置が if 文の中だったので不十分だったようで、変数宣言に UNINITIALIZED_VAR() というマクロを利用して未初期化変数の警告抑制するようにしています。

ko1:r37854 2012-11-26 18:19:00 +0900

make benchmark のオプションに -e で複数の実行体を指定する時にセミコロンで区切るのではなくて複数回 -e オプションを指定する方法ができるようにしています。 また指定したラベルとは別に ruby -v によるバージョン番号を自動的にヘッダに含めるようにしています。 [ruby-core:50139] [Bug #7380]

kosaki:r37855 2012-11-26 18:22:01 +0900

rb_threadptr_interrupt_common() という関数でスレッドへの割り込みを通知する内容はこれまでメインスレッドへのシグナルのトラップハンドラ実行の通知と、全スレッドが対象になる非同期の例外や(Thread#raise) や Thread#kill での停止の通知が一緒になっていたのを、ビットフラグを分けて別々に通知するようにして、関数も rb_threadptr_trap_interrupt() と rb_threadptr_interrupt() に分けています。
もしかしたらメインスレッド以外でもトラップハンドラを実行するようにする前触れとかでしょうか。と思ったら、r37861 でシグナルの割り込みをマスクしてトラップハンドラに再入しないようにしているのでそのためだったようです。

kosaki:r37856 2012-11-26 18:25:47 +0900

signal_exec() で EXEC_TAG() (ひいては setjmp()) を使っているので変数 signum について警告が出力されていたので宣言する位置を内側のスコープに移動しています。 同じスコープに old_in_trap という変数もありますがこれについての対処は次のコミットで。

kosaki:r37857 2012-11-26 18:28:35 +0900

r37856 と同じく signal_exec() で old_in_trap という変数に volatile を付けて、また初期化を setjmp() の後に移動して setjmp() によって値が不定になる問題を回避しています。これって代入を後にするのも必要なんでしたっけ。

ko1:r37858 2012-11-26 18:30:32 +0900

make benchmark の実行体の指定にビルドディレクトリでビルドした実行体のラベルに built-ruby が表示されるようにオプションで指定しています。

ko1:r37859 2012-11-26 19:14:01 +0900

bootstraptest/test_thread.rb で 10000 個 Thread を作るというテストを 100 個作っては全て join で待つというのを 100 回繰り返すというふうに変更しています。 Travis-CI でこのテストが時間をかけすぎてタイムアウトしていたための対処ということですが、そもそもこのテストは何をチェックしたかったんでしょう。

ko1:r37860 2012-11-26 19:46:01 +0900

RubyVM::InstructionSequence.compile_option が trace_instruction オプションの値を返していなかったので追加しています。 しかしこのオプションは今どこにも使われてなさそうですね。 [ruby-core:46711] [Bug #6786]

kosaki:r37861 2012-11-26 19:57:39 +0900

rb_thread_t::interrupt_mask という構造体メンバを追加して、割り込みの種別毎にマスクをかけることができるようにています。このため rb_thread_t::interrupt_flag を参照しているところを RUBY_VM_INTERRUPTED_ANY() という関数マクロ経由でマスクしたビットを除いたビットフラグを参照するように変更しています。また rb_threadptr_execute_interrupts() でマスクされたビットは残して atomic な交換をするために ATOMIC_CAS (Compare And Swap) マクロを ruby_atomic.h に追加しています。流行りの(?)ロックフリーってやつですね。そしてこの新しいしくみを使って、signal_exec() でトラップハンドラを実行中に trap_interrupt(0x08) をマスクするようにしています。つまりトラップハンドラは再入しないようになったわけですね。 [ruby-core:42524] [Bug #6009]

usa:r37862 2012-11-26 20:25:45 +0900

r37851 で追加した ARGF.chars のテストで子プロセスから改行を含む結果を Marshal.dump したものを pipe 経由で読んでいたのが Windows ではテキストモードで読むと改行コードが変換されてしまって Marshal.load 失敗するので base64 エンコードして受け渡すように変更しています。 bytes や codepoints のテストも同じように対処したほうがいいでしょうか。

kosaki:r37863 2012-11-26 20:45:39 +0900

r37852 でシグナルトラップハンドラ内での Thread#join を禁止するために導入した rb_thread_t::in_trap を削除して、かわりに interrupt_mask で trap_interrupt(0x08) がマスクされているかどうかをトラップハンドラ内かどうかの判定に使っています。 ところで今更ですが Signal.trap のハンドラ内で Thread#join が明示的に禁止されたことは NEWS にも書いたほうがいいのではないでしょうか。

kosaki:r37864 2012-11-26 21:17:10 +0900

rb_thread_t::interrupt_flag のビットフラグが各所で magic number として埋め込まれていたのを enum で定数として定義して使うようにしています。 これも先程から指摘しようと思っていたら修正されていてさすがです。

kosaki:r37865 2012-11-26 22:47:23 +0900

Thread 内で ensure 節で sleep するようなコードがあるとプロセス終了時の rb_thread_terminate_all() で各 Thread を一度だけ kill してから終了を待つのに rb_thread_schedule() をはさんで待つためビジーループ状態になるので、native_sleep() を使って CPU 時間を食わずに待つようにして、終了したスレッドはメインスレッドに割り込みを送って起こすようにしています。とりあえず CPU を使わないようにしただけで、プロセスが止まらないのはそのままとなっています。この先どうするかはチケットでさらに議論(というかまつもとさんの意見)を待つようです。 [ruby-dev:44546] [Bug #5368]