Skip to content

Commit

Permalink
perlipc.pod: fix the "exec from signal handler" example
Browse files Browse the repository at this point in the history
This is a partial revert of de7ba51 ("Doc patch to
perlipc", 2011-09-11).

I tested both the pre-de7ba5179657 and current version of
the example program (section "Handling the SIGHUP Signal in
Daemons") on Arch Linux (perl v5.38.2 built for x86_64-linux-thread-multi)
and OpenBSD -current (perl v5.36.3 built for amd64-openbsd).
On both systems, the handler is called only once with the
current (broken) version of the example program.
With the pre-de7ba5179657 version the handler is called on
every delivery of the signal, as expected.

POSIX shell test script (perlipc-sighandler.sh):
================================================
-->8--
#!/bin/sh
check() {
  printf '\nTesting %s\n' "$*"
  "$@" &
  sleep 1
  kill -HUP $!
  sleep 1
  kill -HUP $!
  sleep 1
  kill $!
}

bad=./perlipc-sighandler-bad.perl
good=./perlipc-sighandler-good.perl

# from current perlipc.pod (perl5 commit e78caca v5.39.9-35-ge78caca8144e)
cat <<\EOF >"$bad"
#!/usr/bin/perl

use v5.36;

use POSIX ();
use FindBin ();
use File::Basename ();
use File::Spec::Functions qw(catfile);

$| = 1;

# make the daemon cross-platform, so exec always calls the script
# itself with the right path, no matter how the script was invoked.
my $script = File::Basename::basename($0);
my $SELF   = catfile( $FindBin::Bin, $script );

# POSIX unmasks the sigprocmask properly
$SIG{HUP} = sub {
  print "got SIGHUP\n";
  exec( $SELF, @argv ) || die "$0: couldn't restart: $!";
};

code();

sub code {
  print "PID: $$\n";
  print "ARGV: @argv\n";
  my $count = 0;
  while (1) {
    sleep 2;
    print ++$count, "\n";
  }
}
EOF

# from perlipc.pod before perl5 commit de7ba51 v5.15.2-343-gde7ba5179657
cat <<\EOF >"$good"
#!/usr/bin/perl

use v5.36;

use POSIX ();
use FindBin ();
use File::Basename ();
use File::Spec::Functions qw(catfile);

$| = 1;

# make the daemon cross-platform, so exec always calls the script
# itself with the right path, no matter how the script was invoked.
my $script = File::Basename::basename($0);
my $SELF   = catfile( $FindBin::Bin, $script );

# POSIX unmasks the sigprocmask properly
my $sigset = POSIX::SigSet->new();
my $action = POSIX::SigAction->new("sigHUP_handler",
                                   $sigset,
                                   &POSIX::SA_NODEFER);
POSIX::sigaction(&POSIX::SIGHUP, $action);

sub sigHUP_handler {
  print "got SIGHUP\n";
  exec( $SELF, @argv ) || die "$0: couldn't restart: $!";
}

code();

sub code {
  print "PID: $$\n";
  print "ARGV: @argv\n";
  my $count = 0;
  while (1) {
    sleep 2;
    print ++$count, "\n";
  }
}
EOF

chmod +x "$bad" "$good"

check "$bad"
check "$good"
-->8--

Example observed output:
========================
; ./perlipc-sighandler.sh

Testing ./perlipc-sighandler-bad.perl
PID: 19120
ARGV:
got SIGHUP
PID: 19120
ARGV:

Testing ./perlipc-sighandler-good.perl
PID: 19980
ARGV:
got SIGHUP
PID: 19980
ARGV:
got SIGHUP
PID: 19980
ARGV:

Cc: Leon Timmermans <[email protected]>
Fixes: de7ba51 ("Doc patch to perlipc")
  • Loading branch information
stepnem committed Apr 11, 2024
1 parent e78caca commit d8adbe3
Showing 1 changed file with 14 additions and 2 deletions.
16 changes: 14 additions & 2 deletions pod/perlipc.pod
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,12 @@ the process. Many daemons provide this mechanism using a C<SIGHUP>
signal handler. When you want to tell the daemon to reread the file,
simply send it the C<SIGHUP> signal.

Not all platforms automatically reinstall their (native) signal
handlers after a signal delivery. This means that the handler works
the first time the signal is sent, only. The solution to this problem
is to use C<POSIX> signal handlers if available; their behavior
is well-defined.

The following example implements a simple daemon, which restarts
itself every time the C<SIGHUP> signal is received. The actual code is
located in the subroutine C<code()>, which just prints some debugging
Expand All @@ -205,10 +211,16 @@ info to show that it works; it should be replaced with the real code.
my $SELF = catfile($FindBin::Bin, $script);

# POSIX unmasks the sigprocmask properly
$SIG{HUP} = sub {
my $sigset = POSIX::SigSet->new();
my $action = POSIX::SigAction->new("sigHUP_handler",
$sigset,
&POSIX::SA_NODEFER);
POSIX::sigaction(&POSIX::SIGHUP, $action);

sub sigHUP_handler {
print "got SIGHUP\n";
exec($SELF, @ARGV) || die "$0: couldn't restart: $!";
};
}

code();

Expand Down

0 comments on commit d8adbe3

Please sign in to comment.