mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Merge pull request #4512 from RustPython/upd-nix
Update nix & use its functions more
This commit is contained in:
463
Cargo.lock
generated
463
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -37,7 +37,7 @@ insta = "1.14.0"
|
||||
itertools = "0.10.3"
|
||||
libc = "0.2.133"
|
||||
log = "0.4.16"
|
||||
nix = "0.24"
|
||||
nix = "0.26"
|
||||
num-complex = "0.4.0"
|
||||
num-bigint = "0.4.3"
|
||||
num-integer = "0.1.44"
|
||||
|
||||
@@ -177,6 +177,8 @@ fn exec_inner(args: &ForkExecArgs, procargs: ProcArgs) -> nix::Result<Never> {
|
||||
|
||||
let mut first_err = None;
|
||||
for exec in args.exec_list.as_slice() {
|
||||
// not using nix's versions of these functions because those allocate the char-ptr array,
|
||||
// and we can't allocate
|
||||
if let Some(envp) = procargs.envp {
|
||||
unsafe { libc::execve(exec.s.as_ptr(), procargs.argv.as_ptr(), envp.as_ptr()) };
|
||||
} else {
|
||||
@@ -195,9 +197,8 @@ fn close_fds(above: i32, keep: &[i32]) -> nix::Result<()> {
|
||||
use nix::{dir::Dir, fcntl::OFlag};
|
||||
// TODO: close fds by brute force if readdir doesn't work:
|
||||
// https://github.com/python/cpython/blob/3.8/Modules/_posixsubprocess.c#L220
|
||||
let path = unsafe { CStr::from_bytes_with_nul_unchecked(FD_DIR_NAME) };
|
||||
let mut dir = Dir::open(
|
||||
path,
|
||||
FD_DIR_NAME,
|
||||
OFlag::O_RDONLY | OFlag::O_DIRECTORY,
|
||||
nix::sys::stat::Mode::empty(),
|
||||
)?;
|
||||
@@ -219,10 +220,10 @@ fn close_fds(above: i32, keep: &[i32]) -> nix::Result<()> {
|
||||
target_os = "openbsd",
|
||||
target_vendor = "apple",
|
||||
))]
|
||||
const FD_DIR_NAME: &[u8] = b"/dev/fd\0";
|
||||
const FD_DIR_NAME: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"/dev/fd\0") };
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
const FD_DIR_NAME: &[u8] = b"/proc/self/fd\0";
|
||||
const FD_DIR_NAME: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"/proc/self/fd\0") };
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
fn pos_int_from_ascii(name: &CStr) -> Option<i32> {
|
||||
|
||||
@@ -891,53 +891,8 @@ mod _socket {
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
let buf = crate::vm::function::ArgStrOrBytesLike::try_from_object(vm, addr)?;
|
||||
let path = &*buf.borrow_bytes();
|
||||
if cfg!(any(target_os = "linux", target_os = "android"))
|
||||
&& path.first() == Some(&0)
|
||||
{
|
||||
use libc::{sa_family_t, socklen_t};
|
||||
use {socket2::SockAddr, std::ptr};
|
||||
unsafe {
|
||||
// based on SockAddr::unix
|
||||
// TODO: upstream or fix socklen check for SockAddr::unix()?
|
||||
SockAddr::init(|storage, len| {
|
||||
// Safety: `SockAddr::init` zeros the address, which is a valid
|
||||
// representation.
|
||||
let storage: &mut libc::sockaddr_un = &mut *storage.cast();
|
||||
let len: &mut socklen_t = &mut *len;
|
||||
|
||||
let bytes = path;
|
||||
if bytes.len() > storage.sun_path.len() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"path must be shorter than SUN_LEN",
|
||||
));
|
||||
}
|
||||
|
||||
storage.sun_family = libc::AF_UNIX as sa_family_t;
|
||||
// Safety: `bytes` and `addr.sun_path` are not overlapping and
|
||||
// both point to valid memory.
|
||||
// `SockAddr::init` zeroes the memory, so the path is already
|
||||
// null terminated.
|
||||
ptr::copy_nonoverlapping(
|
||||
bytes.as_ptr(),
|
||||
storage.sun_path.as_mut_ptr() as *mut u8,
|
||||
bytes.len(),
|
||||
);
|
||||
|
||||
let base = storage as *const _ as usize;
|
||||
let path = &storage.sun_path as *const _ as usize;
|
||||
let sun_path_offset = path - base;
|
||||
let length = sun_path_offset + bytes.len();
|
||||
*len = length as socklen_t;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
.map(|(_, addr)| addr)
|
||||
} else {
|
||||
socket2::SockAddr::unix(ffi::OsStr::from_bytes(path))
|
||||
}
|
||||
.map_err(|_| vm.new_os_error("AF_UNIX path too long".to_owned()).into())
|
||||
socket2::SockAddr::unix(ffi::OsStr::from_bytes(path))
|
||||
.map_err(|_| vm.new_os_error("AF_UNIX path too long".to_owned()).into())
|
||||
}
|
||||
c::AF_INET => {
|
||||
let tuple: PyTupleRef = addr.downcast().map_err(|obj| {
|
||||
@@ -1087,20 +1042,7 @@ mod _socket {
|
||||
_ => {}
|
||||
}
|
||||
if socket_kind == -1 {
|
||||
// TODO: when socket2 cuts a new release, type will be available on all os
|
||||
// socket_kind = sock.r#type().map_err(|e| e.into_pyexception(vm))?.into();
|
||||
let res = unsafe {
|
||||
c::getsockopt(
|
||||
sock_fileno(&sock) as _,
|
||||
c::SOL_SOCKET,
|
||||
c::SO_TYPE,
|
||||
&mut socket_kind as *mut libc::c_int as *mut _,
|
||||
&mut (std::mem::size_of::<i32>() as _),
|
||||
)
|
||||
};
|
||||
if res < 0 {
|
||||
return Err(crate::common::os::errno().into());
|
||||
}
|
||||
socket_kind = sock.r#type().map_err(|e| e.into_pyexception(vm))?.into();
|
||||
}
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(
|
||||
@@ -1601,30 +1543,23 @@ mod _socket {
|
||||
if let Some(addr) = addr.as_socket() {
|
||||
return get_ip_addr_tuple(&addr, vm);
|
||||
}
|
||||
match addr.family() as i32 {
|
||||
#[cfg(unix)]
|
||||
libc::AF_UNIX => {
|
||||
let addr_len = addr.len() as usize;
|
||||
let unix_addr = unsafe { &*(addr.as_ptr() as *const libc::sockaddr_un) };
|
||||
let path_u8 = unsafe { &*(&unix_addr.sun_path[..] as *const [_] as *const [u8]) };
|
||||
let sun_path_offset =
|
||||
&unix_addr.sun_path as *const _ as usize - unix_addr as *const _ as usize;
|
||||
if cfg!(any(target_os = "linux", target_os = "android"))
|
||||
&& addr_len > sun_path_offset
|
||||
&& unix_addr.sun_path[0] == 0
|
||||
{
|
||||
let abstractaddrlen = addr_len - sun_path_offset;
|
||||
let abstractpath = &path_u8[..abstractaddrlen];
|
||||
vm.ctx.new_bytes(abstractpath.to_vec()).into()
|
||||
} else {
|
||||
let len = memchr::memchr(b'\0', path_u8).unwrap_or(path_u8.len());
|
||||
let path = &path_u8[..len];
|
||||
vm.ctx.new_str(String::from_utf8_lossy(path)).into()
|
||||
}
|
||||
#[cfg(unix)]
|
||||
use nix::sys::socket::{SockaddrLike, UnixAddr};
|
||||
#[cfg(unix)]
|
||||
if let Some(unix_addr) = unsafe { UnixAddr::from_raw(addr.as_ptr(), Some(addr.len())) } {
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
if let Some(abstractpath) = unix_addr.as_abstract() {
|
||||
return vm.ctx.new_bytes([b"\0", abstractpath].concat()).into();
|
||||
}
|
||||
// TODO: support more address families
|
||||
_ => (String::new(), 0).to_pyobject(vm),
|
||||
// necessary on macos
|
||||
let path = ffi::OsStr::as_bytes(unix_addr.path().unwrap_or("".as_ref()).as_ref());
|
||||
let nul_pos = memchr::memchr(b'\0', path).unwrap_or(path.len());
|
||||
let path = ffi::OsStr::from_bytes(&path[..nul_pos]);
|
||||
return vm.ctx.new_str(path.to_string_lossy()).into();
|
||||
}
|
||||
// TODO: support more address families
|
||||
(String::new(), 0).to_pyobject(vm)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
@@ -1764,25 +1699,19 @@ mod _socket {
|
||||
let fd = sock_fileno(sock);
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let mut pollfd = libc::pollfd {
|
||||
fd,
|
||||
events: match kind {
|
||||
SelectKind::Read => libc::POLLIN,
|
||||
SelectKind::Write => libc::POLLOUT,
|
||||
SelectKind::Connect => libc::POLLOUT | libc::POLLERR,
|
||||
},
|
||||
revents: 0,
|
||||
use nix::poll::*;
|
||||
let events = match kind {
|
||||
SelectKind::Read => PollFlags::POLLIN,
|
||||
SelectKind::Write => PollFlags::POLLOUT,
|
||||
SelectKind::Connect => PollFlags::POLLOUT | PollFlags::POLLERR,
|
||||
};
|
||||
let mut pollfd = [PollFd::new(fd, events)];
|
||||
let timeout = match interval {
|
||||
Some(d) => d.as_millis() as _,
|
||||
None => -1,
|
||||
};
|
||||
let ret = unsafe { libc::poll(&mut pollfd, 1, timeout) };
|
||||
if ret < 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(ret == 0)
|
||||
}
|
||||
let ret = poll(&mut pollfd, timeout)?;
|
||||
Ok(ret == 0)
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
|
||||
@@ -26,7 +26,9 @@ mod _ssl {
|
||||
use crate::{
|
||||
common::{
|
||||
ascii,
|
||||
lock::{PyMutex, PyRwLock, PyRwLockWriteGuard},
|
||||
lock::{
|
||||
PyMappedRwLockReadGuard, PyMutex, PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard,
|
||||
},
|
||||
},
|
||||
socket::{self, PySocket},
|
||||
vm::{
|
||||
@@ -504,12 +506,8 @@ mod _ssl {
|
||||
fn builder(&self) -> PyRwLockWriteGuard<'_, SslContextBuilder> {
|
||||
self.ctx.write()
|
||||
}
|
||||
fn exec_ctx<F, R>(&self, func: F) -> R
|
||||
where
|
||||
F: Fn(&ssl::SslContextRef) -> R,
|
||||
{
|
||||
let c = self.ctx.read();
|
||||
func(builder_as_ctx(&c))
|
||||
fn ctx(&self) -> PyMappedRwLockReadGuard<'_, ssl::SslContextRef> {
|
||||
PyRwLockReadGuard::map(self.ctx.read(), builder_as_ctx)
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
@@ -554,7 +552,7 @@ mod _ssl {
|
||||
}
|
||||
#[pygetset]
|
||||
fn verify_mode(&self) -> i32 {
|
||||
let mode = self.exec_ctx(|ctx| ctx.verify_mode());
|
||||
let mode = self.ctx().verify_mode();
|
||||
if mode == SslVerifyMode::NONE {
|
||||
CertRequirements::None.into()
|
||||
} else if mode == SslVerifyMode::PEER {
|
||||
@@ -703,16 +701,15 @@ mod _ssl {
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<Vec<PyObjectRef>> {
|
||||
let binary_form = binary_form.unwrap_or(false);
|
||||
self.exec_ctx(|ctx| {
|
||||
let certs = ctx
|
||||
.cert_store()
|
||||
.objects()
|
||||
.iter()
|
||||
.filter_map(|obj| obj.x509())
|
||||
.map(|cert| cert_to_py(vm, cert, binary_form))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
Ok(certs)
|
||||
})
|
||||
let certs = self
|
||||
.ctx()
|
||||
.cert_store()
|
||||
.objects()
|
||||
.iter()
|
||||
.filter_map(|obj| obj.x509())
|
||||
.map(|cert| cert_to_py(vm, cert, binary_form))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
Ok(certs)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
@@ -746,9 +743,7 @@ mod _ssl {
|
||||
args: WrapSocketArgs,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PySslSocket> {
|
||||
let mut ssl = zelf
|
||||
.exec_ctx(ssl::Ssl::new)
|
||||
.map_err(|e| convert_openssl_error(vm, e))?;
|
||||
let mut ssl = ssl::Ssl::new(&zelf.ctx()).map_err(|e| convert_openssl_error(vm, e))?;
|
||||
|
||||
let socket_type = if args.server_side {
|
||||
ssl.set_accept_state();
|
||||
|
||||
@@ -1091,13 +1091,9 @@ pub mod module {
|
||||
|
||||
#[pyfunction]
|
||||
fn ttyname(fd: i32, vm: &VirtualMachine) -> PyResult {
|
||||
let name = unsafe { libc::ttyname(fd) };
|
||||
if name.is_null() {
|
||||
Err(errno_err(vm))
|
||||
} else {
|
||||
let name = unsafe { CStr::from_ptr(name) }.to_str().unwrap();
|
||||
Ok(vm.ctx.new_str(name).into())
|
||||
}
|
||||
let name = unistd::ttyname(fd).map_err(|e| e.into_pyexception(vm))?;
|
||||
let name = name.into_os_string().into_string().unwrap();
|
||||
Ok(vm.ctx.new_str(name).into())
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
@@ -1129,30 +1125,24 @@ pub mod module {
|
||||
#[cfg(any(target_os = "android", target_os = "linux", target_os = "openbsd"))]
|
||||
#[pyfunction]
|
||||
fn getresuid(vm: &VirtualMachine) -> PyResult<(u32, u32, u32)> {
|
||||
let mut ruid = 0;
|
||||
let mut euid = 0;
|
||||
let mut suid = 0;
|
||||
let ret = unsafe { libc::getresuid(&mut ruid, &mut euid, &mut suid) };
|
||||
if ret == 0 {
|
||||
Ok((ruid, euid, suid))
|
||||
} else {
|
||||
Err(errno_err(vm))
|
||||
}
|
||||
let ret = unistd::getresuid().map_err(|e| e.into_pyexception(vm))?;
|
||||
Ok((
|
||||
ret.real.as_raw(),
|
||||
ret.effective.as_raw(),
|
||||
ret.saved.as_raw(),
|
||||
))
|
||||
}
|
||||
|
||||
// cfg from nix
|
||||
#[cfg(any(target_os = "android", target_os = "linux", target_os = "openbsd"))]
|
||||
#[pyfunction]
|
||||
fn getresgid(vm: &VirtualMachine) -> PyResult<(u32, u32, u32)> {
|
||||
let mut rgid = 0;
|
||||
let mut egid = 0;
|
||||
let mut sgid = 0;
|
||||
let ret = unsafe { libc::getresgid(&mut rgid, &mut egid, &mut sgid) };
|
||||
if ret == 0 {
|
||||
Ok((rgid, egid, sgid))
|
||||
} else {
|
||||
Err(errno_err(vm))
|
||||
}
|
||||
let ret = unistd::getresgid().map_err(|e| e.into_pyexception(vm))?;
|
||||
Ok((
|
||||
ret.real.as_raw(),
|
||||
ret.effective.as_raw(),
|
||||
ret.saved.as_raw(),
|
||||
))
|
||||
}
|
||||
|
||||
// cfg from nix
|
||||
|
||||
@@ -389,11 +389,11 @@ mod unix {
|
||||
use super::{SEC_TO_NS, US_TO_NS};
|
||||
#[cfg_attr(target_os = "macos", allow(unused_imports))]
|
||||
use crate::{
|
||||
builtins::{try_bigint_to_f64, PyFloat, PyIntRef, PyNamespace, PyStrRef},
|
||||
function::Either,
|
||||
stdlib::os,
|
||||
PyRef, PyResult, VirtualMachine,
|
||||
builtins::{PyNamespace, PyStrRef},
|
||||
convert::IntoPyException,
|
||||
PyObject, PyRef, PyResult, TryFromBorrowedObject, VirtualMachine,
|
||||
};
|
||||
use nix::{sys::time::TimeSpec, time::ClockId};
|
||||
use std::time::Duration;
|
||||
|
||||
#[cfg(target_os = "solaris")]
|
||||
@@ -425,83 +425,62 @@ mod unix {
|
||||
#[pyattr]
|
||||
use libc::{CLOCK_PROF, CLOCK_UPTIME};
|
||||
|
||||
fn get_clock_time(clk_id: PyIntRef, vm: &VirtualMachine) -> PyResult<Duration> {
|
||||
let mut timespec = std::mem::MaybeUninit::uninit();
|
||||
let ts: libc::timespec = unsafe {
|
||||
if libc::clock_gettime(clk_id.try_to_primitive(vm)?, timespec.as_mut_ptr()) == -1 {
|
||||
return Err(os::errno_err(vm));
|
||||
}
|
||||
timespec.assume_init()
|
||||
};
|
||||
Ok(Duration::new(ts.tv_sec as u64, ts.tv_nsec as u32))
|
||||
impl TryFromBorrowedObject for ClockId {
|
||||
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self> {
|
||||
obj.try_to_value(vm).map(ClockId::from_raw)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_clock_time(clk_id: ClockId, vm: &VirtualMachine) -> PyResult<Duration> {
|
||||
let ts = nix::time::clock_gettime(clk_id).map_err(|e| e.into_pyexception(vm))?;
|
||||
Ok(ts.into())
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn clock_gettime(clk_id: PyIntRef, vm: &VirtualMachine) -> PyResult<f64> {
|
||||
fn clock_gettime(clk_id: ClockId, vm: &VirtualMachine) -> PyResult<f64> {
|
||||
get_clock_time(clk_id, vm).map(|d| d.as_secs_f64())
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn clock_gettime_ns(clk_id: PyIntRef, vm: &VirtualMachine) -> PyResult<u128> {
|
||||
fn clock_gettime_ns(clk_id: ClockId, vm: &VirtualMachine) -> PyResult<u128> {
|
||||
get_clock_time(clk_id, vm).map(|d| d.as_nanos())
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[pyfunction]
|
||||
fn clock_getres(clk_id: PyIntRef, vm: &VirtualMachine) -> PyResult<f64> {
|
||||
let mut timespec = std::mem::MaybeUninit::uninit();
|
||||
let ts: libc::timespec = unsafe {
|
||||
if libc::clock_getres(clk_id.try_to_primitive(vm)?, timespec.as_mut_ptr()) == -1 {
|
||||
return Err(os::errno_err(vm));
|
||||
}
|
||||
timespec.assume_init()
|
||||
};
|
||||
Ok(Duration::new(ts.tv_sec as u64, ts.tv_nsec as u32).as_secs_f64())
|
||||
fn clock_getres(clk_id: ClockId, vm: &VirtualMachine) -> PyResult<f64> {
|
||||
let ts = nix::time::clock_getres(clk_id).map_err(|e| e.into_pyexception(vm))?;
|
||||
Ok(Duration::from(ts).as_secs_f64())
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[cfg(any(not(target_vendor = "apple"), target_os = "macos"))]
|
||||
fn set_clock_time(
|
||||
clk_id: PyIntRef,
|
||||
timespec: libc::timespec,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
let res = unsafe { libc::clock_settime(clk_id.try_to_primitive(vm)?, ×pec) };
|
||||
if res == -1 {
|
||||
return Err(os::errno_err(vm));
|
||||
}
|
||||
Ok(())
|
||||
#[cfg(not(target_vendor = "apple"))]
|
||||
fn set_clock_time(clk_id: ClockId, timespec: TimeSpec, vm: &VirtualMachine) -> PyResult<()> {
|
||||
nix::time::clock_settime(clk_id, timespec).map_err(|e| e.into_pyexception(vm))
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[cfg(target_os = "macos")]
|
||||
fn set_clock_time(clk_id: ClockId, timespec: TimeSpec, vm: &VirtualMachine) -> PyResult<()> {
|
||||
// idk why nix disables clock_settime on macos
|
||||
let ret = unsafe { libc::clock_settime(clk_id.as_raw(), timespec.as_ref()) };
|
||||
nix::Error::result(ret)
|
||||
.map(drop)
|
||||
.map_err(|e| e.into_pyexception(vm))
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[cfg(any(not(target_vendor = "apple"), target_os = "macos"))]
|
||||
#[pyfunction]
|
||||
fn clock_settime(
|
||||
clk_id: PyIntRef,
|
||||
time: Either<PyRef<PyFloat>, PyIntRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
let time = match time {
|
||||
Either::A(f) => f.to_f64(),
|
||||
Either::B(z) => try_bigint_to_f64(z.as_bigint(), vm)?,
|
||||
};
|
||||
let nanos = time.fract() * (SEC_TO_NS as f64);
|
||||
let ts = libc::timespec {
|
||||
tv_sec: time.floor() as libc::time_t,
|
||||
tv_nsec: nanos as _,
|
||||
};
|
||||
set_clock_time(clk_id, ts, vm)
|
||||
fn clock_settime(clk_id: ClockId, time: Duration, vm: &VirtualMachine) -> PyResult<()> {
|
||||
set_clock_time(clk_id, time.into(), vm)
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[cfg(any(not(target_vendor = "apple"), target_os = "macos"))]
|
||||
#[pyfunction]
|
||||
fn clock_settime_ns(clk_id: PyIntRef, time: PyIntRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let time: libc::time_t = time.try_to_primitive(vm)?;
|
||||
let ts = libc::timespec {
|
||||
tv_sec: time / (SEC_TO_NS as libc::time_t),
|
||||
tv_nsec: time.rem_euclid(SEC_TO_NS as libc::time_t) as _,
|
||||
};
|
||||
fn clock_settime_ns(clk_id: ClockId, time: libc::time_t, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let ts = Duration::from_nanos(time as _).into();
|
||||
set_clock_time(clk_id, ts, vm)
|
||||
}
|
||||
|
||||
@@ -522,25 +501,25 @@ mod unix {
|
||||
false,
|
||||
"time.clock_gettime(CLOCK_MONOTONIC)",
|
||||
true,
|
||||
clock_getres(vm.ctx.new_int(CLOCK_MONOTONIC), vm)?,
|
||||
clock_getres(ClockId::CLOCK_MONOTONIC, vm)?,
|
||||
),
|
||||
"process_time" => (
|
||||
false,
|
||||
"time.clock_gettime(CLOCK_PROCESS_CPUTIME_ID)",
|
||||
true,
|
||||
clock_getres(vm.ctx.new_int(CLOCK_PROCESS_CPUTIME_ID), vm)?,
|
||||
clock_getres(ClockId::CLOCK_PROCESS_CPUTIME_ID, vm)?,
|
||||
),
|
||||
"thread_time" => (
|
||||
false,
|
||||
"time.clock_gettime(CLOCK_THREAD_CPUTIME_ID)",
|
||||
true,
|
||||
clock_getres(vm.ctx.new_int(CLOCK_THREAD_CPUTIME_ID), vm)?,
|
||||
clock_getres(ClockId::CLOCK_THREAD_CPUTIME_ID, vm)?,
|
||||
),
|
||||
"time" => (
|
||||
true,
|
||||
"time.clock_gettime(CLOCK_REALTIME)",
|
||||
false,
|
||||
clock_getres(vm.ctx.new_int(CLOCK_REALTIME), vm)?,
|
||||
clock_getres(ClockId::CLOCK_REALTIME, vm)?,
|
||||
),
|
||||
_ => return Err(vm.new_value_error("unknown clock".to_owned())),
|
||||
};
|
||||
@@ -568,22 +547,19 @@ mod unix {
|
||||
}
|
||||
|
||||
pub(super) fn get_monotonic_time(vm: &VirtualMachine) -> PyResult<Duration> {
|
||||
get_clock_time(vm.ctx.new_int(CLOCK_MONOTONIC), vm)
|
||||
get_clock_time(ClockId::CLOCK_MONOTONIC, vm)
|
||||
}
|
||||
|
||||
pub(super) fn get_perf_time(vm: &VirtualMachine) -> PyResult<Duration> {
|
||||
get_clock_time(vm.ctx.new_int(CLOCK_MONOTONIC), vm)
|
||||
get_clock_time(ClockId::CLOCK_MONOTONIC, vm)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn sleep(dur: Duration, vm: &VirtualMachine) -> PyResult<()> {
|
||||
// this is basically std::thread::sleep, but that catches interrupts and we don't want to;
|
||||
|
||||
let mut ts = libc::timespec {
|
||||
tv_sec: std::cmp::min(libc::time_t::max_value() as u64, dur.as_secs()) as libc::time_t,
|
||||
tv_nsec: dur.subsec_nanos() as _,
|
||||
};
|
||||
let res = unsafe { libc::nanosleep(&ts, &mut ts) };
|
||||
let ts = TimeSpec::from(dur);
|
||||
let res = unsafe { libc::nanosleep(ts.as_ref(), std::ptr::null_mut()) };
|
||||
let interrupted = res == -1 && nix::errno::errno() == libc::EINTR;
|
||||
|
||||
if interrupted {
|
||||
@@ -600,14 +576,7 @@ mod unix {
|
||||
target_os = "redox"
|
||||
)))]
|
||||
pub(super) fn get_thread_time(vm: &VirtualMachine) -> PyResult<Duration> {
|
||||
let time: libc::timespec = unsafe {
|
||||
let mut time = std::mem::MaybeUninit::uninit();
|
||||
if libc::clock_gettime(CLOCK_THREAD_CPUTIME_ID, time.as_mut_ptr()) == -1 {
|
||||
return Err(vm.new_os_error("Failed to get clock time".to_owned()));
|
||||
}
|
||||
time.assume_init()
|
||||
};
|
||||
Ok(Duration::new(time.tv_sec as u64, time.tv_nsec as u32))
|
||||
get_clock_time(ClockId::CLOCK_THREAD_CPUTIME_ID, vm)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "solaris")]
|
||||
@@ -622,14 +591,7 @@ mod unix {
|
||||
target_os = "openbsd",
|
||||
)))]
|
||||
pub(super) fn get_process_time(vm: &VirtualMachine) -> PyResult<Duration> {
|
||||
let time: libc::timespec = unsafe {
|
||||
let mut time = std::mem::MaybeUninit::uninit();
|
||||
if libc::clock_gettime(CLOCK_PROCESS_CPUTIME_ID, time.as_mut_ptr()) == -1 {
|
||||
return Err(vm.new_os_error("Failed to get clock time".to_owned()));
|
||||
}
|
||||
time.assume_init()
|
||||
};
|
||||
Ok(Duration::new(time.tv_sec as u64, time.tv_nsec as u32))
|
||||
get_clock_time(ClockId::CLOCK_PROCESS_CPUTIME_ID, vm)
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
@@ -639,6 +601,7 @@ mod unix {
|
||||
target_os = "openbsd",
|
||||
))]
|
||||
pub(super) fn get_process_time(vm: &VirtualMachine) -> PyResult<Duration> {
|
||||
use nix::sys::resource::{getrusage, UsageWho};
|
||||
fn from_timeval(tv: libc::timeval, vm: &VirtualMachine) -> PyResult<i64> {
|
||||
(|tv: libc::timeval| {
|
||||
let t = tv.tv_sec.checked_mul(SEC_TO_NS)?;
|
||||
@@ -649,15 +612,9 @@ mod unix {
|
||||
vm.new_overflow_error("timestamp too large to convert to i64".to_owned())
|
||||
})
|
||||
}
|
||||
let ru: libc::rusage = unsafe {
|
||||
let mut ru = std::mem::MaybeUninit::uninit();
|
||||
if libc::getrusage(libc::RUSAGE_SELF, ru.as_mut_ptr()) == -1 {
|
||||
return Err(vm.new_os_error("Failed to get clock time".to_owned()));
|
||||
}
|
||||
ru.assume_init()
|
||||
};
|
||||
let utime = from_timeval(ru.ru_utime, vm)?;
|
||||
let stime = from_timeval(ru.ru_stime, vm)?;
|
||||
let ru = getrusage(UsageWho::RUSAGE_SELF).map_err(|e| e.into_pyexception(vm))?;
|
||||
let utime = from_timeval(ru.user_time().into(), vm)?;
|
||||
let stime = from_timeval(ru.system_time().into(), vm)?;
|
||||
|
||||
Ok(Duration::from_nanos((utime + stime) as u64))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user