| 97 | |
| 98 | #[pyfunction] |
| 99 | fn sleep(seconds: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { |
| 100 | let seconds_type_name = seconds.clone().class().name().to_owned(); |
| 101 | let dur = seconds.try_into_value::<Duration>(vm).map_err(|e| { |
| 102 | if e.class().is(vm.ctx.exceptions.value_error) |
| 103 | && let Some(s) = e.args().first().and_then(|arg| arg.str(vm).ok()) |
| 104 | && s.as_bytes() == b"negative duration" |
| 105 | { |
| 106 | return vm.new_value_error("sleep length must be non-negative"); |
| 107 | } |
| 108 | if e.class().is(vm.ctx.exceptions.type_error) { |
| 109 | return vm.new_type_error(format!( |
| 110 | "'{seconds_type_name}' object cannot be interpreted as an integer or float" |
| 111 | )); |
| 112 | } |
| 113 | e |
| 114 | })?; |
| 115 | |
| 116 | #[cfg(unix)] |
| 117 | { |
| 118 | // Loop on nanosleep, recomputing the |
| 119 | // remaining timeout after each EINTR so that signals don't |
| 120 | // shorten the requested sleep duration. |
| 121 | use std::time::Instant; |
| 122 | let deadline = Instant::now() + dur; |
| 123 | loop { |
| 124 | let remaining = deadline.saturating_duration_since(Instant::now()); |
| 125 | if remaining.is_zero() { |
| 126 | break; |
| 127 | } |
| 128 | let ts = nix::sys::time::TimeSpec::from(remaining); |
| 129 | let (res, err) = vm.allow_threads(|| { |
| 130 | let r = unsafe { libc::nanosleep(ts.as_ref(), core::ptr::null_mut()) }; |
| 131 | (r, nix::Error::last_raw()) |
| 132 | }); |
| 133 | if res == 0 { |
| 134 | break; |
| 135 | } |
| 136 | if err != libc::EINTR { |
| 137 | return Err( |
| 138 | vm.new_os_error(format!("nanosleep: {}", nix::Error::from_raw(err))) |
| 139 | ); |
| 140 | } |
| 141 | // EINTR: run signal handlers, then retry with remaining time |
| 142 | vm.check_signals()?; |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | #[cfg(not(unix))] |
| 147 | { |
| 148 | vm.allow_threads(|| std::thread::sleep(dur)); |
| 149 | } |
| 150 | |
| 151 | Ok(()) |
| 152 | } |
| 153 | |
| 154 | #[pyfunction] |
| 155 | fn time_ns(vm: &VirtualMachine) -> PyResult<u64> { |