Bug #71448 [Wfx]: declare(ticks=1) limited to scope of file makes Signal handling difficult

From: Date: Tue, 14 Mar 2017 13:03:15 +0000
Subject: Bug #71448 [Wfx]: declare(ticks=1) limited to scope of file makes Signal handling difficult
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-207826@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=71448&edit=1

 ID:                 71448
 Updated by:         nikic@php.net
 Reported by:        dave at atst dot io
 Summary:            declare(ticks=1) limited to scope of file makes
                     Signal handling difficult
 Status:             Wont fix
 Type:               Bug
 Package:            PCNTL related
 Operating System:   Linux
 PHP Version:        7.0Git-2016-01-25 (Git)
 Block user comment: N
 Private report:     N

 New Comment:

As an update on the previous comment: PHP 7.1 supports async signals, see https://wiki.php.net/rfc/async_signals. It looks
like pcntl_async_signals() is not documented yet. This allows handling signals without using ticks.


Previous Comments:
------------------------------------------------------------------------
[2016-05-14 17:22:58] nikic@php.net

Due to an implementation bug, the declare(ticks=1) directive leaked into different compilation units
prior to PHP 7.0. This is not how declare() directives, which are per-file or per-scope, are
supposed to work.

Using a single declare(ticks=1) in some class inside a multi-class autoloaded project doesn't
make a lot of sense. Even on PHP 5.x declare(ticks=1) would only affect code that is compiled
starting from that declaration, which means that depending on the loading order of classes your
whole codebase might end up using ticks or maybe only a few classes that were loaded late. (Not to
mention that using ticks will make your code many times slower, but that's a different issue.)

For PHP 7.1 we may make automatic pcntl signal handling work without ticks, as we now have a new
internal mechanism for handling ordinary timeouts which we can reuse.

------------------------------------------------------------------------
[2016-05-14 16:26:33] hamid dot a85 at gmail dot com

We were trying to add a timeout feature to laravel artisan command queue:work. But the
tests failed in PHP 7.0:
Pull request: https://github.com/laravel/framework/pull/13425

A simpler test case that fails:
https://github.com/halaei/ticks-bug-php-7
https://travis-ci.org/halaei/ticks-bug-php-7/builds/130244558

Code:
#main.php
<?php

declare(ticks=1);
pcntl_signal(SIGALRM, function ($sig) {
    die(0);
});

require_once __DIR__ . '/loop.php';


#loop.php
<?php

pcntl_alarm(2);
while (true) {
    sleep(10);
}


Expected behavior: the code terminates after 2 seconds
Observed behavior: the code will never terminate.

------------------------------------------------------------------------
[2016-04-25 01:19:39] nathan dot renniewaldock at gmail dot com

I've noticed this too.
I've got an IRC bot in PHP, I'm handling SIGINT to clean up before exiting.
With declare(ticks=1] in an included file,
in 5.6.20: triggered near instant
in 7.0.4: can take up to 20 seconds. Near instant after moving declare to the main file.
There's also no mention of this change in the migration guide.

------------------------------------------------------------------------
[2016-01-25 21:42:16] dave at atst dot io

Description:
------------
Not sure if this is intended behaviour or fallout from other declare directives intending to be
scoped to a particular file.

The manual states:

The declare construct can also be used in the global scope, affecting all code following it (however
if the file with declare was included then it does not affect the parent file).

I've attached a script that tries to show what I'm trying to do automatically, but you can
remove the forking and just try and ctrl-c from your terminal.

Test script:
---------------
<?php

declare(ticks=1);

$start = time();
pcntl_signal(SIGINT, function() use ($start) {
    $diff = time() - $start;
    echo "SIGINT received after $diff seconds\n";
    exit;
});

$id = posix_getpid();

$child = pcntl_fork();

if ($child) {
    include 'inc.php';
} else {
    posix_kill($id, SIGINT);
}


## inc.php

<?php

$a = 0;
$start = time();
while(time() < $start + 5) {
    $a = $a + 2; # something tickable
}


Expected result:
----------------
SIGINT received after 0 seconds

Actual result:
--------------
SIGINT received after 5 seconds


------------------------------------------------------------------------



--
Edit this bug report at https://bugs.php.net/bug.php?id=71448&edit=1


Thread (5 messages)

« previous php.bugs (#207826) next »