Fix for issue #129212 for the ESP-IDF · patricklam/verify-rust-std@0b0dad4

Original file line numberDiff line numberDiff line change

@@ -267,14 +267,32 @@ impl Thread {

267267
268268

#[cfg(target_os = "espidf")]

269269

pub fn sleep(dur: Duration) {

270-

let mut micros = dur.as_micros();

271-

unsafe {

272-

while micros > 0 {

273-

let st = if micros > u32::MAX as u128 { u32::MAX } else { micros as u32 };

270+

// ESP-IDF does not have `nanosleep`, so we use `usleep` instead.

271+

// As per the documentation of `usleep`, it is expected to support

272+

// sleep times as big as at least up to 1 second.

273+

//

274+

// ESP-IDF does support almost up to `u32::MAX`, but due to a potential integer overflow in its

275+

// `usleep` implementation

276+

// (https://github.com/espressif/esp-idf/blob/d7ca8b94c852052e3bc33292287ef4dd62c9eeb1/components/newlib/time.c#L210),

277+

// we limit the sleep time to the maximum one that would not cause the underlying `usleep` implementation to overflow

278+

// (`portTICK_PERIOD_MS` can be anything between 1 to 1000, and is 10 by default).

279+

const MAX_MICROS: u32 = u32::MAX - 1_000_000 - 1;

280+
281+

// Add any nanoseconds smaller than a microsecond as an extra microsecond

282+

// so as to comply with the `std::thread::sleep` contract which mandates

283+

// implementations to sleep for _at least_ the provided `dur`.

284+

// We can't overflow `micros` as it is a `u128`, while `Duration` is a pair of

285+

// (`u64` secs, `u32` nanos), where the nanos are strictly smaller than 1 second

286+

// (i.e. < 1_000_000_000)

287+

let mut micros = dur.as_micros() + if dur.subsec_nanos() % 1_000 > 0 { 1 } else { 0 };

288+
289+

while micros > 0 {

290+

let st = if micros > MAX_MICROS as u128 { MAX_MICROS } else { micros as u32 };

291+

unsafe {

274292

libc::usleep(st);

275-
276-

micros -= st as u128;

277293

}

294+
295+

micros -= st as u128;

278296

}

279297

}

280298