mirror of
https://github.com/hexagonal-sun/moss-kernel.git
synced 2025-12-23 14:37:57 -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.
|
||||
pub const DEVFS_ID: u64 = 1;
|
||||
pub const PROCFS_ID: u64 = 2;
|
||||
pub const FS_ID_START: u64 = 10;
|
||||
|
||||
/// 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" ::/dev
|
||||
mmd -i "$img" ::/proc
|
||||
mmd -i "$img" ::/tmp
|
||||
|
||||
mcopy -i "$img" "$base/build/bin"/* "::/bin"
|
||||
|
||||
@@ -8,4 +8,4 @@ bin="${elf%.elf}.bin"
|
||||
|
||||
# Convert to binary format
|
||||
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 dev::DevFsDriver;
|
||||
use fat32::Fat32FsDriver;
|
||||
use proc::ProcFsDriver;
|
||||
use tmpfs::TmpFsDriver;
|
||||
|
||||
use super::DM;
|
||||
|
||||
pub mod dev;
|
||||
pub mod fat32;
|
||||
pub mod proc;
|
||||
pub mod tmpfs;
|
||||
|
||||
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(DevFsDriver::new()));
|
||||
dm.insert_driver(Arc::new(ProcFsDriver::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 {
|
||||
tid,
|
||||
comm: Arc::new(SpinLock::new(*current_task.comm.lock_save_irq())),
|
||||
process: tg,
|
||||
vm,
|
||||
fd_table: files,
|
||||
@@ -124,7 +125,7 @@ pub async fn sys_clone(
|
||||
priority: current_task.priority,
|
||||
sig_mask: SpinLock::new(new_sigmask),
|
||||
pending_signals: SpinLock::new(SigSet::empty()),
|
||||
vruntime: SpinLock::new(*current_task.vruntime.lock_save_irq()),
|
||||
vruntime: SpinLock::new(0),
|
||||
exec_start: SpinLock::new(None),
|
||||
deadline: SpinLock::new(*current_task.deadline.lock_save_irq()),
|
||||
state: Arc::new(SpinLock::new(TaskState::Runnable)),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::process::Comm;
|
||||
use crate::{
|
||||
arch::{Arch, ArchImpl},
|
||||
fs::VFS,
|
||||
@@ -116,8 +117,13 @@ pub async fn kernel_exec(
|
||||
// state. Simply activate the new process's address space.
|
||||
vm.mm_mut().address_space_mut().activate();
|
||||
|
||||
let new_comm = argv.first().map(|s| Comm::new(s.as_str()));
|
||||
|
||||
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.state.lock_save_irq() = TaskState::Runnable;
|
||||
*current_task.vm.lock_save_irq() = vm;
|
||||
|
||||
@@ -161,4 +161,9 @@ impl FileDescriptorTable {
|
||||
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,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use core::fmt::Display;
|
||||
use creds::Credentials;
|
||||
use ctx::{Context, UserCtx};
|
||||
use fd_table::FileDescriptorTable;
|
||||
@@ -100,6 +101,16 @@ impl TaskDescriptor {
|
||||
pub fn is_idle(&self) -> bool {
|
||||
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)]
|
||||
@@ -111,6 +122,19 @@ pub enum TaskState {
|
||||
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 {
|
||||
pub fn is_finished(self) -> bool {
|
||||
matches!(self, Self::Finished)
|
||||
@@ -118,8 +142,29 @@ impl TaskState {
|
||||
}
|
||||
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 tid: Tid,
|
||||
pub comm: Arc<SpinLock<Comm>>,
|
||||
pub process: Arc<ThreadGroup>,
|
||||
pub vm: Arc<SpinLock<ProcVM>>,
|
||||
pub cwd: Arc<SpinLock<(Arc<dyn Inode>, PathBuf)>>,
|
||||
@@ -151,6 +196,7 @@ impl Task {
|
||||
|
||||
Self {
|
||||
tid: Tid(0),
|
||||
comm: Arc::new(SpinLock::new(Comm::new("idle"))),
|
||||
process: thread_group_builder.build(),
|
||||
state: Arc::new(SpinLock::new(TaskState::Runnable)),
|
||||
priority: i8::MIN,
|
||||
@@ -172,6 +218,7 @@ impl Task {
|
||||
pub fn create_init_task() -> Self {
|
||||
Self {
|
||||
tid: Tid(1),
|
||||
comm: Arc::new(SpinLock::new(Comm::new("init"))),
|
||||
process: ThreadGroupBuilder::new(Tgid::init()).build(),
|
||||
state: Arc::new(SpinLock::new(TaskState::Runnable)),
|
||||
cwd: Arc::new(SpinLock::new((Arc::new(DummyInode {}), PathBuf::new()))),
|
||||
|
||||
@@ -70,7 +70,7 @@ pub fn insert_task(task: Arc<Task>) {
|
||||
|
||||
pub struct SchedState {
|
||||
running_task: Option<Arc<Task>>,
|
||||
run_queue: BTreeMap<TaskDescriptor, Arc<Task>>,
|
||||
pub run_queue: BTreeMap<TaskDescriptor, Arc<Task>>,
|
||||
}
|
||||
|
||||
unsafe impl Send for SchedState {}
|
||||
@@ -165,7 +165,7 @@ impl SchedState {
|
||||
}
|
||||
|
||||
per_cpu! {
|
||||
static SCHED_STATE: SchedState = SchedState::new;
|
||||
pub static SCHED_STATE: SchedState = SchedState::new;
|
||||
}
|
||||
|
||||
pub fn current_task() -> Arc<Task> {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use super::{SCHED_STATE, current_task, schedule, waker::create_waker};
|
||||
use crate::process::TASK_LIST;
|
||||
use crate::{
|
||||
arch::{Arch, ArchImpl},
|
||||
process::{
|
||||
@@ -144,6 +145,8 @@ pub fn dispatch_userspace_task(ctx: *mut UserCtx) {
|
||||
.borrow_mut()
|
||||
.run_queue
|
||||
.remove(&task.descriptor());
|
||||
let mut task_list = TASK_LIST.lock_save_irq();
|
||||
task_list.remove(&task.descriptor());
|
||||
|
||||
state = State::PickNewTask;
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user