Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??

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". ;-)

In reply to Re^5: Strawberry Perl and alarm() on Windows by afoken
in thread Strawberry Perl and alarm() on Windows by bloonix

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (4)
As of 2024-04-20 00:02 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found