@@ -267,14 +267,32 @@ impl Thread {
|
267 | 267 | |
268 | 268 | #[cfg(target_os = "espidf")] |
269 | 269 | 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 { |
274 | 292 | libc::usleep(st); |
275 | | - |
276 | | - micros -= st as u128; |
277 | 293 | } |
| 294 | + |
| 295 | + micros -= st as u128; |
278 | 296 | } |
279 | 297 | } |
280 | 298 | |
|