sysutils: add cpu/memory information to top

This commit is contained in:
2026-03-30 12:23:25 +03:00
parent d7df44b1d9
commit 6d31142258
5 changed files with 486 additions and 27 deletions
@@ -0,0 +1,206 @@
use core::{any::Any, marker::PhantomData, sync::atomic::AtomicBool};
use alloc::{sync::Arc, vec::Vec};
use libk_util::sync::spin_rwlock::IrqSafeRwLock;
use yggdrasil_abi::{
error::Error,
io::{FileMode, OpenOptions},
};
use crate::{
fs::sysfs::{attribute::Attribute, object::KObject},
vfs::{CommonImpl, Filename, InstanceData, Metadata, Node, NodeFlags, NodeRef, RegularImpl},
};
pub trait IntegerAttributeValue: Sized + Send + Sync + 'static {
fn from_raw(data: &[u8]) -> Result<Self, Error>;
fn into_raw(&self, format: IntegerAttributeFormat) -> Result<Vec<u8>, Error>;
}
pub enum IntegerAttributeFormat {
Decimal,
Hex,
Octal,
}
pub trait IntegerAttributeOps<N: IntegerAttributeValue>: Sync + Send + 'static {
type Data: Send + 'static = ();
const WRITEABLE: bool = false;
const NAME: &'static str;
const FORMAT: IntegerAttributeFormat = IntegerAttributeFormat::Decimal;
fn read(state: &Self::Data) -> Result<N, Error> {
let _ = state;
Err(Error::NotImplemented)
}
fn write(state: &Self::Data, value: N) -> Result<(), Error> {
let _ = state;
let _ = value;
Err(Error::ReadOnly)
}
}
pub struct IntegerAttribute<N: IntegerAttributeValue, V: IntegerAttributeOps<N>>(
PhantomData<(V, N)>,
);
struct IntegerAttributeNode<N: IntegerAttributeValue, V: IntegerAttributeOps<N>> {
object: Arc<KObject<V::Data>>,
_pd: PhantomData<(V, N)>,
}
struct IntegerAttributeState {
value: IrqSafeRwLock<Vec<u8>>,
#[allow(unused)]
modified: AtomicBool,
}
macro_rules! impl_integer_value {
($($ty:ty),+ $(,)?) => {
$(
impl IntegerAttributeValue for $ty {
fn from_raw(_data: &[u8]) -> Result<Self, Error> {
todo!("IntegerAttributeValue::from_raw()")
}
fn into_raw(&self, format: IntegerAttributeFormat) -> Result<Vec<u8>, Error> {
let string = match format {
IntegerAttributeFormat::Decimal => alloc::format!("{self}\n"),
IntegerAttributeFormat::Hex => alloc::format!("{self:#x}\n"),
IntegerAttributeFormat::Octal => alloc::format!("{self:#o}\n")
};
Ok(string.into_bytes())
}
}
)+
};
}
impl_integer_value!(u8, u16, u32, u64, i8, i16, i32, i64);
impl<N: IntegerAttributeValue, V: IntegerAttributeOps<N>> CommonImpl
for IntegerAttributeNode<N, V>
{
fn size(&self, _node: &NodeRef) -> Result<u64, Error> {
Ok(0)
}
fn as_any(&self) -> &dyn Any {
self as _
}
}
impl<N: IntegerAttributeValue, V: IntegerAttributeOps<N>> RegularImpl
for IntegerAttributeNode<N, V>
{
fn open(
&self,
_node: &NodeRef,
opts: OpenOptions,
) -> Result<(u64, Option<InstanceData>), Error> {
if opts.contains(OpenOptions::WRITE) {
// && !V::WRITEABLE {
return Err(Error::ReadOnly);
}
let value = V::read(self.object.data())?.into_raw(V::FORMAT)?;
let instance = IntegerAttributeState {
value: IrqSafeRwLock::new(value),
modified: AtomicBool::new(false),
};
Ok((0, Some(Arc::new(instance))))
}
fn close(&self, _node: &NodeRef, _instance: Option<&InstanceData>) -> Result<(), Error> {
Ok(())
// if V::WRITEABLE {
// let instance = instance.ok_or(Error::InvalidFile)?;
// let instance = instance
// .downcast_ref::<StringAttributeState>()
// .ok_or(Error::InvalidFile)?;
// if instance.modified.load(Ordering::Acquire) {
// let value = instance.value.read();
// let value_str =
// core::str::from_utf8(&value[..]).map_err(|_| Error::InvalidArgument)?;
// // Trim whitespace and newlines
// V::write(&self.object.data, value_str.trim())?;
// }
// }
// Ok(())
}
fn read(
&self,
_node: &NodeRef,
instance: Option<&InstanceData>,
pos: u64,
buf: &mut [u8],
) -> Result<usize, Error> {
let instance = instance.ok_or(Error::InvalidFile)?;
let instance = instance
.downcast_ref::<IntegerAttributeState>()
.ok_or(Error::InvalidFile)?;
let value = instance.value.read();
let len = value.len();
if pos >= len as u64 {
return Ok(0);
}
let pos = pos as usize;
let amount = (len - pos).min(buf.len());
buf[..amount].copy_from_slice(&value[pos..pos + amount]);
Ok(amount)
}
fn write(
&self,
_node: &NodeRef,
_instance: Option<&InstanceData>,
_pos: u64,
_buf: &[u8],
) -> Result<usize, Error> {
todo!("Integer attribute write")
}
fn truncate(&self, _node: &NodeRef, _new_size: u64) -> Result<(), Error> {
Ok(())
}
}
impl<N: IntegerAttributeValue, V: IntegerAttributeOps<N>> From<V> for IntegerAttribute<N, V> {
fn from(_value: V) -> Self {
Self(PhantomData)
}
}
impl<N: IntegerAttributeValue, V: IntegerAttributeOps<N>> Attribute<V::Data>
for IntegerAttribute<N, V>
{
fn instantiate(&self, parent: &Arc<KObject<V::Data>>) -> Result<Arc<Node>, Error> {
let mode = match V::WRITEABLE {
false => FileMode::new(0o444),
true => FileMode::new(0o644),
};
Ok(Node::regular(
IntegerAttributeNode {
object: parent.clone(),
_pd: PhantomData::<(V, N)>,
},
NodeFlags::IN_MEMORY_PROPS,
Some(Metadata::now_root(mode, 0)),
None,
))
}
// TODO implement this properly
fn name(&self) -> &Filename {
unsafe { Filename::from_str_unchecked(V::NAME) }
}
}
@@ -6,6 +6,7 @@ use crate::vfs::{Filename, NodeRef};
use super::object::KObject;
mod bytes;
mod integer;
mod string;
pub trait Attribute<D>: Sync + Send {
@@ -14,4 +15,7 @@ pub trait Attribute<D>: Sync + Send {
}
pub use bytes::{BytesAttribute, BytesAttributeOps};
pub use integer::{
IntegerAttribute, IntegerAttributeFormat, IntegerAttributeOps, IntegerAttributeValue,
};
pub use string::{StringAttribute, StringAttributeOps};
+75 -2
View File
@@ -11,9 +11,14 @@ use kernel_arch::{
task::{Scheduler, TaskContext},
};
use libk_util::{OneTimeInit, sync::IrqGuard};
use yggdrasil_abi::time::SystemTime;
use yggdrasil_abi::{error::Error, time::SystemTime};
use crate::{
fs::sysfs::{
self,
attribute::{IntegerAttribute, IntegerAttributeOps},
object::KObject,
},
task::{TaskContextImpl, ThreadId, ThreadState, thread::Thread},
time::monotonic_time,
};
@@ -131,7 +136,7 @@ impl CpuQueue {
&self.stats.idle
};
let t = delta.as_millis() as u64;
let t = delta.as_nanos() as u64;
self.stats.total.fetch_add(t, Ordering::Relaxed);
counter.fetch_add(t, Ordering::Relaxed);
@@ -254,6 +259,74 @@ impl Scheduler for CpuQueue {
}
}
pub fn setup_sysfs() {
fn register_cpu_node(cpu: usize, node: Arc<KObject<usize>>) {
static KERNEL_SCHED: OneTimeInit<Arc<KObject<()>>> = OneTimeInit::new();
let Ok(kernel_sched) = KERNEL_SCHED.or_try_init_with(|| {
let kernel = sysfs::kernel().ok_or(Error::DoesNotExist)?;
let node = KObject::new(());
kernel.add_object("sched", node.clone())?;
Ok(node)
}) else {
return;
};
let name = alloc::format!("{cpu}");
kernel_sched.add_object(name, node).ok();
}
struct CpuIdle;
struct CpuKernel;
struct CpuUser;
struct CpuTotal;
impl IntegerAttributeOps<u64> for CpuIdle {
type Data = usize;
const NAME: &'static str = "idle";
fn read(state: &Self::Data) -> Result<u64, Error> {
Ok(stats(*state).idle.load(Ordering::Acquire))
}
}
impl IntegerAttributeOps<u64> for CpuTotal {
type Data = usize;
const NAME: &'static str = "total";
fn read(state: &Self::Data) -> Result<u64, Error> {
Ok(stats(*state).total.load(Ordering::Acquire))
}
}
impl IntegerAttributeOps<u64> for CpuUser {
type Data = usize;
const NAME: &'static str = "user";
fn read(state: &Self::Data) -> Result<u64, Error> {
Ok(stats(*state).user.load(Ordering::Acquire))
}
}
impl IntegerAttributeOps<u64> for CpuKernel {
type Data = usize;
const NAME: &'static str = "kernel";
fn read(state: &Self::Data) -> Result<u64, Error> {
Ok(stats(*state).kernel.load(Ordering::Acquire))
}
}
for cpu in 0..ArchitectureImpl::cpu_count() {
let node = KObject::new(cpu);
node.add_attribute(IntegerAttribute::from(CpuIdle)).ok();
node.add_attribute(IntegerAttribute::from(CpuTotal)).ok();
node.add_attribute(IntegerAttribute::from(CpuUser)).ok();
node.add_attribute(IntegerAttribute::from(CpuKernel)).ok();
register_cpu_node(cpu, node);
}
}
pub fn stats(index: usize) -> &'static SchedulerStats {
&QUEUES.get()[index].stats
}
+3 -1
View File
@@ -6,7 +6,7 @@ use libk::{
device::display::console,
fs::devfs,
random,
task::{binary::LoadOptions, process::Process, runtime, thread::Thread},
task::{binary::LoadOptions, process::Process, runtime, sched, thread::Thread},
vfs::{IoContext, NodeRef, OwnedFilename, impls::fn_hardlink},
};
use memfs::MemoryFilesystem;
@@ -69,6 +69,8 @@ pub fn kinit() -> Result<(), Error> {
runtime::spawn(ygg_driver_usb::bus::bus_handler())?;
runtime::spawn(console::flush_consoles_task()).ok();
sched::setup_sysfs();
devfs::root()
.add_child(
OwnedFilename::new("tty").unwrap(),