13
13
*/
14
14
class Loop
15
15
{
16
- /**
17
- * Minimum time that we want to wait, between lock checks. In micro seconds.
18
- */
19
- private const MINIMUM_WAIT_US = 1e4 ; // 0.01 seconds
20
-
21
- /**
22
- * Maximum time that we want to wait, between lock checks. In micro seconds.
23
- */
24
- private const MAXIMUM_WAIT_US = 5e5 ; // 0.50 seconds
25
-
26
16
/** @var float The timeout in seconds */
27
17
private $ timeout ;
28
18
@@ -80,10 +70,13 @@ public function execute(callable $code)
80
70
$ this ->looping = true ;
81
71
82
72
// At this time, the lock will time out.
83
- $ deadline = microtime (true ) + $ this ->timeout ;
73
+ $ deadlineTs = microtime (true ) + $ this ->timeout ;
74
+
75
+ $ minWaitSecs = 0.1e-3 ; // 0.1 ms
76
+ $ maxWaitSecs = max (0.05 , min (25 , $ this ->timeout / 120 )); // 50 ms to 25 s, based on timeout
84
77
85
78
$ result = null ;
86
- for ($ i = 0 ; $ this -> looping && microtime ( true ) < $ deadline ; ++$ i ) { // @phpstan-ignore booleanAnd.leftAlwaysTrue
79
+ for ($ i = 0 ;; ++$ i ) {
87
80
$ result = $ code ();
88
81
if (!$ this ->looping ) { // @phpstan-ignore booleanNot.alwaysFalse
89
82
// The $code callback has called $this->end() and the lock has been acquired.
@@ -92,24 +85,28 @@ public function execute(callable $code)
92
85
}
93
86
94
87
// Calculate max time remaining, don't sleep any longer than that.
95
- $ usecRemaining = (int ) (($ deadline - microtime (true )) * 1e6 );
96
-
97
- // We've ran out of time.
98
- if ($ usecRemaining <= 0 ) {
99
- throw TimeoutException::create ($ this ->timeout );
88
+ $ remainingSecs = $ deadlineTs - microtime (true );
89
+ if ($ remainingSecs <= 0 ) {
90
+ break ;
100
91
}
101
92
102
- $ min = min (
103
- (int ) self ::MINIMUM_WAIT_US * 1.25 ** $ i ,
104
- self ::MAXIMUM_WAIT_US
93
+ $ minSecs = min (
94
+ $ minWaitSecs * 1.5 ** $ i ,
95
+ max ($ minWaitSecs , $ maxWaitSecs / 2 )
96
+ );
97
+ $ maxSecs = min ($ minSecs * 2 , $ maxWaitSecs );
98
+ $ sleepMicros = min (
99
+ max (10 , (int ) ($ remainingSecs * 1e6 )),
100
+ random_int ((int ) ($ minSecs * 1e6 ), (int ) ($ maxSecs * 1e6 ))
105
101
);
106
- $ max = min ($ min * 2 , self ::MAXIMUM_WAIT_US );
107
102
108
- $ usecToSleep = min ($ usecRemaining , random_int ((int ) $ min , (int ) $ max ));
103
+ usleep ($ sleepMicros );
104
+ }
109
105
110
- usleep ($ usecToSleep );
106
+ if (microtime (true ) >= $ deadlineTs ) {
107
+ throw TimeoutException::create ($ this ->timeout );
111
108
}
112
109
113
- throw TimeoutException:: create ( $ this -> timeout ) ;
110
+ return $ result ;
114
111
}
115
112
}
0 commit comments