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/