Merge "Localisation updates from https://translatewiki.net."
[lhc/web/wiklou.git] / includes / libs / WaitConditionLoop.php
index 3cc6236..969e86e 100644 (file)
@@ -34,11 +34,14 @@ class WaitConditionLoop {
        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
@@ -49,15 +52,24 @@ class WaitConditionLoop {
                $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.
         *
@@ -77,12 +89,19 @@ class WaitConditionLoop {
                        $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 );
@@ -128,18 +147,14 @@ class WaitConditionLoop {
         * @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;
        }