StreamSelectLoop: Int overflow for big timer intervals#96
StreamSelectLoop: Int overflow for big timer intervals#96ivkalita wants to merge 7 commits intoreactphp:masterfrom
Conversation
31a613a to
a4bf806
Compare
| protected function sleep($seconds, $nanoseconds = 0) | ||
| { | ||
| if ($seconds > 0 || $nanoseconds > 0) { | ||
| time_nanosleep($seconds, $nanoseconds); |
There was a problem hiding this comment.
I'd like to see explicit handling of $secondsor $nanosecondsbeing null here.
| if ($time == PHP_INT_MAX) { | ||
| return PHP_INT_MAX; | ||
| } | ||
|
|
There was a problem hiding this comment.
Minor nitpicking: for consistency with the other 2 methods, i'd like to an early return for $time === null:
if ($time === null) {
return null;
}
// ...
return intval(floor($time));a4bf806 to
08c709b
Compare
src/StreamSelectLoop.php
Outdated
| */ | ||
| private static function getMicroseconds($time) | ||
| { | ||
| if ($time === null) { |
There was a problem hiding this comment.
Should probably return 0. stream_select accepts null only for the $seconds parameter.
src/StreamSelectLoop.php
Outdated
| */ | ||
| private static function getNanoseconds($time) | ||
| { | ||
| if ($time === null) { |
There was a problem hiding this comment.
Should probably return 0, see above.
| * @param array $read | ||
| * @param array $write | ||
| * @param array $except | ||
| * @param int|null $seconds |
There was a problem hiding this comment.
Should only accept int, see also above.
|
@jsor, thank you for the review. I think that previous implementation was not explicit, cause |
c78624d to
4347fa3
Compare
src/StreamSelectLoop.php
Outdated
| protected function streamSelect(array &$read, array &$write, $timeout) | ||
| { | ||
| $seconds = $timeout === null ? null : self::getSeconds($timeout); | ||
| $microseconds = $timeout === null ? 0 : self::getMicroseconds($timeout); |
There was a problem hiding this comment.
Calculation of $microseconds and $nanoseconds can probably be moved into the ifs so they are only calculated when needed.
| * (float)PHP_INT_MAX == PHP_INT_MAX => true | ||
| * (int)(float)PHP_INT_MAX == PHP_INT_MAX => false | ||
| * (int)(float)PHP_INT_MAX == PHP_INT_MIN => true | ||
| */ |
There was a problem hiding this comment.
@jsor, $time is float, so strict comparison will always return false.
(float) PHP_INT_MAX === PHP_INT_MAX; //is false
(float) PHP_INT_MAX == PHP_INT_MAX; //is trueThere was a problem hiding this comment.
👍 (maybe add a comment that loose comparision is intentional)
|
ping @clue |
|
@clue, can you please describe, why did you mark this PR as BC Break? Imo, only internal representation of time changed and no public interfaces modified... |
clue
left a comment
There was a problem hiding this comment.
Thanks for filing this PR! These are some high quality changes and I'd actually like to get this in to solve this rare issue 👍
The issue only affects 32 bit systems, yet this PR proposes some major changes to the whole StreamSelectLoop, which contains some very performance-critical code.
Does it make sense to perform some benchmarks to check its impact?
| * | ||
| * @param array &$read An array of read streams to select upon. | ||
| * @param array &$write An array of write streams to select upon. | ||
| * @param integer|null $timeout Activity timeout in microseconds, or null to wait forever. |
There was a problem hiding this comment.
This is a rather subtle BC break as consumers could possibly rely on this protected API. Not saying this is an issue with your proposed change, it's more that we screwed up could have done better with defining our external API.
The problem
As described here, current
StreamSelectLoopimplementation restricts using time intervals more thanPHP_INT_MAXmicroseconds. For 32-bit systems it's only 2148 seconds.Suggested solution
StreamSelectLoop$timeouttype fromint(in microseconds) tofloat(in seconds);usleepwithtime_nanosleep, causeusleeptakesintargument in microseconds, and we can't keep more thanPHP_INT_MAXmicroseconds. Buttime_nanosleeptakes 2 arguments:intamount of seconds andintamount of nanoseconds, that allowsStreamSelectLoopto handlePHP_INT_MAXseconds intervals;stream_selectandtime_nanosleepmethods calls fromStreamSelectLoop::streamSelect(...)to test timeout values.