|
11 | 11 | */
|
12 | 12 | class Loop
|
13 | 13 | {
|
14 |
| - /** Minimum time to wait between lock checks. In micro seconds. */ |
15 |
| - private const MINIMUM_WAIT_US = 10_000; |
16 |
| - |
17 |
| - /** Maximum time to wait between lock checks. In micro seconds. */ |
18 |
| - private const MAXIMUM_WAIT_US = 500_000; |
19 |
| - |
20 | 14 | /** True while code execution is repeating */
|
21 | 15 | private bool $looping = false;
|
22 | 16 |
|
@@ -63,34 +57,41 @@ public function execute(callable $code, float $timeout)
|
63 | 57 | // At this time, the lock will timeout.
|
64 | 58 | $deadlineTs = microtime(true) + $timeout;
|
65 | 59 |
|
| 60 | + $minWaitSecs = 0.1e-3; // 0.1 ms |
| 61 | + $maxWaitSecs = max(0.05, min(25, $timeout / 120)); // 50 ms to 25 s, based on timeout |
| 62 | + |
66 | 63 | $result = null;
|
67 |
| - for ($i = 0; $this->looping && microtime(true) < $deadlineTs; ++$i) { // @phpstan-ignore booleanAnd.leftAlwaysTrue |
| 64 | + for ($i = 0;; ++$i) { |
68 | 65 | $result = $code();
|
69 | 66 | if (!$this->looping) { // @phpstan-ignore booleanNot.alwaysFalse
|
70 | 67 | // The $code callback has called $this->end() and the lock has been acquired.
|
71 | 68 |
|
72 |
| - return $result; |
| 69 | + break; |
73 | 70 | }
|
74 | 71 |
|
75 | 72 | // Calculate max time remaining, don't sleep any longer than that.
|
76 |
| - $usecRemaining = LockUtil::getInstance()->castFloatToInt(($deadlineTs - microtime(true)) * 1e6); |
77 |
| - |
78 |
| - // We've ran out of time. |
79 |
| - if ($usecRemaining <= 0) { |
| 73 | + $remainingSecs = $deadlineTs - microtime(true); |
| 74 | + if ($remainingSecs <= 0) { |
80 | 75 | break;
|
81 | 76 | }
|
82 | 77 |
|
83 |
| - $min = min( |
84 |
| - self::MINIMUM_WAIT_US * 1.25 ** $i, |
85 |
| - self::MAXIMUM_WAIT_US |
| 78 | + $minSecs = min( |
| 79 | + $minWaitSecs * 1.5 ** $i, |
| 80 | + max($minWaitSecs, $maxWaitSecs / 2) |
| 81 | + ); |
| 82 | + $maxSecs = min($minSecs * 2, $maxWaitSecs); |
| 83 | + $sleepMicros = min( |
| 84 | + max(10, LockUtil::getInstance()->castFloatToInt($remainingSecs * 1e6)), |
| 85 | + random_int(LockUtil::getInstance()->castFloatToInt($minSecs * 1e6), LockUtil::getInstance()->castFloatToInt($maxSecs * 1e6)) |
86 | 86 | );
|
87 |
| - $max = min($min * 2, self::MAXIMUM_WAIT_US); |
88 | 87 |
|
89 |
| - $usecToSleep = min($usecRemaining, random_int((int) $min, (int) $max)); |
| 88 | + usleep($sleepMicros); |
| 89 | + } |
90 | 90 |
|
91 |
| - usleep($usecToSleep); |
| 91 | + if (microtime(true) >= $deadlineTs) { |
| 92 | + throw LockAcquireTimeoutException::create($timeout); |
92 | 93 | }
|
93 | 94 |
|
94 |
| - throw LockAcquireTimeoutException::create($timeout); |
| 95 | + return $result; |
95 | 96 | }
|
96 | 97 | }
|
0 commit comments