Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Lib/test/_test_multiprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -5009,7 +5009,6 @@ def test_finalize(self):
result = [obj for obj in iter(conn.recv, 'STOP')]
self.assertEqual(result, ['a', 'b', 'd10', 'd03', 'd02', 'd01', 'e'])

@unittest.skip("TODO: RUSTPYTHON; SIGSEGV due to dict thread-safety issue under aggressive GC")
@support.requires_resource('cpu')
def test_thread_safety(self):
# bpo-24484: _run_finalizers() should be thread-safe
Expand Down
24 changes: 24 additions & 0 deletions crates/host_env/src/posix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -953,6 +953,30 @@ pub fn waitpid(pid: libc::pid_t, status: &mut i32, opt: i32) -> std::io::Result<
}
}

/// `wait3(2)` is `wait4(-1, ...)`.
pub fn wait3(options: i32) -> std::io::Result<(libc::pid_t, i32, crate::resource::RUsage)> {
wait4(-1, options)
}

/// `wait4(2)`. `rusage` is zeroed when `pid == 0` (WNOHANG, no child ready).
pub fn wait4(
pid: libc::pid_t,
options: i32,
) -> std::io::Result<(libc::pid_t, i32, crate::resource::RUsage)> {
let mut status = 0;
let mut ru = core::mem::MaybeUninit::<libc::rusage>::zeroed();
let res = unsafe { libc::wait4(pid, &mut status, options, ru.as_mut_ptr()) };
if res == -1 {
return Err(std::io::Error::last_os_error());
}
let ru = if res == 0 {
unsafe { core::mem::zeroed() }
} else {
unsafe { ru.assume_init() }
};
Ok((res, status, ru.into()))
}

pub fn kill(pid: i32, sig: i32) -> std::io::Result<()> {
let ret = unsafe { libc::kill(pid, sig) };
if ret == -1 {
Expand Down
59 changes: 59 additions & 0 deletions crates/vm/src/stdlib/posix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1771,6 +1771,65 @@ pub mod module {
waitpid(-1, 0, vm)
}

fn rusage_to_py(
ru: rustpython_host_env::resource::RUsage,
vm: &VirtualMachine,
) -> PyResult<PyObjectRef> {
let resource = vm.import("resource", 0)?;
let struct_rusage = resource.get_attr("struct_rusage", vm)?;
let tv = |t: rustpython_host_env::resource::timeval| {
t.tv_sec as f64 + (t.tv_usec as f64 / 1_000_000.0)
};
let fields = vm.ctx.new_tuple(vec![
vm.ctx.new_float(tv(ru.ru_utime)).into(),
vm.ctx.new_float(tv(ru.ru_stime)).into(),
vm.ctx.new_int(ru.ru_maxrss).into(),
vm.ctx.new_int(ru.ru_ixrss).into(),
vm.ctx.new_int(ru.ru_idrss).into(),
vm.ctx.new_int(ru.ru_isrss).into(),
vm.ctx.new_int(ru.ru_minflt).into(),
vm.ctx.new_int(ru.ru_majflt).into(),
vm.ctx.new_int(ru.ru_nswap).into(),
vm.ctx.new_int(ru.ru_inblock).into(),
vm.ctx.new_int(ru.ru_oublock).into(),
vm.ctx.new_int(ru.ru_msgsnd).into(),
vm.ctx.new_int(ru.ru_msgrcv).into(),
vm.ctx.new_int(ru.ru_nsignals).into(),
vm.ctx.new_int(ru.ru_nvcsw).into(),
vm.ctx.new_int(ru.ru_nivcsw).into(),
]);
struct_rusage.call((fields,), vm)
}

fn wait_with_rusage<F>(vm: &VirtualMachine, wait: F) -> PyResult<PyTupleRef>
where
F: Fn() -> std::io::Result<(libc::pid_t, i32, rustpython_host_env::resource::RUsage)>,
{
loop {
match vm.allow_threads(&wait) {
Err(err) if err.raw_os_error() == Some(libc::EINTR) => {
vm.check_signals()?;
continue;
}
Err(err) => return Err(err.into_pyexception(vm)),
Ok((pid, status, ru)) => {
let rusage = rusage_to_py(ru, vm)?;
return Ok(vm.new_tuple((pid, status, rusage)));
}
}
}
}

#[pyfunction]
fn wait3(options: i32, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
wait_with_rusage(vm, || rustpython_host_env::posix::wait3(options))
}

#[pyfunction]
fn wait4(pid: libc::pid_t, options: i32, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
wait_with_rusage(vm, || rustpython_host_env::posix::wait4(pid, options))
}

#[pyfunction]
fn kill(pid: i32, signal: isize, vm: &VirtualMachine) -> PyResult<()> {
rustpython_host_env::posix::kill(pid, signal as i32).map_err(|err| err.into_pyexception(vm))
Expand Down
Loading