mirror of
https://github.com/hexagonal-sun/moss-kernel.git
synced 2025-12-23 22:47:55 -05:00
Initial proc fs (#70)
This commit is contained in:
@@ -46,6 +46,7 @@ bitflags::bitflags! {
|
|||||||
|
|
||||||
// Reserved psuedo filesystem instances created internally in the kernel.
|
// Reserved psuedo filesystem instances created internally in the kernel.
|
||||||
pub const DEVFS_ID: u64 = 1;
|
pub const DEVFS_ID: u64 = 1;
|
||||||
|
pub const PROCFS_ID: u64 = 2;
|
||||||
pub const FS_ID_START: u64 = 10;
|
pub const FS_ID_START: u64 = 10;
|
||||||
|
|
||||||
/// Trait for a mounted filesystem instance. Its main role is to act as a
|
/// Trait for a mounted filesystem instance. Its main role is to act as a
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ mkfs.vfat -F 32 "$img"
|
|||||||
|
|
||||||
mmd -i "$img" ::/bin
|
mmd -i "$img" ::/bin
|
||||||
mmd -i "$img" ::/dev
|
mmd -i "$img" ::/dev
|
||||||
|
mmd -i "$img" ::/proc
|
||||||
mmd -i "$img" ::/tmp
|
mmd -i "$img" ::/tmp
|
||||||
|
|
||||||
mcopy -i "$img" "$base/build/bin"/* "::/bin"
|
mcopy -i "$img" "$base/build/bin"/* "::/bin"
|
||||||
|
|||||||
@@ -8,4 +8,4 @@ bin="${elf%.elf}.bin"
|
|||||||
|
|
||||||
# Convert to binary format
|
# Convert to binary format
|
||||||
aarch64-none-elf-objcopy -O binary "$elf" "$bin"
|
aarch64-none-elf-objcopy -O binary "$elf" "$bin"
|
||||||
qemu-system-aarch64 -M virt,gic-version=3 -initrd moss.img -cpu cortex-a72 -m 2G -smp 4 -nographic -s -kernel "$bin" -append "--init=/bin/bash --rootfs=fat32fs --automount=/dev,devfs --automount=/tmp,tmpfs"
|
qemu-system-aarch64 -M virt,gic-version=3 -initrd moss.img -cpu cortex-a72 -m 2G -smp 4 -nographic -s -kernel "$bin" -append "--init=/bin/bash --rootfs=fat32fs --automount=/dev,devfs --automount=/tmp,tmpfs --automount=/proc,procfs"
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use dev::DevFsDriver;
|
use dev::DevFsDriver;
|
||||||
use fat32::Fat32FsDriver;
|
use fat32::Fat32FsDriver;
|
||||||
|
use proc::ProcFsDriver;
|
||||||
use tmpfs::TmpFsDriver;
|
use tmpfs::TmpFsDriver;
|
||||||
|
|
||||||
use super::DM;
|
use super::DM;
|
||||||
|
|
||||||
pub mod dev;
|
pub mod dev;
|
||||||
pub mod fat32;
|
pub mod fat32;
|
||||||
|
pub mod proc;
|
||||||
pub mod tmpfs;
|
pub mod tmpfs;
|
||||||
|
|
||||||
pub fn register_fs_drivers() {
|
pub fn register_fs_drivers() {
|
||||||
@@ -14,5 +16,6 @@ pub fn register_fs_drivers() {
|
|||||||
|
|
||||||
dm.insert_driver(Arc::new(Fat32FsDriver::new()));
|
dm.insert_driver(Arc::new(Fat32FsDriver::new()));
|
||||||
dm.insert_driver(Arc::new(DevFsDriver::new()));
|
dm.insert_driver(Arc::new(DevFsDriver::new()));
|
||||||
|
dm.insert_driver(Arc::new(ProcFsDriver::new()));
|
||||||
dm.insert_driver(Arc::new(TmpFsDriver::new()));
|
dm.insert_driver(Arc::new(TmpFsDriver::new()));
|
||||||
}
|
}
|
||||||
|
|||||||
377
src/drivers/fs/proc.rs
Normal file
377
src/drivers/fs/proc.rs
Normal file
@@ -0,0 +1,377 @@
|
|||||||
|
#![allow(clippy::module_name_repetitions)]
|
||||||
|
|
||||||
|
use crate::process::thread_group::Tgid;
|
||||||
|
use crate::sched::{SCHED_STATE, current_task};
|
||||||
|
use crate::sync::OnceLock;
|
||||||
|
use crate::{
|
||||||
|
drivers::{Driver, FilesystemDriver},
|
||||||
|
process::TASK_LIST,
|
||||||
|
};
|
||||||
|
use alloc::{boxed::Box, format, string::ToString, sync::Arc, vec::Vec};
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use core::sync::atomic::{AtomicU64, Ordering};
|
||||||
|
use libkernel::{
|
||||||
|
error::{FsError, KernelError, Result},
|
||||||
|
fs::{
|
||||||
|
BlockDevice, DirStream, Dirent, FileType, Filesystem, Inode, InodeId, PROCFS_ID,
|
||||||
|
attr::{FileAttr, FilePermissions},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use log::warn;
|
||||||
|
|
||||||
|
pub struct ProcFs {
|
||||||
|
root: Arc<ProcRootInode>,
|
||||||
|
next_inode_id: AtomicU64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProcFs {
|
||||||
|
fn new() -> Arc<Self> {
|
||||||
|
let root_inode = Arc::new(ProcRootInode::new());
|
||||||
|
Arc::new(Self {
|
||||||
|
root: root_inode,
|
||||||
|
next_inode_id: AtomicU64::new(1),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convenience helper to allocate a unique inode ID inside this filesystem.
|
||||||
|
fn alloc_inode_id(&self) -> InodeId {
|
||||||
|
let id = self.next_inode_id.fetch_add(1, Ordering::Relaxed);
|
||||||
|
InodeId::from_fsid_and_inodeid(PROCFS_ID, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Filesystem for ProcFs {
|
||||||
|
async fn root_inode(&self) -> Result<Arc<dyn Inode>> {
|
||||||
|
Ok(self.root.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn id(&self) -> u64 {
|
||||||
|
PROCFS_ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ProcDirStream {
|
||||||
|
entries: Vec<Dirent>,
|
||||||
|
idx: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl DirStream for ProcDirStream {
|
||||||
|
async fn next_entry(&mut self) -> Result<Option<Dirent>> {
|
||||||
|
Ok(if let Some(entry) = self.entries.get(self.idx).cloned() {
|
||||||
|
self.idx += 1;
|
||||||
|
Some(entry)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ProcRootInode {
|
||||||
|
id: InodeId,
|
||||||
|
attr: FileAttr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProcRootInode {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
id: InodeId::from_fsid_and_inodeid(PROCFS_ID, 0),
|
||||||
|
attr: FileAttr {
|
||||||
|
file_type: FileType::Directory,
|
||||||
|
mode: FilePermissions::from_bits_retain(0o555),
|
||||||
|
..FileAttr::default()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Inode for ProcRootInode {
|
||||||
|
fn id(&self) -> InodeId {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn lookup(&self, name: &str) -> Result<Arc<dyn Inode>> {
|
||||||
|
// Lookup a PID directory.
|
||||||
|
let pid = if name == "self" {
|
||||||
|
let current_task = current_task();
|
||||||
|
current_task.descriptor().tgid()
|
||||||
|
} else {
|
||||||
|
Tgid(
|
||||||
|
name.parse()
|
||||||
|
.map_err(|_| FsError::NotFound)
|
||||||
|
.map_err(Into::<KernelError>::into)?,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Validate that the process actually exists.
|
||||||
|
if !TASK_LIST.lock_save_irq().keys().any(|d| d.tgid() == pid) {
|
||||||
|
return Err(FsError::NotFound.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let fs = procfs();
|
||||||
|
|
||||||
|
let inode_id = fs.alloc_inode_id();
|
||||||
|
Ok(Arc::new(ProcTaskInode::new(pid, inode_id)))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn getattr(&self) -> Result<FileAttr> {
|
||||||
|
Ok(self.attr.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn readdir(&self, start_offset: u64) -> Result<Box<dyn DirStream>> {
|
||||||
|
let mut entries: Vec<Dirent> = Vec::new();
|
||||||
|
// Gather task list under interrupt-safe lock.
|
||||||
|
let task_list = TASK_LIST.lock_save_irq();
|
||||||
|
for (idx, desc) in task_list.keys().enumerate() {
|
||||||
|
// Use offset index as dirent offset.
|
||||||
|
let name = desc.tgid().value().to_string();
|
||||||
|
let inode_id =
|
||||||
|
InodeId::from_fsid_and_inodeid(PROCFS_ID, ((desc.tgid().0 + 1) * 100) as u64);
|
||||||
|
entries.push(Dirent::new(
|
||||||
|
name,
|
||||||
|
inode_id,
|
||||||
|
FileType::Directory,
|
||||||
|
(idx + 1) as u64,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let current_task = current_task();
|
||||||
|
entries.push(Dirent::new(
|
||||||
|
"self".to_string(),
|
||||||
|
InodeId::from_fsid_and_inodeid(
|
||||||
|
PROCFS_ID,
|
||||||
|
((current_task.process.tgid.0 + 1) * 100) as u64,
|
||||||
|
),
|
||||||
|
FileType::Directory,
|
||||||
|
(entries.len() + 1) as u64,
|
||||||
|
));
|
||||||
|
|
||||||
|
// honour start_offset
|
||||||
|
let entries = entries.into_iter().skip(start_offset as usize).collect();
|
||||||
|
|
||||||
|
Ok(Box::new(ProcDirStream { entries, idx: 0 }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ProcTaskInode {
|
||||||
|
id: InodeId,
|
||||||
|
attr: FileAttr,
|
||||||
|
pid: Tgid,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProcTaskInode {
|
||||||
|
fn new(pid: Tgid, inode_id: InodeId) -> Self {
|
||||||
|
Self {
|
||||||
|
id: inode_id,
|
||||||
|
attr: FileAttr {
|
||||||
|
file_type: FileType::Directory,
|
||||||
|
mode: FilePermissions::from_bits_retain(0o555),
|
||||||
|
..FileAttr::default()
|
||||||
|
},
|
||||||
|
pid,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Inode for ProcTaskInode {
|
||||||
|
fn id(&self) -> InodeId {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn lookup(&self, name: &str) -> Result<Arc<dyn Inode>> {
|
||||||
|
if let Ok(file_type) = TaskFileType::try_from(name) {
|
||||||
|
let fs = procfs();
|
||||||
|
let inode_id = fs.alloc_inode_id();
|
||||||
|
Ok(Arc::new(ProcTaskFileInode::new(
|
||||||
|
self.pid, file_type, inode_id,
|
||||||
|
)))
|
||||||
|
} else {
|
||||||
|
Err(FsError::NotFound.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn getattr(&self) -> Result<FileAttr> {
|
||||||
|
Ok(self.attr.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn readdir(&self, start_offset: u64) -> Result<Box<dyn DirStream>> {
|
||||||
|
let mut entries: Vec<Dirent> = Vec::new();
|
||||||
|
let inode_offset = ((self.pid.value() + 1) * 100) as u64;
|
||||||
|
entries.push(Dirent::new(
|
||||||
|
"status".to_string(),
|
||||||
|
InodeId::from_fsid_and_inodeid(PROCFS_ID, inode_offset + 1),
|
||||||
|
FileType::File,
|
||||||
|
1,
|
||||||
|
));
|
||||||
|
entries.push(Dirent::new(
|
||||||
|
"comm".to_string(),
|
||||||
|
InodeId::from_fsid_and_inodeid(PROCFS_ID, inode_offset + 2),
|
||||||
|
FileType::File,
|
||||||
|
2,
|
||||||
|
));
|
||||||
|
entries.push(Dirent::new(
|
||||||
|
"state".to_string(),
|
||||||
|
InodeId::from_fsid_and_inodeid(PROCFS_ID, inode_offset + 3),
|
||||||
|
FileType::File,
|
||||||
|
3,
|
||||||
|
));
|
||||||
|
|
||||||
|
// honour start_offset
|
||||||
|
let entries = entries.into_iter().skip(start_offset as usize).collect();
|
||||||
|
|
||||||
|
Ok(Box::new(ProcDirStream { entries, idx: 0 }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TaskFileType {
|
||||||
|
Status,
|
||||||
|
Comm,
|
||||||
|
State,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&str> for TaskFileType {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: &str) -> core::result::Result<TaskFileType, Self::Error> {
|
||||||
|
match value {
|
||||||
|
"status" => Ok(TaskFileType::Status),
|
||||||
|
"comm" => Ok(TaskFileType::Comm),
|
||||||
|
"state" => Ok(TaskFileType::State),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ProcTaskFileInode {
|
||||||
|
id: InodeId,
|
||||||
|
file_type: TaskFileType,
|
||||||
|
attr: FileAttr,
|
||||||
|
pid: Tgid,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProcTaskFileInode {
|
||||||
|
fn new(pid: Tgid, file_type: TaskFileType, inode_id: InodeId) -> Self {
|
||||||
|
Self {
|
||||||
|
id: inode_id,
|
||||||
|
attr: FileAttr {
|
||||||
|
file_type: FileType::File,
|
||||||
|
mode: FilePermissions::from_bits_retain(0o444),
|
||||||
|
..FileAttr::default()
|
||||||
|
},
|
||||||
|
pid,
|
||||||
|
file_type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Inode for ProcTaskFileInode {
|
||||||
|
fn id(&self) -> InodeId {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn lookup(&self, _name: &str) -> Result<Arc<dyn Inode>> {
|
||||||
|
Err(FsError::NotADirectory.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn getattr(&self) -> Result<FileAttr> {
|
||||||
|
Ok(self.attr.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn readdir(&self, _start_offset: u64) -> Result<Box<dyn DirStream>> {
|
||||||
|
Err(FsError::NotADirectory.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
let pid = self.pid;
|
||||||
|
let task_list = TASK_LIST.lock_save_irq();
|
||||||
|
// TODO: Does not obtain details for tasks that are on other CPUs
|
||||||
|
let id = task_list.iter().find(|(desc, _)| desc.tgid() == pid);
|
||||||
|
let task_details = if let Some((desc, _)) = id {
|
||||||
|
SCHED_STATE.borrow().run_queue.get(desc).cloned()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let status_string = if let Some(task) = task_details {
|
||||||
|
let state = *task.state.lock_save_irq();
|
||||||
|
let name = task.comm.lock_save_irq();
|
||||||
|
match self.file_type {
|
||||||
|
TaskFileType::Status => format!(
|
||||||
|
"Name:\t{name}
|
||||||
|
State:\t{state}
|
||||||
|
Tgid:\t{tgid}
|
||||||
|
FDSize:\t{fd_size}
|
||||||
|
Pid:\t{pid}
|
||||||
|
Threads:\t{threads}\n",
|
||||||
|
name = name.as_str(),
|
||||||
|
tgid = task.process.tgid,
|
||||||
|
fd_size = task.fd_table.lock_save_irq().len(),
|
||||||
|
threads = task.process.threads.lock_save_irq().len(),
|
||||||
|
),
|
||||||
|
TaskFileType::Comm => format!("{name}\n", name = name.as_str()),
|
||||||
|
TaskFileType::State => format!("{state}\n"),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
"State:\tGone\n".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let bytes = status_string.as_bytes();
|
||||||
|
let end = usize::min(bytes.len().saturating_sub(offset as usize), buf.len());
|
||||||
|
if end == 0 {
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
let slice = &bytes[offset as usize..offset as usize + end];
|
||||||
|
buf[..end].copy_from_slice(slice);
|
||||||
|
Ok(end)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static PROCFS_INSTANCE: OnceLock<Arc<ProcFs>> = OnceLock::new();
|
||||||
|
|
||||||
|
/// Initializes and/or returns the global singleton [`ProcFs`] instance.
|
||||||
|
/// This is the main entry point for the rest of the kernel to interact with procfs.
|
||||||
|
pub fn procfs() -> Arc<ProcFs> {
|
||||||
|
PROCFS_INSTANCE
|
||||||
|
.get_or_init(|| {
|
||||||
|
log::info!("devfs initialized");
|
||||||
|
ProcFs::new()
|
||||||
|
})
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ProcFsDriver;
|
||||||
|
|
||||||
|
impl ProcFsDriver {
|
||||||
|
#[must_use]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Driver for ProcFsDriver {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"procfs"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_filesystem_driver(self: Arc<Self>) -> Option<Arc<dyn FilesystemDriver>> {
|
||||||
|
Some(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl FilesystemDriver for ProcFsDriver {
|
||||||
|
async fn construct(
|
||||||
|
&self,
|
||||||
|
_fs_id: u64,
|
||||||
|
device: Option<Box<dyn BlockDevice>>,
|
||||||
|
) -> Result<Arc<dyn Filesystem>> {
|
||||||
|
if device.is_some() {
|
||||||
|
warn!("procfs should not be constructed with a block device");
|
||||||
|
return Err(KernelError::InvalidValue);
|
||||||
|
}
|
||||||
|
Ok(procfs())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -115,6 +115,7 @@ pub async fn sys_clone(
|
|||||||
|
|
||||||
Task {
|
Task {
|
||||||
tid,
|
tid,
|
||||||
|
comm: Arc::new(SpinLock::new(*current_task.comm.lock_save_irq())),
|
||||||
process: tg,
|
process: tg,
|
||||||
vm,
|
vm,
|
||||||
fd_table: files,
|
fd_table: files,
|
||||||
@@ -124,7 +125,7 @@ pub async fn sys_clone(
|
|||||||
priority: current_task.priority,
|
priority: current_task.priority,
|
||||||
sig_mask: SpinLock::new(new_sigmask),
|
sig_mask: SpinLock::new(new_sigmask),
|
||||||
pending_signals: SpinLock::new(SigSet::empty()),
|
pending_signals: SpinLock::new(SigSet::empty()),
|
||||||
vruntime: SpinLock::new(*current_task.vruntime.lock_save_irq()),
|
vruntime: SpinLock::new(0),
|
||||||
exec_start: SpinLock::new(None),
|
exec_start: SpinLock::new(None),
|
||||||
deadline: SpinLock::new(*current_task.deadline.lock_save_irq()),
|
deadline: SpinLock::new(*current_task.deadline.lock_save_irq()),
|
||||||
state: Arc::new(SpinLock::new(TaskState::Runnable)),
|
state: Arc::new(SpinLock::new(TaskState::Runnable)),
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::process::Comm;
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{Arch, ArchImpl},
|
arch::{Arch, ArchImpl},
|
||||||
fs::VFS,
|
fs::VFS,
|
||||||
@@ -116,8 +117,13 @@ pub async fn kernel_exec(
|
|||||||
// state. Simply activate the new process's address space.
|
// state. Simply activate the new process's address space.
|
||||||
vm.mm_mut().address_space_mut().activate();
|
vm.mm_mut().address_space_mut().activate();
|
||||||
|
|
||||||
|
let new_comm = argv.first().map(|s| Comm::new(s.as_str()));
|
||||||
|
|
||||||
let current_task = current_task();
|
let current_task = current_task();
|
||||||
|
|
||||||
|
if let Some(new_comm) = new_comm {
|
||||||
|
*current_task.comm.lock_save_irq() = new_comm;
|
||||||
|
}
|
||||||
*current_task.ctx.lock_save_irq() = Context::from_user_ctx(user_ctx);
|
*current_task.ctx.lock_save_irq() = Context::from_user_ctx(user_ctx);
|
||||||
*current_task.state.lock_save_irq() = TaskState::Runnable;
|
*current_task.state.lock_save_irq() = TaskState::Runnable;
|
||||||
*current_task.vm.lock_save_irq() = vm;
|
*current_task.vm.lock_save_irq() = vm;
|
||||||
|
|||||||
@@ -161,4 +161,9 @@ impl FileDescriptorTable {
|
|||||||
Ok(Fd(next as i32))
|
Ok(Fd(next as i32))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Number of file descriptors in use.
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.entries.iter().filter(|e| e.is_some()).count()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use alloc::{
|
|||||||
collections::btree_map::BTreeMap,
|
collections::btree_map::BTreeMap,
|
||||||
sync::{Arc, Weak},
|
sync::{Arc, Weak},
|
||||||
};
|
};
|
||||||
|
use core::fmt::Display;
|
||||||
use creds::Credentials;
|
use creds::Credentials;
|
||||||
use ctx::{Context, UserCtx};
|
use ctx::{Context, UserCtx};
|
||||||
use fd_table::FileDescriptorTable;
|
use fd_table::FileDescriptorTable;
|
||||||
@@ -100,6 +101,16 @@ impl TaskDescriptor {
|
|||||||
pub fn is_idle(&self) -> bool {
|
pub fn is_idle(&self) -> bool {
|
||||||
self.tgid.is_idle()
|
self.tgid.is_idle()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the task-group ID (i.e. the PID) associated with this descriptor.
|
||||||
|
pub fn tgid(&self) -> Tgid {
|
||||||
|
self.tgid
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the thread ID associated with this descriptor.
|
||||||
|
pub fn tid(&self) -> Tid {
|
||||||
|
self.tid
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
@@ -111,6 +122,19 @@ pub enum TaskState {
|
|||||||
Finished,
|
Finished,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for TaskState {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
let state_str = match self {
|
||||||
|
TaskState::Running => "R",
|
||||||
|
TaskState::Runnable => "R",
|
||||||
|
TaskState::Stopped => "T",
|
||||||
|
TaskState::Sleeping => "S",
|
||||||
|
TaskState::Finished => "Z",
|
||||||
|
};
|
||||||
|
write!(f, "{}", state_str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TaskState {
|
impl TaskState {
|
||||||
pub fn is_finished(self) -> bool {
|
pub fn is_finished(self) -> bool {
|
||||||
matches!(self, Self::Finished)
|
matches!(self, Self::Finished)
|
||||||
@@ -118,8 +142,29 @@ impl TaskState {
|
|||||||
}
|
}
|
||||||
pub type ProcVM = ProcessVM<<ArchImpl as VirtualMemory>::ProcessAddressSpace>;
|
pub type ProcVM = ProcessVM<<ArchImpl as VirtualMemory>::ProcessAddressSpace>;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct Comm([u8; 16]);
|
||||||
|
|
||||||
|
impl Comm {
|
||||||
|
/// Create a new command name from the given string.
|
||||||
|
/// Truncates to 15 characters if necessary, and null-terminates.
|
||||||
|
pub fn new(name: &str) -> Self {
|
||||||
|
let mut comm = [0u8; 16];
|
||||||
|
let bytes = name.as_bytes();
|
||||||
|
let len = core::cmp::min(bytes.len(), 15);
|
||||||
|
comm[..len].copy_from_slice(&bytes[..len]);
|
||||||
|
Self(comm)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_str(&self) -> &str {
|
||||||
|
let len = self.0.iter().position(|&c| c == 0).unwrap_or(16);
|
||||||
|
core::str::from_utf8(&self.0[..len]).unwrap_or("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Task {
|
pub struct Task {
|
||||||
pub tid: Tid,
|
pub tid: Tid,
|
||||||
|
pub comm: Arc<SpinLock<Comm>>,
|
||||||
pub process: Arc<ThreadGroup>,
|
pub process: Arc<ThreadGroup>,
|
||||||
pub vm: Arc<SpinLock<ProcVM>>,
|
pub vm: Arc<SpinLock<ProcVM>>,
|
||||||
pub cwd: Arc<SpinLock<(Arc<dyn Inode>, PathBuf)>>,
|
pub cwd: Arc<SpinLock<(Arc<dyn Inode>, PathBuf)>>,
|
||||||
@@ -151,6 +196,7 @@ impl Task {
|
|||||||
|
|
||||||
Self {
|
Self {
|
||||||
tid: Tid(0),
|
tid: Tid(0),
|
||||||
|
comm: Arc::new(SpinLock::new(Comm::new("idle"))),
|
||||||
process: thread_group_builder.build(),
|
process: thread_group_builder.build(),
|
||||||
state: Arc::new(SpinLock::new(TaskState::Runnable)),
|
state: Arc::new(SpinLock::new(TaskState::Runnable)),
|
||||||
priority: i8::MIN,
|
priority: i8::MIN,
|
||||||
@@ -172,6 +218,7 @@ impl Task {
|
|||||||
pub fn create_init_task() -> Self {
|
pub fn create_init_task() -> Self {
|
||||||
Self {
|
Self {
|
||||||
tid: Tid(1),
|
tid: Tid(1),
|
||||||
|
comm: Arc::new(SpinLock::new(Comm::new("init"))),
|
||||||
process: ThreadGroupBuilder::new(Tgid::init()).build(),
|
process: ThreadGroupBuilder::new(Tgid::init()).build(),
|
||||||
state: Arc::new(SpinLock::new(TaskState::Runnable)),
|
state: Arc::new(SpinLock::new(TaskState::Runnable)),
|
||||||
cwd: Arc::new(SpinLock::new((Arc::new(DummyInode {}), PathBuf::new()))),
|
cwd: Arc::new(SpinLock::new((Arc::new(DummyInode {}), PathBuf::new()))),
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ pub fn insert_task(task: Arc<Task>) {
|
|||||||
|
|
||||||
pub struct SchedState {
|
pub struct SchedState {
|
||||||
running_task: Option<Arc<Task>>,
|
running_task: Option<Arc<Task>>,
|
||||||
run_queue: BTreeMap<TaskDescriptor, Arc<Task>>,
|
pub run_queue: BTreeMap<TaskDescriptor, Arc<Task>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for SchedState {}
|
unsafe impl Send for SchedState {}
|
||||||
@@ -165,7 +165,7 @@ impl SchedState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
per_cpu! {
|
per_cpu! {
|
||||||
static SCHED_STATE: SchedState = SchedState::new;
|
pub static SCHED_STATE: SchedState = SchedState::new;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn current_task() -> Arc<Task> {
|
pub fn current_task() -> Arc<Task> {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use super::{SCHED_STATE, current_task, schedule, waker::create_waker};
|
use super::{SCHED_STATE, current_task, schedule, waker::create_waker};
|
||||||
|
use crate::process::TASK_LIST;
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{Arch, ArchImpl},
|
arch::{Arch, ArchImpl},
|
||||||
process::{
|
process::{
|
||||||
@@ -144,6 +145,8 @@ pub fn dispatch_userspace_task(ctx: *mut UserCtx) {
|
|||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.run_queue
|
.run_queue
|
||||||
.remove(&task.descriptor());
|
.remove(&task.descriptor());
|
||||||
|
let mut task_list = TASK_LIST.lock_save_irq();
|
||||||
|
task_list.remove(&task.descriptor());
|
||||||
|
|
||||||
state = State::PickNewTask;
|
state = State::PickNewTask;
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
Reference in New Issue
Block a user