|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2021-02-10 17:34 UTC] calvin at cmpct dot info
Description:
------------
When the PHP built-in development webserver finishes a request, it resets PHP's timer to defaults. On ITIMER_PROF (most) platforms, this usually isn't a problem because listening causes PHP to block on listen, stopping it from counting in execution time. On ITIMER_REAL platforms (IBM i and Cygwin), the timer will continue to count down and hit the hard timeout, killing an idle PHP development web server. (This may affect other mediums of PHP, but the development web server is the easiest case.)
The attached patch will add debug output for handling the ITIMER cases and let you force ITIMER_REAL on Linux.
The issue is likely reproducible on 7.3 and 8.0.
Test script:
---------------
<?php
set_time_limit(10); // recommend setting to a large value to diagnose ITIMER_REAL
$i = 0;
while(true) {
sleep(1); // comment if using ITIMER_PROF because it won't count
echo "$i<br/>\n";
$i++;
ob_flush();
flush();
}
Expected result:
----------------
$ (cd ~/src/long/; /tmp/php7.4/bin/php -S 0.0.0.0:8080; date)
[Wed Feb 10 13:19:30 2021] PHP 7.4.15RC1 Development Server (http://0.0.0.0:8080) started
[Wed Feb 10 13:19:30 2021] 127.0.0.1:45308 Accepted
** Setting prof timer for 30.0 seconds **
** UnSetting prof timer **
** Setting prof timer for 10.0 seconds **
** Setting prof timer for 2.0 seconds **
[Wed Feb 10 13:19:41 2021] 127.0.0.1:45308 [200]: GET / - Maximum execution time of 10 seconds exceeded in /home/calvin/src/long/index.php on line 11
** UnSetting prof timer **
** UnSetting prof timer **
** Setting prof timer for 30.0 seconds **
[Wed Feb 10 13:19:41 2021] 127.0.0.1:45308 Closing
Actual result:
--------------
$ (cd ~/src/long/; /tmp/php7.4/bin/php -S 0.0.0.0:8080; date)
[Wed Feb 10 13:13:34 2021] PHP 7.4.15RC1 Development Server (http://0.0.0.0:8080) started
[Wed Feb 10 13:13:38 2021] 127.0.0.1:45126 Accepted
** Setting real timer for 30.0 seconds **
** UnSetting real timer **
** Setting real timer for 10.0 seconds **
** Setting real timer for 2.0 seconds **
[Wed Feb 10 13:13:48 2021] 127.0.0.1:45126 [200]: GET / - Maximum execution time of 10 seconds exceeded in /home/calvin/src/long/index.php on line 8
** UnSetting real timer **
** UnSetting real timer **
** Setting real timer for 30.0 seconds **
[Wed Feb 10 13:13:48 2021] 127.0.0.1:45126 Closing
[Wed Feb 10 13:13:48 2021] 127.0.0.1:45128 Accepted
[Wed Feb 10 13:13:48 2021] 127.0.0.1:45128 Closed without sending a request; it was probably just an unused speculative preconnection
[Wed Feb 10 13:13:48 2021] 127.0.0.1:45128 Closing
** Setting real timer for 2.0 seconds ** Fatal error: Maximum execution time of 30+2 seconds exceeded (terminated) in Unknown on line 0
Wed 10 Feb 2021 01:14:20 PM AST
Patchesforce-problematic-timer.diff (last revision 2021-02-10 17:34 UTC by calvin at cmpct dot info)Pull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sat Oct 25 15:00:01 2025 UTC |
I think the problem is for the max_execution_time handler (OnUpdateTimeout) - that seems to reset it even when there's no script running if it was changed. Diff: ``` diff --git a/main/main.c b/main/main.c index 1cb50ce1dd..eedce27f8f 100644 --- a/main/main.c +++ b/main/main.c @@ -467,6 +467,7 @@ static PHP_INI_MH(OnUpdateTimeout) } zend_unset_timeout(); ZEND_ATOL(EG(timeout_seconds), ZSTR_VAL(new_value)); +fprintf(stderr, " ** Updating timeout to %d ** \n", EG(timeout_seconds)); zend_set_timeout(EG(timeout_seconds), 0); return SUCCESS; } ``` Output: ``` ** Setting real timer for 30.0 seconds ** ** UnSetting real timer ** ** Updating timeout to 45 ** ** Setting real timer for 45.0 seconds ** ** Setting real timer for 2.0 seconds ** [Thu Feb 11 16:23:02 2021] ip.address:40006 [200]: GET / - Maximum execution time of 45 seconds exceeded in /home/calvin/tmp/long/index.php on line 8 ** UnSetting real timer ** ** UnSetting real timer ** ** Updating timeout to 30 ** ** Setting real timer for 30.0 seconds ** [Thu Feb 11 16:23:02 2021] ip.address:40006 Closing [Thu Feb 11 16:23:04 2021] ip.address:40022 Accepted ** Setting real timer for 30.0 seconds ** ** Setting real timer for 2.0 seconds ** [Thu Feb 11 16:23:34 2021] ip.address:40022 [200]: GET /index2.php - Maximum execution time of 30 seconds exceeded in /home/calvin/tmp/long/index2.php on line 8 ** UnSetting real timer ** [Thu Feb 11 16:23:34 2021] ip.address:40022 Closing ```