Issue #11265 has been updated by Naohisa Goto. 親プロセス側のスレッド l@5 内で呼ばれている dlsym() で要求しているシンボルは _ex_unwind であるのがわかりました。 (下記のdbxの出力は、上記とは別の実行時になりますが、おおむね同じです。) ~~~ t@1 (l@1) stopped in _vfork at 0x7fffffff7e8dd440 0x7fffffff7e8dd440: _vfork+0x0024: bcc,a,pt %icc,_vfork+0x4c ! 0x7fffffff7e8dd468 Current function is retry_fork_async_signal_safe 3529 pid = vfork(); (dbx) lwps >l@1 running in _vfork() l@2 LWP suspended in __pollsys() l@5 LWP suspended in elf_find_sym() (dbx) lwp l@5 t@5 (l@5) stopped in elf_find_sym at 0x7fffffff7fe0eb74 0x7fffffff7fe0eb74: elf_find_sym+0x00b0: ld [%o5], %o4 (dbx) where =>[1] elf_find_sym(0x7fffffff7d0ff9e0, 0x7fffffff7d0ffbe8, 0x7fffffff7d0ffbe4, 0x7fffffff7e101510, 0x1000, 0x6c384a4), at 0x7fffffff7fe0eb74 [2] core_lookup_sym(0x7fffffff7e101510, 0x7fffffff7d0ff9e0, 0x7fffffff7d0ffbe8, 0x7fffffff7d0ffbe4, 0x20, 0x7fffffff7d0ffcfc), at 0x7fffffff7fe0c534 [3] _lookup_sym(0x2200, 0x7fffffff7d0ffbe8, 0x7fffffff7d0ffbe4, 0x7fffffff7d0ffcfc, 0x200, 0x7fffffff7fd00848), at 0x7fffffff7fe0c96c [4] lookup_sym(0x7fffffff7d0ffc00, 0x7fffffff7d0ffbe8, 0x7fffffff7d0ffbe4, 0x7fffffff7d0ffcfc, 0x6c384a4, 0x0), at 0x7fffffff7fe0cc38 [5] dlsym_core(0x200, 0x7fffffff7ff3c198, 0x7fffffff7f801188, 0x7fffffff7d0ffdb8, 0x7fffffff7d0ffcfc, 0x0), at 0x7fffffff7fe1eb68 [6] dlsym_intn(0xfffffffffffffffc, 0x7fffffff7e93c648, 0x7fffffff7f801188, 0x7fffffff7d0ffdb8, 0x0, 0x11e0f0), at 0x7fffffff7fe1edfc [7] dlsym(0xfffffffffffffffc, 0x7fffffff7e93c648, 0x0, 0xffff, 0xffbffeff, 0x1), at 0x7fffffff7fe1ef6c [8] _t_cancel(0x7fffffff7d0ff751, 0x7fffffff7e8ece0c, 0x0, 0x0, 0x7fffffff7ec01200, 0x7fffffff7ea3e000), at 0x7fffffff7e8dbaf4 [9] _thr_exit_common(0x0, 0x1c00, 0x0, 0x7fffffff7ec01200, 0x1003b8340, 0x7fffffff7ea3e000), at 0x7fffffff7e8d5088 (dbx) frame 7 0x7fffffff7fe1ef6c: dlsym+0x0030: call dlsym_check ! 0x7fffffff7fe1eeac (dbx) print (const char *)0x7fffffff7e93c648 dbx: warning: unknown language, 'c' assumed (const char *) 9223372034683422280 = 0x7fffffff7e93c648 "_ex_unwind" (dbx) ~~~ _ex_unwind() は libc の関数かもしれないため、_t_cancel() 内部で dlsym() を呼んでいるようです。 Illumos(旧OpenSolaris)の _t_cancel のソースでも確認できます。 https://github.com/illumos/illumos-gate/blob/09f79f7c66b85f056db11f58210dc6182c9b1aef/usr/src/lib/libc/port/unwind/unwind.c#L51 そして、運悪く dlsym() がロックを確保したまま vfork() が呼ばれると、 子プロセスの run-time link editor も同じロックを確保しようとしてデッドロックになるようです。 ロックを取っている場所は enter() 関数のようです。 Illumos (旧OpenSolaris)では以下のソースになっています。 https://github.com/illumos/illumos-gate/blob/09f79f7c66b85f056db11f58210dc6182c9b1aef/usr/src/cmd/sgs/rtld/common/util.c#L3188 結論として、akrさんの記憶のとおり、 http://www.oracle.com/technetwork/server-storage/solaris10/subprocess-136439.html (Oracleになって移動後の文章。内容は同一。) に記載されている vfork(2) と multi-threading の ld.so の deadlock の現象が原因と見てよさそうです。 そうなると、r50977 は、タイミングがずれて発生しにくくなっただけで本質ではなく、やはり fork() にするのが根本的解決になりそうです。 ただし、r50977 以後、何百回と繰り返していますが、1回しか再現できていません。 また、r50994 のパッチを r50976 以前に当てると、テストが停止することはなくなります。 ---------------------------------------- Bug #11265: deadlock on Solaris 10 since r50900 https://bugs.ruby-lang.org/issues/11265#change-53086 * Author: Naohisa Goto * Status: Assigned * Priority: Normal * Assignee: Naohisa Goto * 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/