Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Awake from sleep()

by cmilfo (Hermit)
on Nov 04, 2002 at 21:49 UTC ( [id://210307]=perlquestion: print w/replies, xml ) Need Help??

cmilfo has asked for the wisdom of the Perl Monks concerning the following question:

Oh wisest Monks,

Is there a way to awake from the eternal sleep()? Two processes exist, a child doing the work and a parent checking that the other is still running. The parent ping()s the SOAP server the child is running, then sleep()s for N seconds. If the child dies just after the parent ping()s, then the process may be down for as much as N-1 seconds. The catch here is that the child is stopping on purpose, to replace a configuration file. This is an advantage, but I do not know exactly how to take advantage of it.

Be it that the child stops itself, the parent can receive a signal from the child to stop what it's doing, sleep()ing. However, I've read over and over that one should limit what's done in a signal handler.

So, the child signals the parent, then stops. The parent catchs the signal, and restarts the child. Before the parent can leave the signal handler, it will need to test the child (via SOAP) to ensure the child starts with the new configuration file, else replace the file and restart again.

1) Is this too much to do inside the singal handler?
2) If 1) is 'yes', is there a way to leave the signal handler, break from the sleep(), and then attempt to restart the child, test, etc?
3) Is there a better way than a signal to telling the sleep()ing parent that the child is stopping?

On a side note: Another solution is to shorten the sleep time of the parent. The problem here is that the parent process then has a larger system footprint (i.e. processor usage).

Thank you once again, Casey

Replies are listed 'Best First'.
Re: Awake from sleep()
by Zaxo (Archbishop) on Nov 04, 2002 at 22:41 UTC

    If the child dies, the parent should receive SIGCHLD. The CHLD handler can set a global flag to restart the child before sleeping again.

    Another handy way to check that a child is running is to call kill 0, $childpid or spawn_another_child();

    Don't wait inside a signal handler until a child starts. That gets you nested handlers, playing dangerous games with the kernel. Instead, try something in the parent's mainline code like:

    sleep 1 until kill 0, $childpid;

    After Compline,
    Zaxo

      I've thought about the kill 0, $childpid solution. One of my constraints is that the code must run on several platforms (*nix not a problem, but Win32 doesn't like kill 0 much).

      I do have a abstracted method for checking the child is alive. Do you think that the  sleep 1 until $child_is_dead will be to expensive on the machine?

      Thanks!

        ...in your original question you said this:

        2) If 1) is 'yes', is there a way to leave the signal handler, break from the sleep(), and then attempt to restart the child, test, etc?

        ...I don't know any reason to believe that you're still "in the sleep()" at the time your signal handler is running. (I can't claim knowledge of this about Windows, but I do know that for Unix,) you've already been interrupted from sleep() by the time your signal handler is running.

        So my expectation is that when your signal handler is running, it will complete, and your program will attempt to execute whatever follows the call to sleep() in its main flow of execution. So I don't think what you've suggested as a signal handler is too ambitious.

        You also said:

        I do have a abstracted method for checking the child is alive. Do you think that the sleep 1 until $child_is_dead will be to expensive on the machine?

        I can't tell for sure, but I would say that each time your main thread wakes and then puts itself back to sleep, you have a context switch, wait for the main thread to be scheduled onto the CPU and (on Unix at least) it then has the clock install another alarm to wake you up one second later.

        I can't really guess the impact to your system of having a one-second wake cycle on the speculative consideration that your child is dead. I would simply say this. We stress that signals are to be handled with care so that novice programmers will not go berserk trying to make everything hang off of this admittedly very crude form of IPC. And to be fair, signal handling has not always (some would say ever) been implemented very cleanly in the OS. But when a process is supposed to react to the death of a child process, that is one of the things that signals were explicitly designed to help you do.

        If you can make it work (on all of your desired platforms) by installing a signal handler, then that would be better than a one-second polling loop.

        But do be aware that I cannot tell how complicated your handler is or the impact in other ways to your server. So YMMV.

        ...All the world looks like -well- all the world, when your hammer is Perl.
        ---v

Re: Awake from sleep()
by John M. Dlugosz (Monsignor) on Nov 04, 2002 at 22:32 UTC
    I'm familiar with Win32, and the Sleep API function allows optional "defered procedure calls" which are queued and then triggered during sleep; this also wakes it from sleep when done.

    I think in principle though sleep is not the right primitive. You want a wait-on-event with an additional timeout. In Win32, I'd use an Event Flag for this. I'm sure any modern OS has a selection of mechanisms like this to choose from.

    How to do it portably in Perl? How about a socket? Sleeper does a blocking read on a socket, and signaler writes a byte to signal.

    —John

      Sounds like the socket solution might work. I mentioned below (in another reply) that the code needs to be platform independent. Is this possible with a socket? And, do you think adding socket communication would be overkill?

      until ($time_to_die) { # listen on socket for N seconds # check files, client, etc }
        How about a pm module that provides for simple blocking event flags. It can contain platform-specific code for known cases, and sockets for all else. That's like File::Copy, which uses native primitives in those cases where it can, and does it itself if it must or doesn't know of a better way.

Re: Awake from sleep()
by BrowserUk (Patriarch) on Nov 04, 2002 at 23:51 UTC

    If you opt for using kill under *nix, you might substitute Win32::Event and $event->wait([$timeout]) under Win32.


    Nah! Your thinking of Simon Templar, originally played by Roger Moore and later by Ian Ogilvy

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others chanting in the Monastery: (9)
As of 2024-03-28 10:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found