Skip to content

Commit 51cec4b

Browse files
committed
syscall/process: Implement getpriority/setpriority
1 parent df6da4c commit 51cec4b

4 files changed

Lines changed: 132 additions & 9 deletions

File tree

kernel/src/process/mod.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ use crate::{
1818
task::Task,
1919
},
2020
sched::Scheduler,
21-
uapi,
21+
uapi::{
22+
self,
23+
resource::{PRIO_MAX, PRIO_MIN},
24+
},
2225
util::{
2326
event::Event,
2427
mutex::{Mutex, spin::SpinMutex},
@@ -40,7 +43,7 @@ use alloc::{
4043
};
4144
use core::{
4245
mem,
43-
sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering},
46+
sync::atomic::{AtomicBool, AtomicI8, AtomicU32, AtomicUsize, Ordering},
4447
time::Duration,
4548
};
4649

@@ -59,6 +62,8 @@ pub struct Process {
5962
name: SpinMutex<String>,
6063
/// The parent of this process, or [`None`], if this is the init process.
6164
parent: SpinMutex<Option<Weak<Process>>>,
65+
/// A value between -20 and 19, where -20 is the highest priority and 0 is a neutral priority.
66+
nice: AtomicI8,
6267
/// A list of [`Task`]s associated with this process.
6368
pub threads: SpinMutex<Vec<Arc<Task>>>,
6469
/// The address space for this process.
@@ -137,6 +142,18 @@ impl Process {
137142
self.parent.lock().as_ref().and_then(Weak::upgrade)
138143
}
139144

145+
pub const fn clamp_nice(nice: i32) -> i8 {
146+
nice.clamp(PRIO_MIN as i32, PRIO_MAX as i32 - 1) as i8
147+
}
148+
149+
pub fn set_nice(&self, nice: i32) {
150+
self.nice.store(Self::clamp_nice(nice), Ordering::Relaxed);
151+
}
152+
153+
pub fn get_nice(&self) -> i8 {
154+
self.nice.load(Ordering::Relaxed)
155+
}
156+
140157
pub fn new(name: String, parent: Option<Arc<Self>>) -> EResult<Self> {
141158
Self::new_with_space(name, parent, AddressSpace::new())
142159
}
@@ -188,6 +205,7 @@ impl Process {
188205
stop_unwaited: AtomicBool::new(false),
189206
continue_unwaited: AtomicBool::new(false),
190207
umask: AtomicU32::new(self.umask.load(Ordering::Relaxed)),
208+
nice: AtomicI8::new(self.nice.load(Ordering::Relaxed)),
191209
});
192210

193211
// Create a heap allocated context that we can pass to the entry point.
@@ -273,6 +291,7 @@ impl Process {
273291
stop_unwaited: AtomicBool::new(false),
274292
continue_unwaited: AtomicBool::new(false),
275293
umask: AtomicU32::new(0o022),
294+
nice: AtomicI8::new(0),
276295
})
277296
}
278297

