mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-20 23:46:32 +00:00
Implementation of load average calculation and corresponding /proc entry
Moved everything into the kernel side. Add a SchedulerStats trait Use 'fixed' to represent fixed-point numbers Make the loadavg calculation lazy
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
efd49a96e3
commit
4701eaf0cb
41
Cargo.lock
generated
41
Cargo.lock
generated
@ -173,6 +173,7 @@ dependencies = [
|
|||||||
"controlled",
|
"controlled",
|
||||||
"core2",
|
"core2",
|
||||||
"cpio-decoder",
|
"cpio-decoder",
|
||||||
|
"fixed",
|
||||||
"getset",
|
"getset",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
"id-alloc",
|
"id-alloc",
|
||||||
@ -291,6 +292,12 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "az"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit_field"
|
name = "bit_field"
|
||||||
version = "0.10.2"
|
version = "0.10.2"
|
||||||
@ -444,6 +451,12 @@ version = "1.1.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f64009896348fc5af4222e9cf7d7d82a95a256c634ebcf61c53e4ea461422242"
|
checksum = "f64009896348fc5af4222e9cf7d7d82a95a256c634ebcf61c53e4ea461422242"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crunchy"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ctor"
|
name = "ctor"
|
||||||
version = "0.1.25"
|
version = "0.1.25"
|
||||||
@ -606,6 +619,18 @@ version = "0.1.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67"
|
checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fixed"
|
||||||
|
version = "1.28.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85c6e0b89bf864acd20590dbdbad56f69aeb898abfc9443008fd7bd48b2cc85a"
|
||||||
|
dependencies = [
|
||||||
|
"az",
|
||||||
|
"bytemuck",
|
||||||
|
"half",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
@ -670,6 +695,16 @@ version = "0.31.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "half"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crunchy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hash32"
|
name = "hash32"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@ -1576,6 +1611,12 @@ dependencies = [
|
|||||||
name = "typeflags-util"
|
name = "typeflags-util"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uart_16550"
|
name = "uart_16550"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
@ -58,6 +58,9 @@ inherit-methods-macro = { git = "https://github.com/asterinas/inherit-methods-ma
|
|||||||
getset = "0.1.2"
|
getset = "0.1.2"
|
||||||
takeable = "0.2.2"
|
takeable = "0.2.2"
|
||||||
cfg-if = "1.0"
|
cfg-if = "1.0"
|
||||||
|
# Fixed point numbers
|
||||||
|
# TODO: fork this crate to rewrite all the (unnecessary) unsafe usage
|
||||||
|
fixed = "1.28.0"
|
||||||
|
|
||||||
[target.riscv64gc-unknown-none-elf.dependencies]
|
[target.riscv64gc-unknown-none-elf.dependencies]
|
||||||
riscv = { version = "0.11.1", features = ["s-mode"] }
|
riscv = { version = "0.11.1", features = ["s-mode"] }
|
||||||
|
46
kernel/src/fs/procfs/loadavg.rs
Normal file
46
kernel/src/fs/procfs/loadavg.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! This module offers `/proc/loadavg` file support, which tells the user space
|
||||||
|
//! about the cpu load average for the last 1, 5, and 15 minutes.
|
||||||
|
//!
|
||||||
|
//! Reference: <https://www.man7.org/linux/man-pages/man5/proc_loadavg.5.html>
|
||||||
|
|
||||||
|
use alloc::format;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
fs::{
|
||||||
|
procfs::template::{FileOps, ProcFileBuilder},
|
||||||
|
utils::Inode,
|
||||||
|
},
|
||||||
|
prelude::*,
|
||||||
|
process::posix_thread,
|
||||||
|
sched::{self, loadavg::get_loadavg},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Represents the inode at `/proc/loadavg`.
|
||||||
|
pub struct LoadAvgFileOps;
|
||||||
|
|
||||||
|
impl LoadAvgFileOps {
|
||||||
|
pub fn new_inode(parent: Weak<dyn Inode>) -> Arc<dyn Inode> {
|
||||||
|
ProcFileBuilder::new(Self).parent(parent).build().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileOps for LoadAvgFileOps {
|
||||||
|
fn data(&self) -> Result<Vec<u8>> {
|
||||||
|
let avg = get_loadavg();
|
||||||
|
let (nr_queued, nr_running) = sched::nr_queued_and_running();
|
||||||
|
|
||||||
|
let output = format!(
|
||||||
|
"{:.2} {:.2} {:.2} {}/{} {}\n",
|
||||||
|
avg[0],
|
||||||
|
avg[1],
|
||||||
|
avg[2],
|
||||||
|
nr_running,
|
||||||
|
nr_queued,
|
||||||
|
posix_thread::last_tid(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(output.into_bytes())
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use core::sync::atomic::{AtomicU64, Ordering};
|
use core::sync::atomic::{AtomicU64, Ordering};
|
||||||
|
|
||||||
|
use loadavg::LoadAvgFileOps;
|
||||||
use sys::SysDirOps;
|
use sys::SysDirOps;
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
@ -21,6 +22,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
mod filesystems;
|
mod filesystems;
|
||||||
|
mod loadavg;
|
||||||
mod meminfo;
|
mod meminfo;
|
||||||
mod pid;
|
mod pid;
|
||||||
mod self_;
|
mod self_;
|
||||||
@ -106,6 +108,8 @@ impl DirOps for RootDirOps {
|
|||||||
FileSystemsFileOps::new_inode(this_ptr.clone())
|
FileSystemsFileOps::new_inode(this_ptr.clone())
|
||||||
} else if name == "meminfo" {
|
} else if name == "meminfo" {
|
||||||
MemInfoFileOps::new_inode(this_ptr.clone())
|
MemInfoFileOps::new_inode(this_ptr.clone())
|
||||||
|
} else if name == "loadavg" {
|
||||||
|
LoadAvgFileOps::new_inode(this_ptr.clone())
|
||||||
} else if let Ok(pid) = name.parse::<Pid>() {
|
} else if let Ok(pid) = name.parse::<Pid>() {
|
||||||
let process_ref =
|
let process_ref =
|
||||||
process_table::get_process(pid).ok_or_else(|| Error::new(Errno::ENOENT))?;
|
process_table::get_process(pid).ok_or_else(|| Error::new(Errno::ENOENT))?;
|
||||||
@ -129,6 +133,8 @@ impl DirOps for RootDirOps {
|
|||||||
});
|
});
|
||||||
cached_children
|
cached_children
|
||||||
.put_entry_if_not_found("meminfo", || MemInfoFileOps::new_inode(this_ptr.clone()));
|
.put_entry_if_not_found("meminfo", || MemInfoFileOps::new_inode(this_ptr.clone()));
|
||||||
|
cached_children
|
||||||
|
.put_entry_if_not_found("loadavg", || LoadAvgFileOps::new_inode(this_ptr.clone()));
|
||||||
|
|
||||||
for process in process_table::process_table_mut().iter() {
|
for process in process_table::process_table_mut().iter() {
|
||||||
let pid = process.pid().to_string();
|
let pid = process.pid().to_string();
|
||||||
|
@ -374,7 +374,7 @@ impl PageCacheManager {
|
|||||||
|
|
||||||
for (_, page) in pages
|
for (_, page) in pages
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.filter(|(idx, _)| page_idx_range.contains(idx))
|
.filter(|(idx, _)| page_idx_range.contains(*idx))
|
||||||
{
|
{
|
||||||
page.set_state(PageState::UpToDate);
|
page.set_state(PageState::UpToDate);
|
||||||
}
|
}
|
||||||
|
@ -305,3 +305,8 @@ static POSIX_TID_ALLOCATOR: AtomicU32 = AtomicU32::new(1);
|
|||||||
pub fn allocate_posix_tid() -> Tid {
|
pub fn allocate_posix_tid() -> Tid {
|
||||||
POSIX_TID_ALLOCATOR.fetch_add(1, Ordering::SeqCst)
|
POSIX_TID_ALLOCATOR.fetch_add(1, Ordering::SeqCst)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the last allocated tid
|
||||||
|
pub fn last_tid() -> Tid {
|
||||||
|
POSIX_TID_ALLOCATOR.load(Ordering::SeqCst) - 1
|
||||||
|
}
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
pub mod priority;
|
pub mod priority;
|
||||||
mod priority_scheduler;
|
mod priority_scheduler;
|
||||||
|
mod stats;
|
||||||
|
|
||||||
|
// Export the stats getter functions.
|
||||||
|
pub use stats::{loadavg, nr_queued_and_running};
|
||||||
|
|
||||||
// There may be multiple scheduling policies in the system,
|
// There may be multiple scheduling policies in the system,
|
||||||
// and subsequent schedulers can be placed under this module.
|
// and subsequent schedulers can be placed under this module.
|
||||||
|
@ -5,6 +5,7 @@ use core::sync::atomic::Ordering;
|
|||||||
use ostd::{
|
use ostd::{
|
||||||
cpu::{num_cpus, CpuId, CpuSet, PinCurrentCpu},
|
cpu::{num_cpus, CpuId, CpuSet, PinCurrentCpu},
|
||||||
task::{
|
task::{
|
||||||
|
disable_preempt,
|
||||||
scheduler::{
|
scheduler::{
|
||||||
info::CommonSchedInfo, inject_scheduler, EnqueueFlags, LocalRunQueue, Scheduler,
|
info::CommonSchedInfo, inject_scheduler, EnqueueFlags, LocalRunQueue, Scheduler,
|
||||||
UpdateFlags,
|
UpdateFlags,
|
||||||
@ -14,13 +15,23 @@ use ostd::{
|
|||||||
trap::disable_local,
|
trap::disable_local,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::priority::{Priority, PriorityRange};
|
use super::{
|
||||||
|
priority::{Priority, PriorityRange},
|
||||||
|
stats::{set_stats_from_scheduler, SchedulerStats},
|
||||||
|
};
|
||||||
use crate::{prelude::*, thread::Thread};
|
use crate::{prelude::*, thread::Thread};
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
let preempt_scheduler = Box::new(PreemptScheduler::default());
|
let preempt_scheduler = Box::new(PreemptScheduler::default());
|
||||||
let scheduler = Box::<PreemptScheduler<Thread, Task>>::leak(preempt_scheduler);
|
let scheduler = Box::<PreemptScheduler<Thread, Task>>::leak(preempt_scheduler);
|
||||||
|
|
||||||
|
// Inject the scheduler into the ostd for actual scheduling work.
|
||||||
inject_scheduler(scheduler);
|
inject_scheduler(scheduler);
|
||||||
|
|
||||||
|
// Set the scheduler into the system for statistics.
|
||||||
|
// We set this after injecting the scheduler into ostd,
|
||||||
|
// so that the loadavg statistics are updated after the scheduler is used.
|
||||||
|
set_stats_from_scheduler(scheduler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The preempt scheduler.
|
/// The preempt scheduler.
|
||||||
@ -118,6 +129,29 @@ impl<T: Sync + Send + PreemptSchedInfo + FromTask<U>, U: Sync + Send + CommonSch
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Sync + Send + PreemptSchedInfo + FromTask<U>, U: Sync + Send + CommonSchedInfo>
|
||||||
|
SchedulerStats for PreemptScheduler<T, U>
|
||||||
|
{
|
||||||
|
fn nr_queued_and_running(&self) -> (u32, u32) {
|
||||||
|
let _preempt_guard = disable_preempt();
|
||||||
|
let mut nr_queued = 0;
|
||||||
|
let mut nr_running = 0;
|
||||||
|
|
||||||
|
for rq in self.rq.iter() {
|
||||||
|
let rq = rq.lock();
|
||||||
|
|
||||||
|
nr_queued +=
|
||||||
|
rq.real_time_entities.len() + rq.normal_entities.len() + rq.lowest_entities.len();
|
||||||
|
|
||||||
|
if rq.current.is_some() {
|
||||||
|
nr_running += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(nr_queued as u32, nr_running)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for PreemptScheduler<Thread, Task> {
|
impl Default for PreemptScheduler<Thread, Task> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new(num_cpus())
|
Self::new(num_cpus())
|
||||||
|
71
kernel/src/sched/stats/loadavg.rs
Normal file
71
kernel/src/sched/stats/loadavg.rs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! This module implements the CPU load average calculation.
|
||||||
|
//!
|
||||||
|
//! Reference: <https://github.com/torvalds/linux/blob/46132e3/kernel/sched/loadavg.c>
|
||||||
|
|
||||||
|
use core::sync::atomic::{AtomicU64, Ordering::Relaxed};
|
||||||
|
|
||||||
|
use ostd::{arch::timer::TIMER_FREQ, sync::RwLock, timer};
|
||||||
|
|
||||||
|
/// Fixed-point representation of the load average.
|
||||||
|
///
|
||||||
|
/// This is an equivalent of an u32 with 21 bits for the integer part and 11 bits for the fractional part.
|
||||||
|
pub type FixedPoint = fixed::types::U21F11;
|
||||||
|
|
||||||
|
/// 5 sec intervals
|
||||||
|
const LOAD_FREQ: u64 = 5 * TIMER_FREQ + 1;
|
||||||
|
/// 1/exp(5sec/1min) as fixed-point
|
||||||
|
const EXP_1: FixedPoint = FixedPoint::from_bits(1884);
|
||||||
|
/// 1/exp(5sec/5min)
|
||||||
|
const EXP_5: FixedPoint = FixedPoint::from_bits(2014);
|
||||||
|
/// 1/exp(5sec/15min)
|
||||||
|
const EXP_15: FixedPoint = FixedPoint::from_bits(2037);
|
||||||
|
|
||||||
|
/// Load average of all CPU cores.
|
||||||
|
///
|
||||||
|
/// The load average is calculated as an exponential moving average of the load
|
||||||
|
/// over the last 1, 5, and 15 minutes.
|
||||||
|
static LOAD_AVG: RwLock<[FixedPoint; 3]> = RwLock::new([FixedPoint::ZERO; 3]);
|
||||||
|
|
||||||
|
/// Next time the load average will be updated (in jiffies).
|
||||||
|
static LOAD_AVG_NEXT_UPDATE: AtomicU64 = AtomicU64::new(0);
|
||||||
|
|
||||||
|
/// Returns the calculated load average of the system.
|
||||||
|
pub fn get_loadavg() -> [FixedPoint; 3] {
|
||||||
|
*LOAD_AVG.read()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates the load average of the system.
|
||||||
|
///
|
||||||
|
/// This function should be called periodically to update the load average.
|
||||||
|
/// The `get_load` function should return the load (the number of queued tasks) of the system.
|
||||||
|
/// See `sched::stats::scheduler_stats::set_stats_from_scheduler()` for an example.
|
||||||
|
pub fn update_loadavg<F>(get_load: F)
|
||||||
|
where
|
||||||
|
F: Fn() -> u32,
|
||||||
|
{
|
||||||
|
let jiffies = timer::Jiffies::elapsed().as_u64();
|
||||||
|
|
||||||
|
// Return if the load average was updated less than 5 seconds ago.
|
||||||
|
if jiffies < LOAD_AVG_NEXT_UPDATE.load(Relaxed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the next time the load average will be updated (now + 5sec)
|
||||||
|
LOAD_AVG_NEXT_UPDATE.store(jiffies + LOAD_FREQ, Relaxed);
|
||||||
|
|
||||||
|
// Get the fixed-point representation of the load
|
||||||
|
let new_load = FixedPoint::from_num(get_load());
|
||||||
|
|
||||||
|
let mut load = LOAD_AVG.write();
|
||||||
|
|
||||||
|
// Calculate the new load average
|
||||||
|
load[0] = calc_loadavg(load[0], EXP_1, new_load);
|
||||||
|
load[1] = calc_loadavg(load[1], EXP_5, new_load);
|
||||||
|
load[2] = calc_loadavg(load[2], EXP_15, new_load);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calc_loadavg(old_load: FixedPoint, exp: FixedPoint, new_load: FixedPoint) -> FixedPoint {
|
||||||
|
old_load * exp + new_load * (FixedPoint::ONE - exp)
|
||||||
|
}
|
6
kernel/src/sched/stats/mod.rs
Normal file
6
kernel/src/sched/stats/mod.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
pub mod loadavg;
|
||||||
|
mod scheduler_stats;
|
||||||
|
|
||||||
|
pub use scheduler_stats::{nr_queued_and_running, set_stats_from_scheduler, SchedulerStats};
|
37
kernel/src/sched/stats/scheduler_stats.rs
Normal file
37
kernel/src/sched/stats/scheduler_stats.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use ostd::timer;
|
||||||
|
use spin::Once;
|
||||||
|
|
||||||
|
use super::loadavg;
|
||||||
|
|
||||||
|
/// The global scheduler statistic singleton
|
||||||
|
static SCHEDULER_STATS: Once<&'static dyn SchedulerStats> = Once::new();
|
||||||
|
|
||||||
|
/// Set the global scheduler statistics singleton.
|
||||||
|
///
|
||||||
|
/// This function should be called once to set the scheduler statistics system.
|
||||||
|
/// It is used to get running stats from the scheduler and to periodically
|
||||||
|
/// calculate the system load average.
|
||||||
|
pub fn set_stats_from_scheduler(scheduler: &'static dyn SchedulerStats) {
|
||||||
|
SCHEDULER_STATS.call_once(|| scheduler);
|
||||||
|
|
||||||
|
// Register a callback to update the load average periodically
|
||||||
|
timer::register_callback(|| {
|
||||||
|
loadavg::update_loadavg(|| nr_queued_and_running().0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The trait for the scheduler statistics.
|
||||||
|
pub trait SchedulerStats: Sync + Send {
|
||||||
|
/// Returns a tuple with the number of tasks in the runqueues and the number of running tasks.
|
||||||
|
///
|
||||||
|
/// We decided to return a tuple instead of having two separate functions to
|
||||||
|
/// avoid the overhead of disabling the preemption twice to inspect the scheduler.
|
||||||
|
fn nr_queued_and_running(&self) -> (u32, u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the amount of tasks in the runqueues and the amount of running tasks.
|
||||||
|
pub fn nr_queued_and_running() -> (u32, u32) {
|
||||||
|
SCHEDULER_STATS.get().unwrap().nr_queued_and_running()
|
||||||
|
}
|
@ -46,7 +46,7 @@ fn handle_getfd(fd: FileDesc, ctx: &Context) -> Result<SyscallReturn> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_setfd(fd: FileDesc, arg: u64, ctx: &Context) -> Result<SyscallReturn> {
|
fn handle_setfd(fd: FileDesc, arg: u64, ctx: &Context) -> Result<SyscallReturn> {
|
||||||
let flags = if arg > u8::MAX.into() {
|
let flags = if arg > u64::from(u8::MAX) {
|
||||||
return_errno_with_message!(Errno::EINVAL, "invalid fd flags");
|
return_errno_with_message!(Errno::EINVAL, "invalid fd flags");
|
||||||
} else {
|
} else {
|
||||||
FdFlags::from_bits(arg as u8).ok_or(Error::with_message(Errno::EINVAL, "invalid flags"))?
|
FdFlags::from_bits(arg as u8).ok_or(Error::with_message(Errno::EINVAL, "invalid flags"))?
|
||||||
|
Reference in New Issue
Block a user