以下 2点。ちょいと困ったので調べた。
1. Daemon::Generic で書いた daemon を cron から起動するとゾンビが残る件
2. logger 経由で表示されるログの pid が、自分のじゃない件
まず、プロセスを daemon 化する処理について。
Unix Programming Frequently Asked Questions 日本語訳 - 1 プロセス制御 / 1.7 プログラムをデーモンとして動かすにはどうすればいいですか?と Daemon::Generic のソースを見比べたら流れが違う。
- fork()
- setsid()
- fork()
- STDIN, STDOUT, STDERR を close して open
という流れだと理解したんだけど、Daemon::Generic は gd_daemonize() の中で
- STDOUT, STDERR を close して open
- ただし STDERR は明示的に close してない
- fork()
- fork()
- setsid()
という風に書いてある。
1. cron から起動するとゾンビが残る件
STDERR を logger 用に再open する前に、明示的に close したら直った。
2. pid が自分のじゃない件
fork 前に logger をパイプ経由で起動して、そこに渡す -t オプションの文字列を pid から作ってるから。
実際に動き続けるプロセスの pid ではなく、その親の親の pid が logger に渡ってる。
てことで、以下のように patch したら解決。
--- /usr/lib/perl5/site_perl/5.8.8/Daemon/Generic.pm 2007-08-16 02:29:18.000000000 +0900 +++ tmp/Generic.pm 2008-05-09 22:19:24.000000000 +0900 @@ -233,29 +233,30 @@ sub gd_redirect_output { my $self = shift; return if $self->{gd_foreground}; my $logname = $self->gd_logname; my $p = $self->{gd_logpriority} ? "-p $self->{gd_logpriority}" : ""; + close(STDERR); open(STDERR, "|logger $p -t '$logname'") or (print "could not open stderr: $!" && exit(1)); close(STDOUT); open(STDOUT, ">&STDERR") or die "redirect STDOUT -> STDERR: $!"; } sub gd_daemonize { my $self = shift; print "Starting $self->{gd_progname} server\n"; - $self->gd_redirect_output(); my $pid; POSIX::_exit(0) if $pid = fork; die "Could not fork: $!" unless defined $pid; + POSIX::setsid(); POSIX::_exit(0) if $pid = fork; die "Could not fork: $!" unless defined $pid; - POSIX::setsid(); + $self->gd_redirect_output(); select(STDERR); $| = 1; print "Sucessfully daemonized\n"; }