Skip to content
Closed
80 changes: 76 additions & 4 deletions os/StarryOS/kernel/src/syscall/task/schedule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ use ax_task::{
AxCpuMask, current,
future::{block_on, interruptible, sleep},
};
use bytemuck::{Pod, Zeroable};
use linux_raw_sys::general::{
__kernel_clockid_t, CLOCK_MONOTONIC, CLOCK_REALTIME, PRIO_PGRP, PRIO_PROCESS, PRIO_USER,
SCHED_RR, TIMER_ABSTIME, timespec,
SCHED_BATCH, SCHED_FIFO, SCHED_IDLE, SCHED_NORMAL, SCHED_RR, TIMER_ABSTIME, timespec,
};
use starry_vm::{VmMutPtr, VmPtr, vm_load, vm_write_slice};

Expand All @@ -20,6 +21,12 @@ use crate::{
time::TimeValueLike,
};

#[repr(C)]
#[derive(Copy, Clone, Pod, Zeroable)]
struct SchedParam {
sched_priority: i32,
}

pub fn sys_sched_yield() -> AxResult<isize> {
ax_task::yield_now();
Ok(0)
Expand Down Expand Up @@ -107,7 +114,27 @@ pub fn sys_sched_getaffinity(pid: i32, cpusetsize: usize, user_mask: *mut u8) ->
Ok(mask_bytes.len() as _)
}

pub fn check_sched_permission(pid: i32) -> AxResult<()> {
let caller = current().as_thread().cred();
let task = get_task_by_sched_pid(pid)?;
if task.id() == current().id() {
return Ok(());
}
let target_proc = get_process_data(pid as u32)?;
let target_cred = process_cred(&target_proc)?;
if caller.has_cap_sys_nice()
|| caller.euid == target_cred.uid
|| caller.euid == target_cred.euid
{
Ok(())
} else {
Err(AxError::OperationNotPermitted)
}
}

