ruby-trunk-changes r47360 - r47374

今日は spawn や system で使う fork(2) を vfork(2) にして高速化する変更と、dup/clone でのメモリリークの修正がありました。

akr: r47360 2014-09-03 00:47:53 +0900

r47260 からの Benchmark の時間計測を Process.clock_getclock に変更した関係で Benchmark.realtime のテストを修正していた件の続きで、assert_in_epsilon で誤差をチェックしていたのを assert_operator で sleep した時間よりも長く測定されていれば OK としています。なるほど。あれでも sleep のほうの実装で sleeptime よりも早く起床してしまう可能性は……いやこれは計測と sleep の実装(pthread_cond_timedwait(3) などのはず)で同じ時計(方法)を使ってるかどうかということなのかなぁ。

akr: r47361 2014-09-03 07:51:03 +0900

configure.in に AC_FUNC_FORK を追加して fork(2), vfork(2) のチェックをさせて(AC_CHECK_FUNCS で fork はチェックしていましたが AC_FUNC_FORK は両方チェックして HAVE_WORKING_FORK というマクロを定義してくれるそうです)これを使って fork(2) の有無を判定するように変更しています。

hsbt: r47362 2014-09-03 11:33:18 +0900

拡張ライブラリ openssl の RSA 署名検証のメモリリークのテストで ARM 上でテストした時にタイムアウトすることがあるということで、タイムアウトを延ばしています。 [ruby-core:63367] [Bug #9984]

akr: r47363 2014-09-03 12:06:17 +0900

process.c で Process.spawn や system、 popen などで fork(2) のかわりに vfork(2) を利用するようにしています。 vfork() はメモリ空間のコピー( 正確には CoW なのでページテーブルのコピー)をせずに fork() するシステムコールで、fork した子プロセスがすぐに exec するのでコピーが不要(なおかつ子プロセスで親プロセスのメモリを不用意に壊したりしないなど注意が必要、ですが ruby の spawn の実装は子プロセスで実行する内容が async-signal-safe になるようにしているので大丈夫なのだと思います)なのでより高速に子プロセスを起動できます。特にたくさんメモリを使っているプロセスの時に効果的です。

nobu: r47370 2014-09-03 14:47:31 +0900

tool/make-snapshot でバージョンの指定が X.Y.Z の時は 2.1 以降は tag を、それ以前は branch を意味するようになりましたが、 X.Y のように teeny のない指定も受け付けて、branch として解釈するようにしています。 ブランチから作るということは nightly snapshot のようなパッケージの作成用ですね。

nobu: r47371 2014-09-03 15:05:01 +0900

tool/make-snapshot で X.Y のような記法も受け付けるようになったことを usage に追加しています。

nobu: r47372 2014-09-03 16:56:09 +0900

Object#dup, clone でインスタンス変数が存在しないオブジェクトを複製した時もインスタンス変数用の配列のメモリ確保(サイズ0で)してしまっていて、コピーしたオブジェクトでインスタンス変数を代入すると再度メモリが確保されて上書きされるという memory leak があったのを修正しています。 すごいなぁ、たまにこんな根本的なところに leak が残ってたりしますよね(もしくは入り込んだか)。 [ruby-core:64700] [Bug #10191]

akr: r47373 2014-09-03 18:56:38 +0900

process.c で fork 後に親プロセスと子プロセスを区別するために forked_child という変数に 0 or 1 を代入しておいたのですが、変数ごと消しています。 fork(2) はメモリ空間を共有しないため代入しても他方に影響しない、ただし vfork(2) に替えた時にメモリ空間は共有されるようになったので、frok 直後に親プロセスで 0 を代入するようにしていました。しかしそもそもこの変数をチェックして処理を替えていた before_exec_non_async_signal_safe() は分離されていて子プロセスで呼ばれないようになっていたので、変数での区別自体不要になっていました。

akr: r47374 2014-09-03 19:23:24 +0900

process.c の関数マクロ before_fork()/after_fork() をそれぞれ before_fork_ruby()/after_fork_ruby() と改名しています。