Matz 日記にちょっと書いてありますが、Process.daemon というメソッドを提 案します。 4.4BSD (または glibc) をあるていど知っている人は名前から想像できると思 うのですが、daemon(3) を呼んで(またはそれと等価なことをして)、プロセス をデーモン化するメソッドです。 これは以前にも何回か議論にのぼって Ruby で実現可能であるとして立ち消え になっているのですが ([ruby-talk:87459], [ruby-dev:22938])、あえてまた 提案するのは、Ruby で実装するとデーモン化を行なった以外のスレッドがす べて死ぬのに対し、C で実装すればスレッドを生きたままデーモン化できるか らです。これが可能なのは、デーモン化においては fork 直後に親が死ぬため、 親に残ったスレッドは存在しないものとできて、子供 (というか孫) のプロセ スにスレッドを残しても競合が起こらないからです。 fork において子プロセスのスレッドが死ぬ挙動は 1.8 における fork の仕様 が原因ですが、fork でスレッドが死んで困ったという例を調べると、理由が わかるもののはほとんどが (私の知る限りひとつの例外を除いて) デーモン化 するために fork したときに死んで困ったという話です。([ruby-dev:11680] の rwiki, [ruby-bugs-ja:576] の QuickML, http://eto.com/d/0407.html) # 私が知っているただひとつの例外はなひさんのデバッガです。 というわけで、デーモン化するメソッドを C で書いて新設すれば、fork の仕 様の変化で困る状況のかなりの部分を救済できるのではないかと思います。 また、fork/setsid とか難しいこと (古い Unix も考えるなら、BSD と SysV での制御端末の切り離しかたとかなどの微妙な話) を知らなくてもデーモン化で きるようになるという利点もあります。つまり、4.4BSD/glibc で C で書くの と同じくらいデーモン化が簡単になるといえるわけで、そもそも現在の、C よ りも Ruby で書くほうがデーモン化が難しいというのは変ではないでしょうか? 具体的な仕様は daemon(3) に似せておけばよかろうというわけで、試しに次 のような実装を行なってみました。実際には daemon(3) が無い場合には fork/setsid などで行なう実装も加えるべきですが、それはやっていません。 どんなもんでしょう? Index: configure.in =================================================================== RCS file: /src/ruby/configure.in,v retrieving revision 1.241 diff -u -p -r1.241 configure.in --- configure.in 8 Jul 2004 10:27:23 -0000 1.241 +++ configure.in 7 Aug 2004 15:09:51 -0000 @@ -418,7 +418,7 @@ AC_CHECK_FUNCS(fmod killpg wait4 waitpid getpgrp setpgrp getpgid setpgid initgroups getgroups setgroups\ getpriority getrlimit dlopen sigprocmask sigaction _setjmp\ setsid telldir seekdir fchmod mktime timegm cosh sinh tanh\ - setuid setgid) + setuid setgid daemon) AC_ARG_ENABLE(setreuid, [ --enable-setreuid use setreuid()/setregid() according to need even if obsolete.], [use_setreuid=$enableval]) Index: process.c =================================================================== RCS file: /src/ruby/process.c,v retrieving revision 1.108 diff -u -p -r1.108 process.c --- process.c 17 Jul 2004 06:28:10 -0000 1.108 +++ process.c 7 Aug 2004 15:10:09 -0000 @@ -1834,6 +1834,35 @@ proc_setsid() #endif } +/* + * call-seq: + * Process.daemon([nochdir], [noclose]) => nil + * + * Make the process as a daemon. + * + * Process.daemon doesn't kill other threads unlike Process.fork. + * + */ + +static VALUE +proc_daemon(argc, argv) + int argc; + VALUE *argv; +{ +#if defined(HAVE_DAEMON) + VALUE nochdir, noclose; + + rb_scan_args(argc, argv, "02", &nochdir, &noclose); + + if (daemon(RTEST(nochdir), RTEST(noclose)) < 0) { + rb_sys_fail("daemon"); + } +#else + rb_notimplement(); +#endif + return Qnil; +} + /* * call-seq: @@ -3519,6 +3548,7 @@ Init_process() rb_define_module_function(rb_mProcess, "setpgid", proc_setpgid, 2); rb_define_module_function(rb_mProcess, "setsid", proc_setsid, 0); + rb_define_module_function(rb_mProcess, "daemon", proc_daemon, -1); rb_define_module_function(rb_mProcess, "getpriority", proc_getpriority, 2); rb_define_module_function(rb_mProcess, "setpriority", proc_setpriority, 3); なお、Matz 日記には /dev/null (の存在?) への懸念が書いてありますが、 daemon を呼び出す限りはその問題に対する責任は libc にあるといえるので はないかと思います。というか、glibc の daemon の実装でも、/dev/null の 存在は仮定しているような記述がマニュアルにありますし、それは悩んでもう まい解は存在しない類の懸念なのではないかと思います。 -- [田中 哲][たなか あきら][Tanaka Akira]