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