Skip to content
Draft
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
3 changes: 3 additions & 0 deletions header/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ pub mod syscalls {
MqTimedReceive,
MqGetSetAttr,
Ioctl,
SchedGetPriorityMax,
SchedGetPriorityMin,
SchedRrGetInterval,
LastNR,
}
}
Expand Down
45 changes: 31 additions & 14 deletions kernel/src/scheduler/global_scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,23 +174,40 @@ pub fn remove_from_ready_queue(t: &ThreadNode) -> bool {
remove_from_ready_queue_inner(&mut tbl, t)
}

pub fn update_ready_thread_priority(
t: &ThreadNode,
new_priority: ThreadPriority,
) -> Result<(), Uint> {
pub fn update_thread_priority_safe(t: &ThreadNode, newprio: ThreadPriority) {
let mut tbl = unsafe { READY_TABLE.assume_init_ref().irqsave_lock() };
if !remove_from_ready_queue_inner(&mut tbl, t) {
let state = t.state();
return Err(state);

let mut removed_from_ready = false;
let priority = t.priority();
if priority <= MAX_THREAD_PRIORITY {
let q = &mut tbl.tables[priority as usize];
let removed = q.remove_if(|e| ThreadNode::as_ptr(t) == e as *const _);
if removed.is_some() {
removed_from_ready = true;
if q.is_empty() {
tbl.clear_active_queue(priority as u32);
}
}
}

let mut thread_guard = t.lock();
thread_guard.set_origin_priority(new_priority);
thread_guard.set_priority(new_priority);
drop(thread_guard);
if removed_from_ready {
// Enqueued: update fields then requeue under the same ready-table lock.
{
let mut g = t.lock();
g.set_origin_priority(newprio);
g.set_priority(newprio);
}
let _ = queue_ready_thread_inner(&mut tbl, t.clone());
return;
}

if queue_ready_thread_inner(&mut tbl, t.clone()) {
return Ok(());
// Not enqueued: drop runqueue lock and update fields only.
drop(tbl);
let mut g = t.lock();
// if retired, do not change priority
if g.state() == thread::RETIRED {
return;
}
Err(thread::RUNNING)
g.set_origin_priority(newprio);
g.set_priority(newprio);
}
73 changes: 47 additions & 26 deletions kernel/src/syscall_handlers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ use libc::{
sigset_t, size_t, sockaddr, socklen_t, timespec, EBUSY, EINVAL, ESRCH,
};

pub const SCHED_RR: c_int = 1;
#[cfg(not(enable_vfs))]
mod vfs_syscalls {
use super::*;
Expand Down Expand Up @@ -334,45 +335,29 @@ get_sched_param(tid: usize) -> c_long {
let Some(target) = target else {
return -(ESRCH as c_long);
};
target.priority() as c_long
(config::MAX_THREAD_PRIORITY - (target.priority() as crate::types::ThreadPriority)) as c_long
});

define_syscall_handler!(
set_sched_param(tid: usize, prio: c_int) -> c_long {
if prio < 0 || (prio as u32) > (config::MAX_THREAD_PRIORITY as u32) {
return -(EINVAL as c_long);
}
let p = prio as crate::types::ThreadPriority;
let mut was_ready = false;
let target = thread::GlobalQueueVisitor::find_if(|t| {
if thread::Thread::id(t) == tid {
was_ready = t.state() == thread::READY;
if !was_ready {
let mut w = t.lock();
w.set_origin_priority(p);
w.set_priority(p);
}
true
} else {
false
}
});
// convert posix priority to kernel priority
let p = config::MAX_THREAD_PRIORITY - (prio as crate::types::ThreadPriority);
let target = thread::GlobalQueueVisitor::find_if(|t| thread::Thread::id(t) == tid);

let Some(target) = target else {
return -(ESRCH as c_long);
};

if target.lock().priority() == p {
return 0;
}
let preempt_guard = thread::Thread::try_preempt_me();
let ret = if was_ready {
match scheduler::update_ready_thread_priority(&target, p) {
Ok(()) => 0,
Err(_) => -(EBUSY as c_long),
}
} else {
0
};

scheduler::update_thread_priority_safe(&target, p);
Copy link
Contributor

Choose a reason for hiding this comment

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

do we need to trigger task schedule if thread prio is changed

drop(preempt_guard);
ret
0
});

define_syscall_handler!(
Expand Down Expand Up @@ -505,6 +490,39 @@ define_syscall_handler!(sched_yield() -> c_long {
scheduler::yield_me();
0
});

define_syscall_handler!(sched_get_priority_max(policy: c_int) -> c_long {
// Only SCHED_RR is supported.
if policy != SCHED_RR {
return -(libc::EINVAL as c_long);
}
config::MAX_THREAD_PRIORITY as c_long
});

define_syscall_handler!(sched_get_priority_min(policy: c_int) -> c_long {
// Only SCHED_RR is supported.
if policy != SCHED_RR {
return -(libc::EINVAL as c_long);
}
0
});

define_syscall_handler!(sched_rr_get_interval(pid: c_int, interval: *mut timespec) -> c_long {
let _ = pid;
if interval.is_null() {
return -(libc::EINVAL as c_long);
}

unsafe {
(*interval).tv_sec = 0;
let ns: i64 = (time::tick_to_millisecond(blueos_kconfig::CONFIG_ROBIN_SLICE as usize)
as i64)
.saturating_mul(1_000_000);
let clamped: i64 = core::cmp::min(ns, 999_999_999);
(*interval).tv_nsec = clamped as c_int;
}
0
});
define_syscall_handler!(
rmdir(path: *const c_char) -> c_int {
vfs_syscalls::rmdir(path)
Expand Down Expand Up @@ -896,6 +914,9 @@ syscall_table! {
(MqTimedReceive, mq_timedreceive),
(MqGetSetAttr, mq_getsetattr),
(Ioctl, ioctl),
(SchedGetPriorityMax, sched_get_priority_max),
(SchedGetPriorityMin, sched_get_priority_min),
(SchedRrGetInterval, sched_rr_get_interval),
}

#[cfg(not(enable_syscall))]
Expand Down