Пишу, по большей части, про историю, свою жизнь и немного про программирование.

Функция sleep и сигналы

Век живи, век учись. Вот уж не знал, что при получении сигнала программой на ПХП, моментально прерывается выполнение функции sleep (и родственных ей time_nanosleep и usleep):

$ php -r 'pcntl_signal(SIGUSR1, "_"); var_dump(sleep(PHP_INT_MAX));' &
[1] 3177
$ kill -USR1 3177
$ int(4294967288)

Вообще в Си так же, но где ПХП и где Си. Как и в Си, назад возвращается количество секунд, которые функция не «доспала» (time_nanosleep возвращает массив из секунд и наносекунд, а usleep — NULL). Правда под Виндой есть особенность — sleep при «недосыпе» всегда возвращает 192 (значение константы WAIT_IO_COMPLETION).

Любопытное исключение из правила — time_sleep_until, она сигналы игнорирует. Так что если вам нужна гарантированная по времени задержка, используйте её или напишите обёртку:

function bulletproof_sleep(int $seconds): bool
{
    $period = ['seconds' => $seconds, 'nanoseconds' => 0];

    while (array_sum($period) > 0) {
        $period = time_nanosleep($period['seconds'], $period['nanoseconds']);

        if (is_bool($period)) {
            return $period;
        }
    }

    return true;
}
4 комментария
PastorGL 2018

а чему тут удивляться. *sleep в любом языке это всегда очень тонкие обёртки над соответствующими системными вызовами, а они везде одинаковые со времён царя гороха, и реагируют на сигналы by design. на это даже термин есть специальный, spurious wakeup.

Евгений Степанищев 2018

Как-то у меня связалось всё это вместе, может потому что ПХП мне кажется страшно далёким от Си. Но вы должны тогда удивиться, что time_sleep_until почему-то на сигнал не реагирует (я пробовал).

PastorGL 2018

нууу, если рассуждать об общей картине, то почти любой язык — это обёртка над де факто стандартными сишными библиотеками, а если не над ними непосредственно, то над слоем аби операционки, которая в той или иной мере реализует стандарт посикс (потому как в современном мире без него никуда), выросший из юникса, где основным языком был си, и стандартной библиотекой был силиб. даже в жабе и то Thread.sleep() это обёртка над сисколом sleep, хотя казалось бы жаба это про jvm. но нет, в жабе тоже дёргается нативная реализация. что уж про пых говорить, он к платформе ещё ближе.

подозреваю, что time_sleep_until дёргает в итоге посиксовый timer_create. он на сигналы реагировать не должен (потому как обычно это примитив операционки), но при срабатывании сам шлёт вызывающему процессу соответствующий сигнал.

Евгений Степанищев 2018

Да я-то это всё умом понимаю, а всё равно сердце принимать не хочет :))