kernel/src/process/task.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,6 @@ pub struct Task {
8080
pub user_stack: AtomicUsize,
8181
/// The amount of time that this task can live on.
8282
pub ticks: usize,
83-
/// A value between -20 and 19, where -20 is the highest priority and 0 is a neutral priority.
84-
pub priority: i8,
8583
/// Used to handle [`UserPtr`] page faults.
8684
pub uar: AtomicPtr<UserAccessRegion>,
8785
/// Per-thread signal state (pending signals and signal mask).
@@ -212,7 +210,6 @@ impl Task {
212210
kernel_stack: KernelStack::new()?,
213211
user_stack: AtomicUsize::new(0),
214212
ticks: 0,
215-
priority: 0,
216213
name: SpinMutex::new(String::new()),
217214
last_cpu: AtomicU32::new(u32::MAX),
218215
sched_cpu: AtomicU32::new(u32::MAX),

kernel/src/syscall/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,8 +297,8 @@ pub(crate) fn dispatch(frame: &mut Context) {
297297
// Scheduling
298298
numbers::SLEEP => system::sleep,
299299
numbers::YIELD => system::sched_yield,
300-
numbers::GETPRIORITY => sys_unimpl!("getpriority", Err(Errno::ENOSYS)),
301-
numbers::SETPRIORITY => sys_unimpl!("setpriority", Err(Errno::ENOSYS)),
300+
numbers::GETPRIORITY => process::getpriority,
301+
numbers::SETPRIORITY => process::setpriority,
302302
numbers::SCHED_GETPARAM => sys_unimpl!("sched_getparam", Err(Errno::ENOSYS)),
303303
numbers::SCHED_SETPARAM => sys_unimpl!("sched_setparam", Err(Errno::ENOSYS)),
304304
numbers::GETENTROPY => system::getentropy,

kernel/src/syscall/process.rs

Lines changed: 109 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@ use crate::{
1010
to_user,
1111
},
1212
sched::Scheduler,
13-
uapi::{self, gid_t, limits::PATH_MAX, pid_t, uid_t},
13+
uapi::{self, gid_t, limits::PATH_MAX, pid_t, resource::*, uid_t},
1414
vfs::{File, file::OpenFlags, inode::Mode},
1515
wrap_syscall,
1616
};
17-
use alloc::{string::String, sync::Arc, vec::Vec};
17+
use alloc::{
18+
string::String,
19+
sync::{Arc, Weak},
20+
vec::Vec,
21+
};
1822

1923
#[wrap_syscall]
2024
pub fn gettid() -> usize {
@@ -361,6 +365,109 @@ pub fn setsid() -> EResult<pid_t> {
361365
Ok(pid)
362366
}
363367

368+
fn parse_processes(which: u32, who: pid_t) -> EResult<Vec<Arc<Process>>> {
369+
let current = Scheduler::get_current().get_process();
370+
371+
if which == PRIO_PROCESS {
372+
let proc = if who == 0 {
373+
current
374+
} else {
375+
let table = crate::process::PROCESS_TABLE.lock();
376+
377+
table
378+
.get(&who)
379+
.cloned()
380+
.ok_or(Errno::ESRCH)?
381+
.upgrade()
382+
.ok_or(Errno::ESRCH)?
383+
};
384+
385+
return Ok(vec![proc]);
386+
}
387+
388+
let table = crate::process::PROCESS_TABLE
389+
.lock()
390+
.values()
391+
.filter_map(Weak::upgrade)
392+
.collect::<Vec<_>>();
393+
394+
let procs = match which {
395+
PRIO_PGRP => {
396+
let pgrp = if who == 0 { *current.pgrp.lock() } else { who };
397+
398+
table
399+
.into_iter()
400+
.filter(|proc| *proc.pgrp.lock() == pgrp)
401+
.collect::<Vec<_>>()
402+
}
403+
404+
PRIO_USER => {
405+
let uid = if who == 0 {
406+
current.identity.lock().user_id
407+
} else {
408+
who as uid_t
409+
};
410+
411+
table
412+
.into_iter()
413+
.filter(|proc| proc.identity.lock().user_id == uid)
414+
.collect::<Vec<_>>()
415+
}
416+
417+
_ => return Err(Errno::EINVAL),
418+
};
419+
420+
if procs.is_empty() {
421+
return Err(Errno::ESRCH);
422+
}
423+
424+
Ok(procs)
425+
}
426+
427+
#[wrap_syscall]
428+
pub fn getpriority(which: u32, who: pid_t) -> EResult<i32> {
429+
Ok(parse_processes(which, who)?
430+
.iter()
431+
.map(|p| p.get_nice() as i32)
432+
.min()
433+
.unwrap())
434+
}
435+
436+
#[wrap_syscall]
437+
pub fn setpriority(which: u32, who: pid_t, prio: i32) -> EResult<()> {
438+
let procs = parse_processes(which, who)?;
439+
440+
let nice = Process::clamp_nice(prio);
441+
442+
let euid = Scheduler::get_current()
443+
.get_process()
444+
.identity
445+
.lock()
446+
.effective_user_id;
447+
448+
let mut last_result = Ok(());
449+
450+
for proc in procs {
451+
let identity = proc.identity.lock();
452+
453+
if euid != 0 && euid != identity.user_id && euid != identity.effective_user_id {
454+
last_result = Err(Errno::EPERM);
455+
continue;
456+
}
457+
458+
let current_nice = proc.get_nice();
459+
460+
if nice < current_nice && euid != 0 {
461+
last_result = Err(Errno::EACCES);
462+
continue;
463+
}
464+
465+
proc.set_nice(nice as i32);
466+
}
467+
468+
last_result
469+
}
470+
364471
pub fn exit(error: usize) -> ! {
365472
Process::exit(State::Exited(error as _));
366473
}

0 commit comments

Comments
 (0)