|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2005-07-20 09:40 UTC] vesely at tana dot it
Description: ------------ When using the Apache module it is not possible to use pcntl_alarm (why?). OTOH stream_set_timeout does not work on the "pipe" in descriptorspec. Of course, if the program really doesn't know _if_ there is any data to read, it should use stream_select and fgetc in a loop. Frequently enough, the program knows what it is doing and wants to sleep on fgets until data is available on the pipe. If anything goes wrong here, the two processes may hang waiting for each other. Meanwhile, the user angrily reloads the page knocking out yet another Apache's child... "NEEDED: a timeout for stdout pipe, otherwise a fgets on $pipes[1] can lag forever...)" has been for years in http://www.php.net/manual/en/function.proc-open.php#20866 The global script timeout is quite hard to manage from an included function. stream_select and fgets is good but is not bullet-proof. A request for a timer already exists (bug #9676), hence I guess I should ask for some "guarded-pipe" where the select-fgetc loop is coded in C using a time limit that can be set via stream_set_timeout. Is that cool? PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sun Oct 26 15:00:01 2025 UTC |
The simple solution is to NOT use fgets() when you're on a deadline, because of the greedy read semantic. Use fread() instead, in conjunction with stream_select() (which is what is used internally to implement the timeout). Here's an example from our test suite: function system_with_timeout($commandline) { $data = ""; $proc = proc_open($commandline, array( 0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w') ), $pipes, null, null, array("suppress_errors" => true)); if (!$proc) return false; fclose($pipes[0]); while (true) { /* hide errors from interrupted syscalls */ $r = $pipes; $w = null; $e = null; $n = @stream_select($r, $w, $e, 60); if ($n === 0) { /* timed out */ $data .= "\n ** ERROR: process timed out **\n"; proc_terminate($proc); return $data; } else if ($n > 0) { $line = fread($pipes[1], 8192); if (strlen($line) == 0) { /* EOF */ break; } $data .= $line; } } $stat = proc_get_status($proc); if ($stat['signaled']) { $data .= "\nTermsig=".$stat['stopsig']; } $code = proc_close($proc); return $data; }I have a couple of notes on that example. The function attempts to fread 8Kbytes, whilst a positive response from stream_select only guarantees that 1 byte can be read w/o blocking. Further, 60 secs is really eons. I'm using this: function guarded_fgets($pipes) { $line = ""; $time = 2; $c = "c"; while ($time >= 0 && ord($c) != 10) { $read = array($pipes[1]); while (!feof($read[0]) && ($n = stream_select($read, $w = NULL, $e = NULL, $time)) !== FALSE && $n > 0 && strlen($c = fgetc($read[0])) > 0 && ord($c) != 10) $line .= $c; --$time; } if (ord($c) != 10) { // error handling } return $line; }