Question

I'm writing a daemon which periodcally does some work and sleeps some time before repeating it again. But it must still be responsive to outer impacts (i.e. termination request) while asleep.

I managed to implement sleep timeout with ALRM signal and termination with TERM signal (sample):

// ...

declare(ticks = 1);

function do_work()
{
    echo "Doing some work.\n";
}

$term = FALSE;

$sighandler = function ($signal) use (&$term)
{
    if ($signal === SIGTERM)
    {
        pcntl_alarm(0);

        $term = TRUE;

        echo "TERM HANDLER\n";
    } else {
        echo "ALRM HANDLER\n";
    }
};

pcntl_signal(SIGALRM, $sighandler);
pcntl_signal(SIGTERM, $sighandler);

while (!$term)
{
    do_work();

    // Kick myself after 2 seconds
    pcntl_alarm(2);

    // Wait for alarm or termination
    $signal = pcntl_sigwaitinfo(array(SIGTERM, SIGALRM), $info);

    pcntl_signal_dispatch();

    switch ($signal)
    {
        case SIGALRM: echo "ALRM SIGWI\n"; break;
        case SIGTERM: echo "TERM SIGWI\n"; $term = TRUE; break;
    }
}

// ...

But for Gods sake I can't figure out why the sighandler is never called. I get the following output:

$ php sigsample.php
Doing some work.
ALRM SIGWI
Doing some work.
ALRM SIGWI
Doing some work.
TERM SIGWI

And at the same time if I don't set this handler the script dies because of unhandler signal.

Am I missing somethind? Why is my signal handler function never called? Is it pcntl_sigwaitinfo() interferes?

And are there are any other means to implement timeout and signal handling at the same time?

Was it helpful?

Solution

That's not entirely unexpected.

You've asked for delivery to a signal handler (pcntl_signal(...)), but then also asked to accept the signal without invoking any handlers (pcntl_sigwaitinfo(...)). Your OS gets to decide what happens in this case, and your OS (like mine) chooses to let pcntl_sigwaitinfo() win.

Background

A process can receive ("suffer?") a signal in two different ways:

  1. asynchronous delivery

    The signal induces some asynchronous action, typically killing the process or invoking a user-defined handler. pcntl_signal registers just such a handler.

    The underlying calls familiar to C programmers are signal and sigaction.

  2. synchronous acceptance

    Special system functions note that a signal is pending, and remove it from the pending list, returning information about the signal to the process. pcntl_sigwaitinfo is such a function.

    The underlying calls are sigwait, sigwaitinfo and sigtimedwait.

These two ways, delivery and acceptance, are different and are not meant to be used together. AIX, for example, simply forbids "[c]oncurrent use of sigaction and sigwait".

(Related to the above is the concept of the signal mask, which can "block" signals, effectively forcing them to stay pending until accepted or until "unblocked" and delivered.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top