Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Re^4: Strawberry Perl and alarm() on Windows

by BrowserUk (Patriarch)
on May 24, 2015 at 10:55 UTC ( #1127574=note: print w/replies, xml ) Need Help??


in reply to Re^3: Strawberry Perl and alarm() on Windows
in thread Strawberry Perl and alarm() on Windows

On Windows, signals are emulated. alarm($timeout) sets up a timer that must be polled.

That's not a very good description of what actually happens.

On Windows, alarm is simulated using the SetTimer() system API, which send a message to the process' message queue when the time expires.

From perl5.18/Win32.c:

And that message is received when the run loop checks the message queue:

And, at least since the advent of SAFE_SIGNALS in 5.8.1, *nix perls, also only process signals, between opcodes, by "polling" (from the run loop) to see if any have been received during the last opcode. Ie. in exactly the same way as Windows perls do.

The reason your rather over-elaborate demo "works" on *nix and not under windows, is because under *nix, signals are also delivered (by the OS) to child processes, whereas they are obviously not on Windows. Thus, the locker child process also receives the alrm signal which interrupts the 10 second sleep, thus the lock it holds gets removed, and the main() process can therefore acquire its lock before the alarm is triggered.

This is clearly shown by the output you posted:

>perl lockdemo.pl locker: flock LOCK_EX locker: locked locker: sleep 10 main: alarm 5 main: flock LOCK_EX ### The lock is acquired +here main: timeout at lockdemo.pl line 30. ### before the timeout oc +curs. main: 5 seconds have passed locker: flock LOCK_UN locker: unlocked

Perl's "Safe Signals" (unless disabled) are also implemented on *nix perls, and are only acted upon between opcodes, just as they are on Windows perls. Your demo is deceptive (I'm not suggesting deliberately so), because the alarm is not interrupting the flock opcode in the main() process, but the sleep in the child process. The lock is only acquired early in the main process because the child process relinquished its lock early.

That doesn't happen in the Windows example, because the OS doesn't do signals, thus doesn't deliver the signal to the child process.

I agree that the emulated signals on Windows are less complete than the real ones on *nix; but then the reason Perl has "Safe signals" in the first place is because the entire concept of using asynchronous interrupts as a flow-control mechanism is terminally brain-dead.


With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked

