pcntl_sigwaitinfo и обработчики сигналов

Я пишу демон, который периодически выполняет какую-то работу и некоторое время спит, прежде чем повторить ее снова. Но он все еще должен реагировать на внешние воздействия (например, запрос на завершение) во время сна.

Мне удалось реализовать тайм-аут сна с помощью сигнала ALRM и завершение с помощью сигнала TERM (пример):

// ...

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;
    }
}

// ...

Но, ради бога, я не могу понять, почему сигхандлер никогда не вызывается. Я получаю следующий вывод:

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

И в то же время, если я не устанавливаю этот обработчик, скрипт умирает из-за сигнала unhandler.

Я что-то упустил? Почему моя функция обработчика сигналов никогда не вызывается? Мешает ли pcntl_sigwaitinfo()?

И есть ли какие-либо другие средства для одновременной реализации тайм-аута и обработки сигнала?


person Kaero    schedule 10.10.2012    source источник


Ответы (1)


Это не совсем неожиданно.

Вы запросили доставку обработчику сигнала (pcntl_signal(...)), но затем также попросили принять сигнал без вызова каких-либо обработчиков (pcntl_sigwaitinfo(...)). Ваша ОС решает, что произойдет в этом случае, и ваша ОС (как и моя) решает позволить pcntl_sigwaitinfo() победить.

Задний план

Процесс может получить ("страдать?") сигнал двумя разными способами:

  1. асинхронная доставка
    #P4# #P5#
  2. синхронное принятие
    #P6# #P7#

Эти два способа, доставка и принятие, являются разные и не предназначены для совместного использования. AIX, например, просто запрещает "[c]текущее использование sigaction и sigwait".

(С вышесказанным связана концепция маски сигнала, которая может «блокировать» сигналы, эффективно заставляя их оставаться в ожидании до тех пор, пока они не будут приняты или пока «разблокированы» и не будут доставлены.)

person pilcrow    schedule 11.10.2012
comment
Спасибо. Так есть ли другой способ ждать сигналов без вызова pcntl_sigwaitinfo? Я считаю, что перепробовал все и все еще не смог добиться желаемого поведения. - person Kaero; 11.10.2012
comment
Пожалуйста. Если ответ был полезен, не стесняйтесь голосовать/принимать его. :) Что касается другого способа ожидания сигналов, то да, есть множество способов их обработки. Однако мне не ясно, какое поведение вы конкретно хотите. Возможно, уместно задать другой вопрос, иллюстрирующий желаемое вами поведение? - person pilcrow; 11.10.2012