From aa112ef17f4fdfeecc05e5305af93a6d4b9fce70 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Wed, 4 Jan 2023 12:04:56 -0500
Subject: [PATCH] DRTVWR-575: Fix bug in macOS micro_sleep().

The compiler was deducing an unsigned type for the difference (U64 desired
microseconds - half KERNEL_SLEEP_INTERVAL_US). When the desired sleep was less
than that constant, the difference went hugely positive, resulting in a very
long snooze.

Amusingly, forcing that U64 result into an S32 num_sleep_intervals worked only
*because* of integer truncation: the high-order bits were discarded, resulting
in a negative result as intended.

Ensuring that both integer operands are signed at the outset, though, produces
a more formally correct result.
---
 indra/llcommon/lltimer.cpp | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp
index 74ec62d347c..58bedacf431 100644
--- a/indra/llcommon/lltimer.cpp
+++ b/indra/llcommon/lltimer.cpp
@@ -121,9 +121,14 @@ U32 micro_sleep(U64 us, U32 max_yields)
     U64 start = get_clock_count();
     // This is kernel dependent.  Currently, our kernel generates software clock
     // interrupts at 250 Hz (every 4,000 microseconds).
-    const U64 KERNEL_SLEEP_INTERVAL_US = 4000;
-
-    auto num_sleep_intervals = (us - (KERNEL_SLEEP_INTERVAL_US >> 1)) / KERNEL_SLEEP_INTERVAL_US;
+    const S64 KERNEL_SLEEP_INTERVAL_US = 4000;
+
+    // Use signed arithmetic to discover whether a sleep is even necessary. If
+    // either 'us' or KERNEL_SLEEP_INTERVAL_US is unsigned, the compiler
+    // promotes the difference to unsigned. If 'us' is less than half
+    // KERNEL_SLEEP_INTERVAL_US, the unsigned difference will be hugely
+    // positive, resulting in a crazy long wait.
+    auto num_sleep_intervals = (S64(us) - (KERNEL_SLEEP_INTERVAL_US >> 1)) / KERNEL_SLEEP_INTERVAL_US;
     if (num_sleep_intervals > 0)
     {
         U64 sleep_time = (num_sleep_intervals * KERNEL_SLEEP_INTERVAL_US) - (KERNEL_SLEEP_INTERVAL_US >> 1);
-- 
GitLab