rework SchedParam

This commit is contained in:
Jeong, YunWon committed 2026-02-03 22:10:31 +09:00
1 parent c0f3a09c2b
commit 674d7dbb3a
3 files changed
+173 -213

No files matched your search

+4 -6
View File
@@ -2206,9 +2206,9 @@ mod _socket {
Some(t) => {
let f = t.into_float();
if f.is_nan() {
return Err(vm.new_value_error(
"Invalid value NaN (not a number)".to_owned(),
));
return Err(
vm.new_value_error("Invalid value NaN (not a number)".to_owned())
);
}
if f < 0.0 || !f.is_finite() {
return Err(vm.new_value_error("Timeout value out of range".to_owned()));
@@ -3388,9 +3388,7 @@ mod _socket {
Some(t) => {
let f = t.into_float();
if f.is_nan() {
return Err(vm.new_value_error(
"Invalid value NaN (not a number)".to_owned(),
));
return Err(vm.new_value_error("Invalid value NaN (not a number)".to_owned()));
}
if f < 0.0 || !f.is_finite() {
return Err(vm.new_value_error("Timeout value out of range".to_owned()));
+1 -3
View File
@@ -127,9 +127,7 @@ impl TryFromObject for core::time::Duration {
if let Some(float) = obj.downcast_ref::<PyFloat>() {
let f = float.to_f64();
if f.is_nan() {
return Err(
vm.new_value_error("Invalid value NaN (not a number)".to_owned())
);
return Err(vm.new_value_error("Invalid value NaN (not a number)".to_owned()));
}
if f < 0.0 {
return Err(vm.new_value_error("negative duration".to_owned()));
+168 -204
View File
@@ -15,11 +15,20 @@ pub fn set_inheritable(fd: BorrowedFd<'_>, inheritable: bool) -> nix::Result<()>
Ok(())
}
#[pymodule(name = "posix", with(super::os::_os))]
#[pymodule(name = "posix", with(
super::os::_os,
#[cfg(any(
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd",
target_os = "android"
))]
posix_sched
))]
pub mod module {
use crate::{
AsObject, Py, PyObjectRef, PyPayload, PyResult, VirtualMachine,
builtins::{PyDictRef, PyInt, PyListRef, PyStr, PyTupleRef, PyType},
AsObject, Py, PyObjectRef, PyResult, VirtualMachine,
builtins::{PyDictRef, PyInt, PyListRef, PyStr, PyTupleRef},
convert::{IntoPyException, ToPyObject, TryFromObject},
exceptions::OSErrorBuilder,
function::{Either, KwArgs, OptionalArg},
@@ -28,7 +37,6 @@ pub mod module {
_os, DirFd, FollowSymlinks, SupportFunc, TargetIsDirectory, fs_metadata,
warn_if_bool_fd,
},
types::{Constructor, Representable},
};
#[cfg(any(
target_os = "android",
@@ -889,206 +897,6 @@ pub mod module {
nix::sched::sched_yield().map_err(|e| e.into_pyexception(vm))
}
#[pyattr]
#[pyclass(name = "sched_param")]
#[derive(Debug, PyPayload)]
struct SchedParam {
sched_priority: PyObjectRef,
}
impl TryFromObject for SchedParam {
fn try_from_object(_vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
Ok(Self {
sched_priority: obj,
})
}
}
#[pyclass(with(Constructor, Representable))]
impl SchedParam {
#[pygetset]
fn sched_priority(&self, vm: &VirtualMachine) -> PyObjectRef {
self.sched_priority.clone().to_pyobject(vm)
}
#[pymethod]
fn __reduce__(zelf: crate::PyRef<Self>, vm: &VirtualMachine) -> PyTupleRef {
vm.new_tuple((zelf.class().to_owned(), (zelf.sched_priority.clone(),)))
}
#[pymethod]
fn __replace__(
zelf: crate::PyRef<Self>,
args: crate::function::FuncArgs,
vm: &VirtualMachine,
) -> PyResult<Self> {
if !args.args.is_empty() {
return Err(
vm.new_type_error("__replace__() takes no positional arguments".to_owned())
);
}
let sched_priority = match args.kwargs.get("sched_priority") {
Some(v) => v.clone(),
None => zelf.sched_priority.clone(),
};
// Check for unexpected keyword arguments
for key in args.kwargs.keys() {
if key.as_str() != "sched_priority" {
return Err(vm.new_type_error(format!(
"__replace__() got an unexpected keyword argument '{key}'"
)));
}
}
Ok(Self { sched_priority })
}
#[cfg(any(
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd",
target_os = "android"
))]
#[cfg(not(target_env = "musl"))]
fn try_to_libc(&self, vm: &VirtualMachine) -> PyResult<libc::sched_param> {
use crate::AsObject;
let priority_class = self.sched_priority.class();
let priority_type = priority_class.name();
let priority = self.sched_priority.clone();
let value = priority.downcast::<PyInt>().map_err(|_| {
vm.new_type_error(format!("an integer is required (got type {priority_type})"))
})?;
let sched_priority = value.try_to_primitive(vm)?;
Ok(libc::sched_param { sched_priority })
}
}
#[derive(FromArgs)]
pub struct SchedParamArg {
sched_priority: PyObjectRef,
}
impl Constructor for SchedParam {
type Args = SchedParamArg;
fn py_new(_cls: &Py<PyType>, arg: Self::Args, _vm: &VirtualMachine) -> PyResult<Self> {
Ok(Self {
sched_priority: arg.sched_priority,
})
}
}
impl Representable for SchedParam {
#[inline]
fn repr_str(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<String> {
let sched_priority_repr = zelf.sched_priority.repr(vm)?;
Ok(format!(
"posix.sched_param(sched_priority = {})",
sched_priority_repr.as_str()
))
}
}
#[cfg(any(
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd",
target_os = "android"
))]
#[pyfunction]
fn sched_getscheduler(pid: libc::pid_t, vm: &VirtualMachine) -> PyResult<i32> {
let policy = unsafe { libc::sched_getscheduler(pid) };
if policy == -1 {
Err(vm.new_last_errno_error())
} else {
Ok(policy)
}
}
#[cfg(any(
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd",
target_os = "android"
))]
#[derive(FromArgs)]
struct SchedSetschedulerArgs {
#[pyarg(positional)]
pid: i32,
#[pyarg(positional)]
policy: i32,
#[pyarg(positional)]
sched_param_obj: crate::PyRef<SchedParam>,
}
#[cfg(any(
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd",
target_os = "android"
))]
#[cfg(not(target_env = "musl"))]
#[pyfunction]
fn sched_setscheduler(args: SchedSetschedulerArgs, vm: &VirtualMachine) -> PyResult<i32> {
let libc_sched_param = args.sched_param_obj.try_to_libc(vm)?;
let policy = unsafe { libc::sched_setscheduler(args.pid, args.policy, &libc_sched_param) };
if policy == -1 {
Err(vm.new_last_errno_error())
} else {
Ok(policy)
}
}
#[cfg(any(
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd",
target_os = "android"
))]
#[pyfunction]
fn sched_getparam(pid: libc::pid_t, vm: &VirtualMachine) -> PyResult<SchedParam> {
let param = unsafe {
let mut param = core::mem::MaybeUninit::uninit();
if -1 == libc::sched_getparam(pid, param.as_mut_ptr()) {
return Err(vm.new_last_errno_error());
}
param.assume_init()
};
Ok(SchedParam {
sched_priority: param.sched_priority.to_pyobject(vm),
})
}
#[cfg(any(
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd",
target_os = "android"
))]
#[derive(FromArgs)]
struct SchedSetParamArgs {
#[pyarg(positional)]
pid: i32,
#[pyarg(positional)]
sched_param_obj: crate::PyRef<SchedParam>,
}
#[cfg(any(
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd",
target_os = "android"
))]
#[cfg(not(target_env = "musl"))]
#[pyfunction]
fn sched_setparam(args: SchedSetParamArgs, vm: &VirtualMachine) -> PyResult<i32> {
let libc_sched_param = args.sched_param_obj.try_to_libc(vm)?;
let ret = unsafe { libc::sched_setparam(args.pid, &libc_sched_param) };
if ret == -1 {
Err(vm.new_last_errno_error())
} else {
Ok(ret)
}
}
#[pyfunction]
fn get_inheritable(fd: BorrowedFd<'_>, vm: &VirtualMachine) -> PyResult<bool> {
let flags = fcntl::fcntl(fd, fcntl::FcntlArg::F_GETFD);
@@ -2699,3 +2507,159 @@ pub mod module {
Ok(())
}
}
#[cfg(any(
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd",
target_os = "android"
))]
#[pymodule(sub)]
mod posix_sched {
use crate::{
AsObject, Py, PyObjectRef, PyResult, VirtualMachine,
builtins::{PyInt, PyTupleRef},
convert::ToPyObject,
function::FuncArgs,
types::PyStructSequence,
};
#[derive(FromArgs)]
struct SchedParamArgs {
#[pyarg(any)]
sched_priority: PyObjectRef,
}
#[pystruct_sequence_data]
struct SchedParamData {
pub sched_priority: PyObjectRef,
}
#[pyattr]
#[pystruct_sequence(name = "sched_param", module = "posix", data = "SchedParamData")]
struct PySchedParam;
#[pyclass(with(PyStructSequence))]
impl PySchedParam {
#[pyslot]
fn slot_new(
cls: crate::builtins::PyTypeRef,
args: FuncArgs,
vm: &VirtualMachine,
) -> PyResult {
use crate::PyPayload;
let SchedParamArgs { sched_priority } = args.bind(vm)?;
let items = vec![sched_priority];
crate::builtins::PyTuple::new_unchecked(items.into_boxed_slice())
.into_ref_with_type(vm, cls)
.map(Into::into)
}
#[extend_class]
fn extend_pyclass(ctx: &crate::vm::Context, class: &'static Py<crate::builtins::PyType>) {
// Override __reduce__ to return (type, (sched_priority,))
// instead of the generic structseq (type, ((sched_priority,),)).
// The trait's extend_class checks contains_key before setting default.
const SCHED_PARAM_REDUCE: crate::function::PyMethodDef =
crate::function::PyMethodDef::new_const(
"__reduce__",
|zelf: crate::PyRef<crate::builtins::PyTuple>,
vm: &VirtualMachine|
-> PyTupleRef {
vm.new_tuple((zelf.class().to_owned(), (zelf[0].clone(),)))
},
crate::function::PyMethodFlags::METHOD,
None,
);
class.set_attr(
ctx.intern_str("__reduce__"),
SCHED_PARAM_REDUCE.to_proper_method(class, ctx),
);
}
}
#[cfg(not(target_env = "musl"))]
fn convert_sched_param(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult<libc::sched_param> {
use crate::{builtins::PyTuple, class::StaticType};
if !obj.fast_isinstance(PySchedParam::static_type()) {
return Err(vm.new_type_error("must have a sched_param object".to_owned()));
}
let tuple = obj.downcast_ref::<PyTuple>().unwrap();
let priority = tuple[0].clone();
let priority_type = priority.class().name().to_string();
let value = priority.downcast::<PyInt>().map_err(|_| {
vm.new_type_error(format!("an integer is required (got type {priority_type})"))
})?;
let sched_priority = value.try_to_primitive(vm)?;
Ok(libc::sched_param { sched_priority })
}
#[pyfunction]
fn sched_getscheduler(pid: libc::pid_t, vm: &VirtualMachine) -> PyResult<i32> {
let policy = unsafe { libc::sched_getscheduler(pid) };
if policy == -1 {
Err(vm.new_last_errno_error())
} else {
Ok(policy)
}
}
#[derive(FromArgs)]
struct SchedSetschedulerArgs {
#[pyarg(positional)]
pid: i32,
#[pyarg(positional)]
policy: i32,
#[pyarg(positional)]
sched_param: PyObjectRef,
}
#[cfg(not(target_env = "musl"))]
#[pyfunction]
fn sched_setscheduler(args: SchedSetschedulerArgs, vm: &VirtualMachine) -> PyResult<i32> {
let libc_sched_param = convert_sched_param(&args.sched_param, vm)?;
let policy = unsafe { libc::sched_setscheduler(args.pid, args.policy, &libc_sched_param) };
if policy == -1 {
Err(vm.new_last_errno_error())
} else {
Ok(policy)
}
}
#[pyfunction]
fn sched_getparam(pid: libc::pid_t, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
let param = unsafe {
let mut param = core::mem::MaybeUninit::uninit();
if -1 == libc::sched_getparam(pid, param.as_mut_ptr()) {
return Err(vm.new_last_errno_error());
}
param.assume_init()
};
Ok(PySchedParam::from_data(
SchedParamData {
sched_priority: param.sched_priority.to_pyobject(vm),
},
vm,
))
}
#[derive(FromArgs)]
struct SchedSetParamArgs {
#[pyarg(positional)]
pid: i32,
#[pyarg(positional)]
sched_param: PyObjectRef,
}
#[cfg(not(target_env = "musl"))]
#[pyfunction]
fn sched_setparam(args: SchedSetParamArgs, vm: &VirtualMachine) -> PyResult<i32> {
let libc_sched_param = convert_sched_param(&args.sched_param, vm)?;
let ret = unsafe { libc::sched_setparam(args.pid, &libc_sched_param) };
if ret == -1 {
Err(vm.new_last_errno_error())
} else {
Ok(ret)
}
}
}