[ruby-dev:49120] [Ruby trunk - Bug #11265] deadlock on Solaris 10 since r50900

From: ngotogenome@...
Date: 2015-06-19 09:43:44 UTC
List: ruby-dev #49120
Issue #11265 has been updated by Naohisa Goto.


process.c の1260行目付近に以下の記述があります。

~~~
    envp = envp_str ? (char **)RSTRING_PTR(envp_str) : NULL;
    if (envp_str)
        execve(prog, argv, envp); /* async-signal-safe */
    else
        execv(prog, argv); /* async-signal-safe */
~~~

しかし、Solaris 10 の man exec(2) によると、execve は確かに async-signal-safe ですが、
コメント部分の記述に反して、execv は NOT async-signal-safe です。

そこで、以下のようにして popen を呼ぶ際に環境変数を与えて execve を呼ばせるようにすると、デッドロックは発生しなくなりました。

~~~
diff --git a/test/lib/test/unit.rb b/test/lib/test/unit.rb
index 9d9ff4b..6c527a8 100644
--- a/test/lib/test/unit.rb
+++ b/test/lib/test/unit.rb
@@ -148,7 +148,7 @@ module Test
 
       class Worker
         def self.launch(ruby,args=[])
-          io = IO.popen([*ruby,
+          io = IO.popen({"DUMMY"=>"test"}, [*ruby,
                         "#{File.dirname(__FILE__)}/unit/parallel.rb",
                         *args], "rb+")
           new(io, io.pid, :waiting)
~~~

単にenvpstr作成処理が間に入ったのでタイミングが微妙にずれて掬われただけの可能性も残ってはいますが、仮にそうであったとしても、async-signal-safe であるべき場所でそれが保証されない関数を呼ぶのは、やはり好ましくないと思います。

つまり、横着せずに必ず envp を自前で作成して execve を呼ぶ必要があるということになりますが、
それには、メモリ確保の必要があるので async-signal-safe が不要な場所で予め envpstr を作成した上で渡すことになり、API変更が必要になりそうです。

なお、execv が not async-signal-safe なのは Linux でも同様のようです。



----------------------------------------
Bug #11265: deadlock on Solaris 10 since r50900
https://bugs.ruby-lang.org/issues/11265#change-53049

* Author: Naohisa Goto
* Status: Open
* Priority: Normal
* Assignee: 
* ruby -v: -
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN
----------------------------------------
Solaris10にて、r50900 以降、
 TestParallel::TestParallel#test_jobs_status
 TestParallel::TestParallel#test_separate
のいずれか、または両方で、テストが停止状態となり次に進まなくなります。
スレッドのデッドロックが発生しているような感じです。

ところで、こういう場合の上手いデバッグ方法って何があるでしょうか?




-- 
https://bugs.ruby-lang.org/

In This Thread

Prev Next