#31749 [Opn->Fbk]: deadlock due to libc mutexes not released when timeout signal is delivered
| From: | jani@php.net | Date: | Sun, 13 Jul 2008 15:52:05 +0000 |
| Subject: | #31749 [Opn->Fbk]: deadlock due to libc mutexes not released when timeout signal is delivered | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-126609@lists.php.net to get a copy of this message | ||
ID: 31749
Updated by: jani@php.net
Reported By: phpbug2 at mailinator dot com
-Status: Open
+Status: Feedback
Bug Type: Scripting Engine problem
Operating System: Linux 2.4.28, 2.4.21-SMP
PHP Version: 5CVS, 4CVS (2005-06-19)
Assigned To: dmitry
Previous Comments:
------------------------------------------------------------------------
[2008-07-13 15:51:47] jani@php.net
Please try using this CVS snapshot:
http://snaps.php.net/php5.2-latest.tar.gz
For Windows (zip):
http://snaps.php.net/win32/php5.2-win32-latest.zip
For Windows (installer):
http://snaps.php.net/win32/php5.2-win32-installer-latest.msi
------------------------------------------------------------------------
[2005-12-24 02:46:25] sniper@php.net
Dmitry, can you check this out please?
------------------------------------------------------------------------
[2005-02-20 15:55:55] wez@php.net
Andi, please take a look. I remember some talk in the past about going
this route, but I don't recall the arguments against it.
Similarly, I'm not sure that this is really a problem for PHP to fix;
given that the time() function is officially not thread-safe, it seems
wrong for the libc to mutex internally.
------------------------------------------------------------------------
[2005-02-19 22:28:32] phpbug2 at mailinator dot com
I've created a patch against 5.0.3 to implement my "soft timeout" idea
above. It will try to soft-break execution after the timeout period
elapses and then hard-break after another timeout period.
There seem to be a lot of calls to the zend_set_timeout and
zend_unset_timeout functions that I'm not too sure are helping the
situation. Here's what happens using the CLI PHP and printing whenever
certain functions are hit:
$ sapi/cli/php /www/htdocs/time.php
zend_unset_timeout()
zend_set_timeout (0)
zend_set_timeout (0)
zend_set_timeout (0)
zend_unset_timeout()
zend_set_timeout (5)
Array 2005 2217696508 Jan-01-1998 Jan 01 1998 05:00:00
Array 2005 2217696508 Jan-01-1998 Jan 01 1998 05:00:00
Array 2005 2217696510 Jan-01-1998 Jan 01 1998 05:00:00
Array 2005 2217696512 Jan-01-1998 Jan 01 1998 05:00:00
Array 2005 2217696516 Jan-01-1998 Jan 01 1998 05:00:00
Array 2005 2217696516 Jan-01-1998 Jan 01 1998 05:00:00
zend_soft_timeout()
zend_set_timeout (5)
zend_timeout()
zend_set_timeout (5)
Fatal error: Maximum execution time of 5 seconds exceeded in
/www/htdocs/time.php on line 10
zend_unset_timeout()
zend_set_timeout (30)
zend_unset_timeout()
And the patch to 5.0.3 to implement the "zend_soft_timeout" that "works
for me" in that I'm not getting any more deadlocked Apache children:
http://www.r1hosting.net/zend_timeout.patch
------------------------------------------------------------------------
[2005-02-03 12:10:41] phpbug2 at mailinator dot com
I believe this is the buggy code. It is setting a signal handler for
SIGPROF that immediately dumps a timeout error message when the signal
is received. However if the signal is delivered whilst PHP is processing
a libc call to time(), a pthread mutex within libc is not released,
causing a deadlock when Apache tries to call time() for the output.
A fix would be to have PHP set some flag such as "processing time
exceeded" for the request and to then abort the request at the next
available opporunity from within PHP instead of jumping out and leaving
libc in a potentially unstable or dangerous state. Obviously this
reduces the effectiveness of the maximum execution timeout as a blocking
libc call could cause the timeout to be greatly exceeded, but I see no
other safe way of handling this without leaving libc in a potentially
dangerous state. Perhaps two signals could be used, the first one to
break execution if possible at the next available opportunity and then
the current "hard" break if no response within 15 seconds or something.
ZEND_API void zend_timeout(int dummy)
{
TSRMLS_FETCH();
if (zend_on_timeout) {
zend_on_timeout(EG(timeout_seconds) TSRMLS_CC);
}
zend_error(E_ERROR, "Maximum execution time of %d second%s
exceeded",
EG(timeout_seconds), EG(timeout_seconds) == 1
? "" : "s");
}
...
t_r.it_value.tv_sec = seconds;
t_r.it_value.tv_usec = t_r.it_interval.tv_sec =
t_r.it_interval.tv_usec = 0;
setitimer(ITIMER_PROF, &t_r, NULL);
signal(SIGPROF, zend_timeout);
sigemptyset(&sigset);
sigaddset(&sigset, SIGPROF);
sigprocmask(SIG_UNBLOCK, &sigset, NULL);
}
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
http://bugs.php.net/31749
--
Edit this bug report at http://bugs.php.net/?id=31749&edit=1