kzk さんに教えてもらったネタ
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6336770
Javaは新しいプロセス作るときに、ファイルディスクリプタを全部閉じようとするけども、実装がバグっているのでデッドロックが起きる可能性があるそうだ。
てきとうに見つけたクロスリファレンスサイトから引用すると
http://www.jiema.org/xref/openjdk/jdk7/jdk/src/solaris/native/java/lang/UNIXProcess_md.c#293
fork-and-exec処理の時のディスクリプタ全クローズ処理で、よりにもよってopendir()。ここでmalloc()が発生。あぼーん。
なんで、UNIX系OSってcloseall()システムコールがないんだろうね。困ったもんだ
追記: Linux限定の話でいうと /proc/{pid}/statusのFDSizeフィールドがmax fdを表しているので、3からFDSizeまでcloseしていけば、OKなんじゃないかという気がしてきた。誰か検証プリーズ
追記2: ついでにRubyの実装をちらりと見たけど、NOFILEまでしかクローズしていないから最大ファイルディスクリプタが動的なシステムだとリークしているっぽい。今度、akrさんあたりに真相を聞いてみよう。
追記3: glibc malloc はpthread_atfork()を使って、fork前後でmutexを取っているので、forkとexecの間でmalloc()呼んでも平気。これはtcmallocのような外部mallocを使った場合のみに問題になりそう
追記4: いくつかのページで sysconf(_SC_OPEN_MAX)を薦めているところがあったけど、これ、Linuxではうまくいかない。getrlimit()で現在のlimitを取っているだけなので、ファイルを開いた後で最大値を下げられたら、ちゃんとハンドリングできない。まあ、普通の人はそんな事しない。という指摘は正しいと思います
追記5: forkとexecの間はasync signal safeしかダメって話は以前にも書いたので、そっちも見てね
http://mkosaki.blog46.fc2.com/blog-entry-886.html
追記6: kzkさんに指摘されて気づいたけど、これが記念すべき1000エントリ目かー。妙に感慨深いな
追記7: kzkさんの関連エントリも参照のこと。
http://kzk9.net/blog/2009/09/deadlock_on_process_builder.html
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6336770
Javaは新しいプロセス作るときに、ファイルディスクリプタを全部閉じようとするけども、実装がバグっているのでデッドロックが起きる可能性があるそうだ。
てきとうに見つけたクロスリファレンスサイトから引用すると
http://www.jiema.org/xref/openjdk/jdk7/jdk/src/solaris/native/java/lang/UNIXProcess_md.c#293
fork-and-exec処理の時のディスクリプタ全クローズ処理で、よりにもよってopendir()。ここでmalloc()が発生。あぼーん。
なんで、UNIX系OSってcloseall()システムコールがないんだろうね。困ったもんだ
追記: Linux限定の話でいうと /proc/{pid}/statusのFDSizeフィールドがmax fdを表しているので、3からFDSizeまでcloseしていけば、OKなんじゃないかという気がしてきた。誰か検証プリーズ
追記2: ついでにRubyの実装をちらりと見たけど、NOFILEまでしかクローズしていないから最大ファイルディスクリプタが動的なシステムだとリークしているっぽい。今度、akrさんあたりに真相を聞いてみよう。
追記3: glibc malloc はpthread_atfork()を使って、fork前後でmutexを取っているので、forkとexecの間でmalloc()呼んでも平気。これはtcmallocのような外部mallocを使った場合のみに問題になりそう
追記4: いくつかのページで sysconf(_SC_OPEN_MAX)を薦めているところがあったけど、これ、Linuxではうまくいかない。getrlimit()で現在のlimitを取っているだけなので、ファイルを開いた後で最大値を下げられたら、ちゃんとハンドリングできない。まあ、普通の人はそんな事しない。という指摘は正しいと思います
追記5: forkとexecの間はasync signal safeしかダメって話は以前にも書いたので、そっちも見てね
http://mkosaki.blog46.fc2.com/blog-entry-886.html
追記6: kzkさんに指摘されて気づいたけど、これが記念すべき1000エントリ目かー。妙に感慨深いな
追記7: kzkさんの関連エントリも参照のこと。
http://kzk9.net/blog/2009/09/deadlock_on_process_builder.html
コメント
コメント一覧 (5)
http://stackoverflow.com/questions/899038/getting-the-highest-allocated-file-descriptor
Ruby がてきとうなのはその通りです。
それなりには動くので、まぁ、そのうち困ったら。
(そうなったときに fdwalk が普及しているといいなぁ)
そもそも、追記1で書いた方法でmaxfd 取ってきて、closeしまくる作戦でもNOFILEよりかはマシになりそう。どうせ、通常のケースではmaxfdってせいぜい1024ぐらいな気がするし。
なんでかというと、valgrind 上で動かした時とか、使用中の fd があったりするのです。
FDSize: で maxfd を得る方法は悪くはないと思います。プラットフォーム限定であることを除けば。
ついていけなかった。execする直前だと、FD_CLOEXEC しても close()しても結果は同じになりませんか?
うーむ、何か見落としている気がする
隠蔽が甘いというべきかもしれませんが。