pub fn sys_sched_setaffinity(pid: i32, cpusetsize: usize, user_mask: *const u8) -> AxResult<isize> {
check_sched_permission(pid)?;
let task = get_task_by_sched_pid(pid)?;
let size = cpusetsize.min(ax_hal::cpu_num().div_ceil(8));
let user_mask = vm_load(user_mask, size)?;
let mut cpu_mask = AxCpuMask::new();
Expand All @@ -121,8 +148,6 @@ pub fn sys_sched_setaffinity(pid: i32, cpusetsize: usize, user_mask: *const u8)
if cpu_mask.is_empty() {
return Err(AxError::InvalidInput);
}

let task = get_task_by_sched_pid(pid)?;
if task.id() == current().id() {
ax_task::set_current_affinity(cpu_mask);
} else {
Expand All @@ -141,14 +166,61 @@ fn get_task_by_sched_pid(pid: i32) -> AxResult<ax_task::AxTaskRef> {
}

pub fn sys_sched_getscheduler(_pid: i32) -> AxResult<isize> {
Ok(SCHED_RR as _)
let task = get_task_by_sched_pid(_pid)?;
Ok(task.sched_policy() as isize)
}

pub fn sys_sched_setscheduler(_pid: i32, _policy: i32, _param: *const ()) -> AxResult<isize> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 建议:sched_setscheduler 未处理 SCHED_RESET_ON_FORK 标志位

Linux 允许在 policy 参数中 OR 上 SCHED_RESET_ON_FORK(0x40000000)标志。当前实现直接将 _policy as u32SCHED_NORMAL 等常量比较,会导致带该标志的合法调用被误判为 EINVAL。

建议在策略校验前先剥离该标志:

const SCHED_RESET_ON_FORK: u32 = 0x40000000;
let reset_on_fork = (policy & SCHED_RESET_ON_FORK) != 0;
let policy = policy & !SCHED_RESET_ON_FORK;

然后在设置任务时存储 reset_on_fork 状态(或在当前阶段先忽略其语义,只做标志剥离以避免 EINVAL 误判)。

Comment thread
04megumi marked this conversation as resolved.
check_sched_permission(_pid)?;
let task = get_task_by_sched_pid(_pid)?;
if _param.is_null() {
return Err(AxError::InvalidInput);
}
let user_param = vm_load::<SchedParam>(_param.cast(), 1)?;
let user_param = user_param[0];
let mut policy = _policy as u32;
const SCHED_RESET_ON_FORK: u32 = 0x40000000;
let _reset_on_fork = (policy & SCHED_RESET_ON_FORK) != 0;
policy &= !SCHED_RESET_ON_FORK;
let prio = user_param.sched_priority;
match policy {
SCHED_NORMAL | SCHED_FIFO | SCHED_RR | SCHED_BATCH | SCHED_IDLE => {}
_ => return Err(AxError::InvalidInput),
}
match policy {
SCHED_NORMAL | SCHED_BATCH | SCHED_IDLE => {
if prio != 0 {
return Err(AxError::InvalidInput);
}
}
SCHED_FIFO | SCHED_RR => {
if !(1..=99).contains(&prio) {
return Err(AxError::InvalidInput);
}
}
_ => unreachable!(),
}
task.set_sched_policy(policy as i32);
task.set_sched_priority(prio);
Ok(0)
}

pub fn sys_sched_getparam(_pid: i32, _param: *mut ()) -> AxResult<isize> {
let task = get_task_by_sched_pid(_pid)?;
if _param.is_null() {
return Err(AxError::InvalidInput);
}
let param = SchedParam {
sched_priority: task.sched_priority(),
};
let ptr = _param as *mut SchedParam;
unsafe {
let bytes = core::slice::from_raw_parts(
&param as *const SchedParam as *const u8,
core::mem::size_of::<SchedParam>(),
);
vm_write_slice(ptr as *mut u8, bytes)?;
Comment thread
04megumi marked this conversation as resolved.
}
Ok(0)
}

Expand Down
28 changes: 28 additions & 0 deletions os/arceos/modules/axtask/src/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ pub struct TaskInner {
/// CPU affinity mask.
cpumask: SpinNoIrq<AxCpuMask>,

/// Scheduling policy of the task.
sched_policy: AtomicI32,

/// Scheduling priority of the task.
sched_priority: AtomicI32,

/// Mark whether the task is in the wait queue.
in_wait_queue: AtomicBool,

Expand Down Expand Up @@ -264,6 +270,26 @@ impl TaskInner {
*self.cpumask.lock() = cpumask
}

#[inline]
pub fn sched_policy(&self) -> i32 {
self.sched_policy.load(Ordering::Acquire)
}

#[inline]
pub fn set_sched_policy(&self, policy: i32) {
self.sched_policy.store(policy, Ordering::Release)
}

#[inline]
pub fn sched_priority(&self) -> i32 {
self.sched_priority.load(Ordering::Acquire)
}

#[inline]
pub fn set_sched_priority(&self, prio: i32) {
self.sched_priority.store(prio, Ordering::Release)
}

/// Polls whether the task has been interrupted.
#[inline]
pub fn poll_interrupt(&self, cx: &Context) -> Poll<()> {
Expand Down Expand Up @@ -324,6 +350,8 @@ impl TaskInner {
state: AtomicU8::new(TaskState::Ready as u8),
// By default, the task is allowed to run on all CPUs.
cpumask: SpinNoIrq::new(crate::api::cpu_mask_full()),
sched_policy: AtomicI32::new(0),
sched_priority: AtomicI32::new(0),
in_wait_queue: AtomicBool::new(false),
#[cfg(feature = "irq")]
timer_ticket_id: AtomicU64::new(0),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.20)
project(test-sched-family C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
add_executable(test-sched-family src/main.c)
target_include_directories(test-sched-family PRIVATE src)
target_compile_options(test-sched-family PRIVATE -Wall -Wextra -Werror)
install(TARGETS test-sched-family RUNTIME DESTINATION usr/bin)
Loading
Loading