読者です 読者をやめる 読者になる 読者になる

SIGHUPとかで再起動するPerlスクリプトで、再起動後にシグナルが受信できない

Perl

現象

Perlでサーバとして動作するプログラムを作った時のこと。
SIGHUPとかのシグナルによって再起動させたいと思って安直に以下のように実装して、

$SIG{HUP} = sub { exec $0, @ARGV or die "Failed restart : $!"; };

SIGHUPを送ると再起動しました。
はい、OK〜っと思ったのですが、再度SIGHUPを送っても次からは再起動しないっす…。

POSIX::SigActionを使ってみる

Perlでシグナル処理について調べると、以下が見つかったので、

参考にして以下のようにしてみたのですが、だめでした。

use POSIX ();
my $sigset = POSIX::SigSet->new(&POSIX::SIGHUP);
my $sigact = POSIX::SigAction->new(sub { exec $0, @ARGV or die "Failed restart : $!"; }, $sigset, &POSIX::SA_NODEFER);
POSIX::sigaction(&POSIX::SIGHUP, $sigact);

local化してみる

local $SIG{HUP} = sub { exec $0, @ARGV or die "Failed restart : $!"; };

とか、以下を参考に、

use Sys::SigAction qw( set_sig_handler );
my $h = set_sig_handler('HUP', sub { exec $0, @ARGV or die "Failed restart : $!"; }, { flags => SA_NODEFER });

とかしてみましたが関係なし。

ようやくそれっぽい情報が

execを使用してプログラムを再起動すると、起動されたプロセスはブロックされたシグナルを継承するとのこと。
これかッ!と上記を参考にして、

use POSIX ();
my $sigset = POSIX::SigSet->new(&POSIX::SIGHUP);
my $sigact = POSIX::SigAction->new(sub {
    for my $nal ( qw{ ALRM CHLD HUP INT PIPE TERM } ) {
        $SIG{$nal} = sub {};
    }
    my $s = POSIX::SigSet->new;
    my $t = POSIX::SigSet->new;
    POSIX::sigprocmask(&POSIX::SIG_BLOCK, $s, $t);
    exec $0, @ARGV or die "Failed restart : $!";
}, $sigset, &POSIX::SA_NODEFER);
POSIX::sigaction(&POSIX::SIGHUP, $sigact);

としてみたのですが、やっぱりダメっす…。期待した分、テンション↓も大きい…。

シグナルのブロック解除で何か上手くいったっぽい

で、シグナルのブロックとかsigprocmaskとかSIG_BLOCKとか勉強した結果、
ブロック解除したいんだから、POSIX::SIG_UNBLOCKを使わないといけないんじゃないかと思い、

use POSIX ();
my $sigset = POSIX::SigSet->new(&POSIX::SIGHUP);
my $sigact = POSIX::SigAction->new(sub { exec $0, @ARGV or die "Failed restart : $!"; }, $sigset, &POSIX::SA_NODEFER);
POSIX::sigprocmask(&POSIX::SIG_UNBLOCK, $sigset);
POSIX::sigaction(&POSIX::SIGHUP, $sigact);

としたら、上手くいきました。

あとがき

でも、本当に良いのか自信無しです。ツッコミがあれば是非。
そもそもシグナルとかよくわかってないんだよなぁと。

似たような処理のサンプルを載せてるサイトは、たくさん見つかりましたが、
SIG_UNBLOCKを扱っている所は見つからなかったです。
これって初歩的な知識なんだろか。
それとも、Proc::Daemonとかのライブラリを使ってれば、意識する必要無いのかな。