@@ -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 |
|