Replies are listed 'Best First'.
Re^5: Strawberry Perl and alarm() on Windows
by afoken (Canon) on May 24, 2015 at 13:15 UTC

    This is clearly shown by the output you posted:

    >perl lockdemo.pl locker: flock LOCK_EX locker: locked locker: sleep 10 main: alarm 5 main: flock LOCK_EX ### The lock is acquired +here main: timeout at lockdemo.pl line 30. ### before the timeout oc +curs. main: 5 seconds have passed locker: flock LOCK_UN locker: unlocked
    download

    Sorry, either I don't understand what you wrote here or you don't understand what happens in my code when it runs on Linux. (Did you actually run it on a Linux system?)

    The output line "main: flock LOCK_EX" is written before flock() is called in main(). That does not aquire a lock. The next output line "main: timeout at lockdemo.pl line 30." is written by code following eval, the timeout comes from the signal handler in line 30. If flock() was successful, the next code line should have written "main: alarm 0" to the output - unless, of course, the ALRM signal was handled right between flock() and say(). For a successful flock(), locker() must have unlocked the file. That takes at least 10 seconds due to sleep(10) in locker(). After 5 seconds (plus one second due to the earlier sleep(1) in main()), the file is still locked and flock() in main() must have failed.

    (I know that the file was still locked for another 4 seconds when the timeout occurred, see below.)

    the alarm is not interrupting the flock opcode in the main() process, but the sleep in the child process. The lock is only acquired early in the main process because the child process relinquished its lock early.

    Your argument is that locker() was killed by SIGALRM set up by alarm(5) in main(). By the time that alarm(5) is called in main(), about 1 second should have passed due to sleep 1. Enough time for locker() to run into sleep(10). If locker was killed right there, the following output ("locker: flock LOCK_UN" and "locker: unlocked") would not exist. But because it exists, we can be sure that locker() was not killed. BUT ...

    The Linux manual page for sleep warns not to mix sleep and alarm, because sleep() may be implemented using SIGALRM. (Emphasis mine) So perhaps that SIGALRM messed up sleep() (i.e. sleep() in locker caught SIGALRM and slept much less than 10 seconds)?

    I changed locker() to measure time as well:

    sub locker { my $start=time(); open my $h,'>>','tempfile.tmp'; say 'locker: flock LOCK_EX'; flock($h,LOCK_EX); say 'locker: locked'; say 'locker: sleep 10'; sleep 10; say 'locker: flock LOCK_UN'; flock($h,LOCK_UN); say 'locker: unlocked'; close $h; my $stop=time(); say 'locker ran for ',$stop-$start,' seconds'; }

    Output on Linux is:

    >perl lockdemo-timed.pl locker: flock LOCK_EX locker: locked locker: sleep 10 main: alarm 5 main: flock LOCK_EX main: timeout at lockdemo-timed.pl line 30. main: 5 seconds have passed locker: flock LOCK_UN locker: unlocked locker ran for 10 seconds >

    Output on Windows is:

    H:\tmp\lockdemo>perl lockdemo-timed.pl locker: flock LOCK_EX locker: locked locker: sleep 10 main: alarm 5 main: flock LOCK_EX locker: flock LOCK_UN main: alarm 0 main: successfully locked main: 9 seconds have passed locker: unlocked locker ran for 10 seconds H:\tmp\lockdemo>

    No change compared to the original output, except for the filename and the final "locker ran for 10 seconds" line.

    So no, locker() is not affected by SIGALRM at all. (This is on perl 5.18.1, Slackware 14.1 64 bit, Linux 3.10.17) If locker() was disturbed by alarm(5) from main(), that would happen after about 6 seconds, resulting in a total runtime of about 6 seconds, not 10 seconds. If locker() was killed by alarm(5) from main(), the total run time would not be written to the output.

    To avoid any issues with SIGALRM and sleep, let's explicitly ignore SIGALRM and change sleep($timeout) to select(undef,undef,undef,$timeout):

    sub locker { $SIG{'ALRM'}='IGNORE'; my $start=time(); open my $h,'>>','tempfile.tmp'; say 'locker: flock LOCK_EX'; flock($h,LOCK_EX); say 'locker: locked'; say 'locker: sleep 10 using select'; select(undef,undef,undef,10); say 'locker: flock LOCK_UN'; flock($h,LOCK_UN); say 'locker: unlocked'; close $h; my $stop=time(); say 'locker ran for ',$stop-$start,' seconds'; }

    Output on Linux:

    >perl lockdemo-select.pl locker: flock LOCK_EX locker: locked locker: sleep 10 using select main: alarm 5 main: flock LOCK_EX main: timeout at lockdemo-select.pl line 30. main: 5 seconds have passed locker: flock LOCK_UN locker: unlocked locker ran for 10 seconds >

    Output on Windows:

    H:\tmp\lockdemo>perl lockdemo-select.pl locker: flock LOCK_EX locker: locked locker: sleep 10 using select main: alarm 5 main: flock LOCK_EX locker: flock LOCK_UN main: alarm 0 main: successfully locked main: 9 seconds have passed locker: unlocked locker ran for 10 seconds H:\tmp\lockdemo>

    Again, no changes compared to the original output, except for the filename and the final locker ran for 10 seconds line.

    The reason your rather over-elaborate demo "works" on *nix and not under windows, is because under *nix, signals are also delivered (by the OS) to child processes

    I doubt that alarm(timeout) sends a signal to child processes. The Linux man page for alarm states: " alarm() arranges for a SIGALRM signal to be delivered to the calling process in seconds seconds. ". No word about sending signals to child processes. POSIX has a similar statement: "The alarm() function shall cause the system to generate a SIGALRM signal for the process after the number of realtime seconds specified by seconds have elapsed." And it explicitly specifies what happends to child processes: "The fork() function clears pending alarms in the child process. A new process image created by one of the exec functions inherits the time left to an alarm signal in the old process' image."

    Signals are sent to only one process by default when using kill, though it is possible to send signals to process groups by using a negative process ID as argument to kill:

    The kill() system call can be used to send any signal to any process group or process. If pid is positive, then signal sig is sent to the process with the ID specified by pid. If pid equals 0, then sig is sent to every process in the process group of the calling process. If pid equals -1, then sig is sent to every process for which the call‐ ing process has permission to send signals, except for process 1 (init), but see below. If pid is less than -1, then sig is sent to every process in the process group whose ID is -pid.

    (From the kill(2) Linux man page, POSIX is very similar.)

    Let's see if a signal is delivered to locker(), as you suggest:

    sub locker { $SIG{'ALRM'}=sub { warn "*** ALARM ***" }; my $start=time(); open my $h,'>>','tempfile.tmp'; say 'locker: flock LOCK_EX'; flock($h,LOCK_EX); say 'locker: locked'; say 'locker: sleep 10 using select'; select(undef,undef,undef,10); say 'locker: flock LOCK_UN'; flock($h,LOCK_UN); say 'locker: unlocked'; close $h; my $stop=time(); say 'locker ran for ',$stop-$start,' seconds'; }

    Output (Linux only):

    >perl lockdemo-signal.pl locker: flock LOCK_EX locker: locked locker: sleep 10 using select main: alarm 5 main: flock LOCK_EX main: timeout at lockdemo-signal.pl line 30. main: 5 seconds have passed locker: flock LOCK_UN locker: unlocked locker ran for 10 seconds >

    No traces of a SIGALRM here.

    So, my code works on Linux as I explained. locker() is not at all affected by alarm(5) in main.

    For better portability, maybe I should have set $SIG{'ARLM'}='IGNORE' in locker() and used select(undef,undef,undef,10) instead of sleep(10) in locker().

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
      or you don't understand what happens in my code when it runs on Linux. (Did you actually run it on a Linux system?)

      No. I don't use Linux. And you're right. I did misinterpret what I saw in your post.

      My main purpose was to point out:

      1. The description of the Windows implementation of alarm was inadequate and somewhat misleading.
      2. That the "polling" required to detect that the alarm signal (and other signals) had arrived, also occurs on Linux under the Safe Signals scheme.

        See the PERL_ASYNC_CHECK() in run.c and Perl_despatch_signals(pTHX) in mg.c

        See also perldoc/perlipc:

        Long-running opcodes

        As the Perl interpreter only looks at the signal flags when it is about to execute a new opcode, a signal that arrives during a long-running opcode (e.g. a regular expression operation on a very large string) will not be seen until the current opcode completes.

      The rest was an attempt to understand (from your posted output) how linux was apparently able to interrupt flock when it appears to be implemented as a single opcode; and thus (according to my understanding of safe signals) should not be interruptible.

      I don't understand why that works for you, unless you have PERL_SIGNALS=unsafe?

      The (wrong) explanation I came up with seemed to fit; but then it is well passed the end of my (logical) day here and I'm somewhat punchy.


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
      In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked
        I don't understand why that works for you, unless you have PERL_SIGNALS=unsafe?

        PERL_SIGNALS is not set in my environment.

        But PERL_SIGNALS does not affect the operating system in any way. Linux deliveres SIGALRM as it would for any other program. That means that the flock() system call (deep inside the perl flock() function) will be interrupted and will return EINTR immediately after the signal handler (deep inside the perl executable, not $SIG{'ALRM'}) has returned. The signal handler will - according to Deferred Signals (Safe Signals) - just set a flag. So a few CPU cycles after SIGALRM, the flock() system call will return. Standard Unix behaviour. Perl obviously does not attempt to restart the interrupted flock() system call, but makes the perl-level flock() function return false after setting $! to EINTR. Just before the perl-level flock() function returns, perl consideres the situation safe for signals, checks the flag set in the real signal handler, finds it set, and calls the perl-level signal handler stored in $SIG{ALRM}.

        With unsafe signals, the flock() system call would be interrupted as above, but instead of setting a flag, the signal handler (deep inside the perl executable) would directly invoke the perl-level signal handler stored in $SIG{ALRM}. Everything else would behave the same: If &$SIG{ALRM} returns, control returns to the place where the fcntl() system call was invoked (i.e. the implementation of the fcntl perl function), with fcntl() returning EINTR. That would make the perl function return false after setting $! to EINTR.

        The only two differences here are:

        • With unsafe signals, perl internals could be damaged by the code in $SIG{ALRM}.
        • Safe signals guarantee that the code that handles the return value of the system call flock() inside the perl function flock() is executed, so $! will be set properly. Perl with unsafe signals and with a $SIG{ALRM} that dies or exits perhaps will not reach that code.

        Another demo:

        This code only warns when a signal was caught, and all of the Win32 workarounds and timing is stripped from the orignal demo. say also writes time and PID.

        #!/usr/bin/perl use strict; use warnings; use autodie qw( open close ); use Fcntl qw( LOCK_EX LOCK_UN ); sub say { print scalar localtime(),' pid=',$$,': ',@_,"\n"; } my $mainpid=$$; my $pid=fork() // die "Can't fork: $!"; # in both parent and child process, install signal handler $SIG{'ALRM'}=sub { warn 'SIGALRM in ',$$==$mainpid ? 'main' : 'helper' + }; if ($pid) { # parent process say "main starts"; say "main waiting for helper to lock"; sleep 1; open my $f,'>','tempfile.tmp'; alarm(5); say "main flock"; flock($f,LOCK_EX) or say "main can't lock: $! (error code ",0+ +$!,')'; say "main flock done"; alarm(0); close $f; say "main ends"; wait; } else { # child process say "helper starts"; open my $f,'>','tempfile.tmp'; flock($f,LOCK_EX) or die "Helper can't lock: $!"; select(undef,undef,undef,10); flock($f,LOCK_UN) or die "Helper can't unlock: $!"; close $f; say "helper ends"; exit(0); }

        Output:

        >env - perl interrupted.pl Sun May 24 20:24:11 2015 pid=31389: main starts Sun May 24 20:24:11 2015 pid=31389: main waiting for helper to lock Sun May 24 20:24:11 2015 pid=31390: helper starts Sun May 24 20:24:12 2015 pid=31389: main flock SIGALRM in main at interrupted.pl line 16. Sun May 24 20:24:17 2015 pid=31389: main can't lock: Interrupted syste +m call (error code 4) Sun May 24 20:24:17 2015 pid=31389: main flock done Sun May 24 20:24:17 2015 pid=31389: main ends Sun May 24 20:24:21 2015 pid=31390: helper ends >env - PERL_SIGNALS=unsafe perl interrupted.pl Sun May 24 20:24:39 2015 pid=31396: main starts Sun May 24 20:24:39 2015 pid=31396: main waiting for helper to lock Sun May 24 20:24:39 2015 pid=31397: helper starts Sun May 24 20:24:40 2015 pid=31396: main flock SIGALRM in main at interrupted.pl line 16. Sun May 24 20:24:49 2015 pid=31397: helper ends Sun May 24 20:24:49 2015 pid=31396: main flock done Sun May 24 20:24:49 2015 pid=31396: main ends alex@enterprise pts/0 20:24:49 /home/alex/tmp/lockdemo>

        The interesting effect of unsafe signals is that flock() in main returns true, there is no warning message. But as you can see from the timing, flock() in main returns only after the helper has released its lock. So in that case, perl must have restarted the interrupted flock() system call. strace confirms that:

        (Note that strace traces only the main process, not the fork()ed child.)

        >env - PERL_SIGNALS=unsafe strace -o trace.txt /usr/bin/perl interrupt +ed.pl Sun May 24 20:39:02 2015 pid=31774: helper starts Sun May 24 20:39:02 2015 pid=31773: main starts Sun May 24 20:39:02 2015 pid=31773: main waiting for helper to lock Sun May 24 20:39:03 2015 pid=31773: main flock SIGALRM in main at interrupted.pl line 16. Sun May 24 20:39:12 2015 pid=31774: helper ends Sun May 24 20:39:12 2015 pid=31773: main flock done Sun May 24 20:39:12 2015 pid=31773: main ends >grep -C5 flock trace.txt fstat(3, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0 fcntl(3, F_SETFD, FD_CLOEXEC) = 0 alarm(5) = 0 stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2335, ...}) = 0 write(1, "Sun May 24 20:39:03 2015 pid=317"..., 47) = 47 flock(3, LOCK_EX) = ? ERESTARTSYS (To be restart +ed if SA_RESTART is set) --- SIGALRM {si_signo=SIGALRM, si_code=SI_KERNEL} --- rt_sigaction(SIGALRM, NULL, {0x7fdcf683dde0, [], SA_RESTORER|SA_RESTAR +T, 0x7fdcf5a2f670}, 8) = 0 write(2, "SIGALRM in main at interrupted.p"..., 43) = 43 rt_sigreturn() = 73 flock(3, LOCK_EX) = 0 stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2335, ...}) = 0 write(1, "Sun May 24 20:39:12 2015 pid=317"..., 52) = 52 alarm(0) = 0 close(3) = 0 stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2335, ...}) = 0 >env - strace -o trace.txt /usr/bin/perl interrupted.pl Sun May 24 20:43:14 2015 pid=31859: helper starts Sun May 24 20:43:14 2015 pid=31858: main starts Sun May 24 20:43:14 2015 pid=31858: main waiting for helper to lock Sun May 24 20:43:15 2015 pid=31858: main flock SIGALRM in main at interrupted.pl line 16. Sun May 24 20:43:20 2015 pid=31858: main can't lock: Interrupted syste +m call (error code 4) Sun May 24 20:43:20 2015 pid=31858: main flock done Sun May 24 20:43:20 2015 pid=31858: main ends Sun May 24 20:43:24 2015 pid=31859: helper ends >grep -C5 flock trace.txt fstat(3, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0 fcntl(3, F_SETFD, FD_CLOEXEC) = 0 alarm(5) = 0 stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2335, ...}) = 0 write(1, "Sun May 24 20:43:15 2015 pid=318"..., 47) = 47 flock(3, LOCK_EX) = ? ERESTARTSYS (To be restart +ed if SA_RESTART is set) --- SIGALRM {si_signo=SIGALRM, si_code=SI_KERNEL} --- rt_sigreturn() = -1 EINTR (Interrupted system + call) rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, NULL, {0x7f43b0eaede0, [], SA_RESTORER, 0x7f43b0 +0a0670}, 8) = 0 write(2, "SIGALRM in main at interrupted.p"..., 43) = 43 >

        Unsafe signals seem to change how rt_sigaction is called: SA_RESTART is set only for unsafe signals. So fcntl() is automatically restarted (not by perl, as I wrote above) only with unsafe signals. Another round of strace also confirmes that:

        >env - PERL_SIGNALS=unsafe strace -o trace.txt /usr/bin/perl interrupt +ed.pl Sun May 24 20:51:14 2015 pid=32083: helper starts Sun May 24 20:51:14 2015 pid=32082: main starts Sun May 24 20:51:14 2015 pid=32082: main waiting for helper to lock Sun May 24 20:51:15 2015 pid=32082: main flock SIGALRM in main at interrupted.pl line 16. Sun May 24 20:51:24 2015 pid=32083: helper ends Sun May 24 20:51:24 2015 pid=32082: main flock done Sun May 24 20:51:24 2015 pid=32082: main ends >grep -C5 SIGALRM trace.txt close(3) = 0 rt_sigprocmask(SIG_SETMASK, ~[RTMIN RT_1], [], 8) = 0 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIG +CHLD, child_tidptr=0x7fdbc5fc2a10) = 32083 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x7fdbc5ad9de0, [], SA_RESTORER|SA_RESTART, 0x7 +fdbc4ccb670}, {SIG_DFL, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 open("/etc/localtime", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=2335, ...}) = 0 fstat(3, {st_mode=S_IFREG|0644, st_size=2335, ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, +0) = 0x7fdbc5fe6000 -- fcntl(3, F_SETFD, FD_CLOEXEC) = 0 alarm(5) = 0 stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2335, ...}) = 0 write(1, "Sun May 24 20:51:15 2015 pid=320"..., 47) = 47 flock(3, LOCK_EX) = ? ERESTARTSYS (To be restart +ed if SA_RESTART is set) --- SIGALRM {si_signo=SIGALRM, si_code=SI_KERNEL} --- rt_sigaction(SIGALRM, NULL, {0x7fdbc5ad9de0, [], SA_RESTORER|SA_RESTAR +T, 0x7fdbc4ccb670}, 8) = 0 write(2, "SIGALRM in main at interrupted.p"..., 43) = 43 rt_sigreturn() = 73 flock(3, LOCK_EX) = 0 stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2335, ...}) = 0 write(1, "Sun May 24 20:51:24 2015 pid=320"..., 52) = 52 alarm(0) = 0 -- rt_sigaction(SIGKILL, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigaction(SIGUSR1, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigaction(SIGSEGV, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigaction(SIGUSR2, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigaction(SIGPIPE, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigaction(SIGALRM, NULL, {0x7fdbc5ad9de0, [], SA_RESTORER|SA_RESTAR +T, 0x7fdbc4ccb670}, 8) = 0 rt_sigaction(SIGALRM, {SIG_DFL, [], SA_RESTORER|SA_RESTART, 0x7fdbc4cc +b670}, {0x7fdbc5ad9de0, [], SA_RESTORER|SA_RESTART, 0x7fdbc4ccb670}, +8) = 0 rt_sigaction(SIGTERM, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigaction(SIGSTKFLT, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigaction(SIGCONT, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigaction(SIGSTOP, NULL, {SIG_DFL, [], 0}, 8) = 0 >env - strace -o trace.txt /usr/bin/perl interrupted.pl Sun May 24 20:51:35 2015 pid=32103: helper starts Sun May 24 20:51:35 2015 pid=32102: main starts Sun May 24 20:51:35 2015 pid=32102: main waiting for helper to lock Sun May 24 20:51:36 2015 pid=32102: main flock SIGALRM in main at interrupted.pl line 16. Sun May 24 20:51:41 2015 pid=32102: main can't lock: Interrupted syste +m call (error code 4) Sun May 24 20:51:41 2015 pid=32102: main flock done Sun May 24 20:51:41 2015 pid=32102: main ends Sun May 24 20:51:45 2015 pid=32103: helper ends >grep -C5 SIGALRM trace.txt close(3) = 0 rt_sigprocmask(SIG_SETMASK, ~[RTMIN RT_1], [], 8) = 0 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIG +CHLD, child_tidptr=0x7f45f31f1a10) = 32103 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x7f45f2d08de0, [], SA_RESTORER, 0x7f45f1efa670 +}, {SIG_DFL, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 open("/etc/localtime", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=2335, ...}) = 0 fstat(3, {st_mode=S_IFREG|0644, st_size=2335, ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, +0) = 0x7f45f3215000 -- fcntl(3, F_SETFD, FD_CLOEXEC) = 0 alarm(5) = 0 stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2335, ...}) = 0 write(1, "Sun May 24 20:51:36 2015 pid=321"..., 47) = 47 flock(3, LOCK_EX) = ? ERESTARTSYS (To be restart +ed if SA_RESTART is set) --- SIGALRM {si_signo=SIGALRM, si_code=SI_KERNEL} --- rt_sigreturn() = -1 EINTR (Interrupted system + call) rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, NULL, {0x7f45f2d08de0, [], SA_RESTORER, 0x7f45f1 +efa670}, 8) = 0 write(2, "SIGALRM in main at interrupted.p"..., 43) = 43 rt_sigprocmask(SIG_UNBLOCK, [ALRM], NULL, 8) = 0 stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2335, ...}) = 0 write(1, "Sun May 24 20:51:41 2015 pid=321"..., 92) = 92 stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2335, ...}) = 0 write(1, "Sun May 24 20:51:41 2015 pid=321"..., 52) = 52 -- rt_sigaction(SIGKILL, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigaction(SIGUSR1, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigaction(SIGSEGV, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigaction(SIGUSR2, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigaction(SIGPIPE, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigaction(SIGALRM, NULL, {0x7f45f2d08de0, [], SA_RESTORER, 0x7f45f1 +efa670}, 8) = 0 rt_sigaction(SIGALRM, {SIG_DFL, [], SA_RESTORER, 0x7f45f1efa670}, {0x7 +f45f2d08de0, [], SA_RESTORER, 0x7f45f1efa670}, 8) = 0 rt_sigaction(SIGTERM, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigaction(SIGSTKFLT, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigaction(SIGCONT, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigaction(SIGSTOP, NULL, {SIG_DFL, [], 0}, 8) = 0 >

        SA_RESTART is only set for unsafe signals. So with unsafe signals, interrupted system calls are restarted if possible; with safe signals, interrupted system calls are not restarted.

        That is at least strange, perhaps even a bug. I think that perl should either always or never restart interrupted system calls, not depending on safe or unsafe signal handlers.

        Deferred Signals (Safe Signals) says unter "Restartable system calls":

        On systems that supported it, older versions of Perl used the SA_RESTART flag when installing %SIG handlers. This meant that restartable system calls would continue rather than returning when a signal arrived. In order to deliver deferred signals promptly, Perl 5.8.0 and later do not use SA_RESTART. Consequently, restartable system calls can fail (with $! set to EINTR) in places where they previously would have succeeded.

        The default :perlio layer retries read, write and close as described above; interrupted wait and waitpid calls will always be retried.

        So, this starts to look like a bug in unsafe signals. SA_RESTART should not be set in Perl 5.8.0 and later, no matter what type of signal handlers is used.

        <UPDATE>

        Relevant code is in util.c, functions Sighandler_t Perl_rsignal(pTHX_ int signo, Sighandler_t handler) and int Perl_rsignal_save(pTHX_ int signo, Sighandler_t handler, Sigsave_t *save). Both have the following four lines:

        #ifdef SA_RESTART if (PL_signals & PERL_SIGNALS_UNSAFE_FLAG) act.sa_flags |= SA_RESTART; /* SVR4, 4.3+BSD */ #endif

        </UPDATE>

        See also: Linux signal handling

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1127574]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (2)
As of 2022-05-24 03:39 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Do you prefer to work remotely?



    Results (82 votes). Check out past polls.

    Notices?