private $timeout;
/** @var float Seconds */
private $lastWaitTime;
+ /** @var integer|null */
+ private $rusageMode;
const CONDITION_REACHED = 1;
const CONDITION_CONTINUE = 0; // evaluates as falsey
- const CONDITION_TIMED_OUT = -1;
- const CONDITION_ABORTED = -2;
+ const CONDITION_FAILED = -1;
+ const CONDITION_TIMED_OUT = -2;
+ const CONDITION_ABORTED = -3;
/**
* @param callable $condition Callback that returns a WaitConditionLoop::CONDITION_ constant
$this->condition = $condition;
$this->timeout = $timeout;
$this->busyCallbacks =& $busyCallbacks;
+
+ if ( defined( 'HHVM_VERSION' ) && PHP_OS === 'Linux' ) {
+ $this->rusageMode = 2; // RUSAGE_THREAD
+ } elseif ( function_exists( 'getrusage' ) ) {
+ $this->rusageMode = 0; // RUSAGE_SELF
+ }
}
/**
* Invoke the loop and continue until either:
- * - a) The condition callback does not return either CONDITION_CONTINUE or true
+ * - a) The condition callback returns neither CONDITION_CONTINUE nor false
* - b) The timeout is reached
* This a condition callback can return true (stop) or false (continue) for convenience.
* In such cases, the halting result of "true" will be converted to CONDITION_REACHED.
*
+ * If $timeout is 0, then only the condition callback will be called (no busy callbacks),
+ * and this will immediately return CONDITION_FAILED if the condition was not met.
+ *
* Exceptions in callbacks will be caught and the callback will be swapped with
* one that simply rethrows that exception back to the caller when invoked.
*
$checkResult = call_user_func( $this->condition );
$cpu = $this->getCpuTime() - $cpuStart;
$real = $this->getWallTime() - $realStart;
- // Exit if the condition is reached
- if ( (int)$checkResult !== self::CONDITION_CONTINUE ) {
- $finalResult = is_int( $checkResult ) ? $checkResult : self::CONDITION_REACHED;
+ // Exit if the condition is reached, and error occurs, or this is non-blocking
+ if ( $this->timeout <= 0 ) {
+ $finalResult = $checkResult ? self::CONDITION_REACHED : self::CONDITION_FAILED;
+ break;
+ } elseif ( (int)$checkResult !== self::CONDITION_CONTINUE ) {
+ if ( is_int( $checkResult ) ) {
+ $finalResult = $checkResult;
+ } else {
+ $finalResult = self::CONDITION_REACHED;
+ }
break;
} elseif ( $lastCheck ) {
- break; // timeout
+ break; // timeout reached
}
// Detect if condition callback seems to block or if justs burns CPU
$conditionUsesInterrupts = ( $real > 0.100 && $cpu <= $real * .03 );
* @return float Returns 0.0 if not supported (Windows on PHP < 7)
*/
protected function getCpuTime() {
- $time = 0.0;
-
- if ( defined( 'HHVM_VERSION' ) && PHP_OS === 'Linux' ) {
- $ru = getrusage( 2 /* RUSAGE_THREAD */ );
- } else {
- $ru = getrusage( 0 /* RUSAGE_SELF */ );
- }
- if ( $ru ) {
- $time += $ru['ru_utime.tv_sec'] + $ru['ru_utime.tv_usec'] / 1e6;
- $time += $ru['ru_stime.tv_sec'] + $ru['ru_stime.tv_usec'] / 1e6;
+ if ( $this->rusageMode === null ) {
+ return microtime( true ); // assume worst case (all time is CPU)
}
+ $ru = getrusage( $this->rusageMode );
+ $time = $ru['ru_utime.tv_sec'] + $ru['ru_utime.tv_usec'] / 1e6;
+ $time += $ru['ru_stime.tv_sec'] + $ru['ru_stime.tv_usec'] / 1e6;
+
return $time;
}