Skip to content

Commit

Permalink
refactor: make Process immutable (wip)
Browse files Browse the repository at this point in the history
  • Loading branch information
llenotre committed Nov 11, 2024
1 parent 44349b9 commit 42b7686
Show file tree
Hide file tree
Showing 60 changed files with 278 additions and 411 deletions.
6 changes: 2 additions & 4 deletions kernel/src/device/tty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@ impl TTYDeviceHandle {
///
/// This function must be called before performing the read operation.
fn check_sigttin(&self, tty: &TTYDisplay) -> EResult<()> {
let proc_mutex = Process::current();
let mut proc = proc_mutex.lock();
let proc = Process::current();
if proc.pgid == tty.get_pgrp() {
return Ok(());
}
Expand All @@ -73,8 +72,7 @@ impl TTYDeviceHandle {
///
/// This function must be called before performing the write operation.
fn check_sigttou(&self, tty: &TTYDisplay) -> EResult<()> {
let proc_mutex = Process::current();
let mut proc = proc_mutex.lock();
let proc = Process::current();
if tty.get_termios().c_lflag & termios::consts::TOSTOP == 0 {
return Ok(());
}
Expand Down
89 changes: 27 additions & 62 deletions kernel/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,10 @@

use crate::{
arch::x86::{idt, idt::IntFrame, pic},
crypto::{rand, rand::EntropyPool},
crypto::rand,
process,
};
use core::{ffi::c_void, intrinsics::unlikely, ptr::NonNull};
use utils::{boxed::Box, collections::vec::Vec, errno::AllocResult, lock::IntMutex};
use utils::{collections::vec::Vec, errno::AllocResult, lock::IntMutex};

/// The list of interrupt error messages ordered by index of the corresponding
/// interrupt vector.
Expand All @@ -47,7 +46,7 @@ static ERROR_MESSAGES: &[&str] = &[
"Page Fault",
"Unknown",
"x87 Floating-Point Exception",
"Alignement Check",
"Alignment Check",
"Machine Check",
"SIMD Floating-Point Exception",
"Virtualization Exception",
Expand All @@ -64,16 +63,6 @@ static ERROR_MESSAGES: &[&str] = &[
"Unknown",
];

/// Returns the error message corresponding to the given interrupt vector index
/// `i`.
fn get_error_message(i: u32) -> &'static str {
if (i as usize) < ERROR_MESSAGES.len() {
ERROR_MESSAGES[i as usize]
} else {
"Unknown"
}
}

/// The action to execute after the interrupt handler has returned.
pub enum CallbackResult {
/// Executes remaining callbacks for the interrupt.
Expand All @@ -94,7 +83,7 @@ pub enum CallbackResult {
/// - `ring` tells the ring at which the code was running.
///
/// The return value tells which action to perform next.
type CallbackWrapper = Box<dyn FnMut(u32, u32, &mut IntFrame, u8) -> CallbackResult>;
pub type Callback = fn(u32, u32, &mut IntFrame, u8) -> CallbackResult;

/// Structure used to detect whenever the object owning the callback is
/// destroyed, allowing to unregister it automatically.
Expand All @@ -103,7 +92,7 @@ pub struct CallbackHook {
/// The id of the interrupt the callback is bound to.
id: u32,
/// The pointer of the callback.
ptr: NonNull<c_void>,
callback: Callback,
}

impl Drop for CallbackHook {
Expand All @@ -113,7 +102,7 @@ impl Drop for CallbackHook {
let i = vec
.iter()
.enumerate()
.find(|(_, c)| c.as_ptr() as *mut c_void == self.ptr.as_ptr())
.find(|(_, c)| **c == self.callback)
.map(|(i, _)| i);
if let Some(i) = i {
vec.remove(i);
Expand All @@ -122,15 +111,14 @@ impl Drop for CallbackHook {
}

/// The default value for `CALLBACKS`.
#[allow(clippy::declare_interior_mutable_const)]
const CALLBACKS_INIT: IntMutex<Vec<CallbackWrapper>> = IntMutex::new(Vec::new());
const CALLBACKS_INIT: IntMutex<Vec<Callback>> = IntMutex::new(Vec::new());
/// List containing vectors that store callbacks for every interrupt watchdogs.
static CALLBACKS: [IntMutex<Vec<CallbackWrapper>>; idt::ENTRIES_COUNT as _] =
static CALLBACKS: [IntMutex<Vec<Callback>>; idt::ENTRIES_COUNT as _] =
[CALLBACKS_INIT; idt::ENTRIES_COUNT as _];

/// Registers the given callback and returns a reference to it.
///
/// The latest registered callback is executed last. Thus, callback that are registered before can
/// The latest registered callback is executed last. Thus, callback that are registered first can
/// prevent next callbacks from being executed.
///
/// Arguments:
Expand All @@ -140,74 +128,51 @@ static CALLBACKS: [IntMutex<Vec<CallbackWrapper>>; idt::ENTRIES_COUNT as _] =
/// If an allocation fails, the function shall return an error.
///
/// If the provided ID is invalid, the function returns `None`.
pub fn register_callback<C>(id: u32, callback: C) -> AllocResult<Option<CallbackHook>>
where
C: 'static + FnMut(u32, u32, &mut IntFrame, u8) -> CallbackResult,
{
if unlikely(id as usize >= CALLBACKS.len()) {
pub fn register_callback(id: u32, callback: Callback) -> AllocResult<Option<CallbackHook>> {
let Some(callbacks) = CALLBACKS.get(id as usize) else {
return Ok(None);
}

let mut vec = CALLBACKS[id as usize].lock();
let b = Box::new(callback)?;
let ptr = b.as_ptr();
vec.push(b)?;

};
let mut vec = callbacks.lock();
vec.push(callback)?;
Ok(Some(CallbackHook {
id,
ptr: NonNull::new(ptr as _).unwrap(),
callback,
}))
}

/// Unlocks the callback vector with id `id`. This function is to be used in
/// case of an event callback that never returns.
///
/// This function does not re-enable interruptions.
///
/// # Safety
///
/// This function is marked as unsafe since it may lead to concurrency issues if
/// not used properly. It must be called from the same CPU core as the one that
/// locked the mutex since unlocking changes the interrupt flag.
#[no_mangle]
pub unsafe extern "C" fn unlock_callbacks(id: usize) {
CALLBACKS[id].unlock(false);
}

/// Feeds the entropy pool using the given data.
fn feed_entropy<T>(pool: &mut EntropyPool, val: &T) {
let buff = utils::bytes::as_bytes(val);
pool.write(buff);
}

/// Called whenever an interruption is triggered.
///
/// `frame` is the stack frame of the interruption, with general purpose registers saved.
#[no_mangle]
extern "C" fn interrupt_handler(frame: &mut IntFrame) {
// Feed entropy pool
{
let buf = utils::bytes::as_bytes(frame);
let mut pool = rand::ENTROPY_POOL.lock();
if let Some(pool) = &mut *pool {
feed_entropy(pool, frame);
pool.write(buf);
}
}
let id = frame.int as u32;
let ring = (frame.cs & 0b11) as u8;
let code = frame.code as u32;
// Call corresponding callbacks
let mut callbacks = CALLBACKS[id as usize].lock();
for c in callbacks.iter_mut() {
let res = c(id, code, frame, ring);
let callbacks = &CALLBACKS[id as usize];
let mut i = 0;
while let Some(callback) = callbacks.lock().get(i).cloned() {
i += 1;
let res = callback(id, code, frame, ring);
match res {
CallbackResult::Continue => {}
CallbackResult::Panic => panic!("{}, code: {code:x}", get_error_message(id)),
CallbackResult::Panic => {
let error = ERROR_MESSAGES.get(id as usize).unwrap_or(&"Unknown");
panic!("{error}, code: {code:x}");
}
}
}
// Unlock to avoid deadlocks
// If not a hardware exception, send EOI
if id >= ERROR_MESSAGES.len() as u32 {
pic::end_of_interrupt((id - ERROR_MESSAGES.len() as u32) as _);
}
drop(callbacks);
process::yield_current(ring, frame);
}
3 changes: 1 addition & 2 deletions kernel/src/file/fs/proc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ use version::Version;
/// If the process does not exist, the function returns `(0, 0)`.
fn get_proc_owner(pid: Pid) -> (Uid, Gid) {
Process::get_by_pid(pid)
.map(|proc_mutex| {
let proc = proc_mutex.lock();
.map(|proc| {
let uid = proc.access_profile.euid;
let gid = proc.access_profile.egid;
(uid, gid)
Expand Down
3 changes: 1 addition & 2 deletions kernel/src/file/fs/proc/proc_dir/cmdline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ impl NodeOps for Cmdline {
}

fn read_content(&self, _loc: &FileLocation, off: u64, buf: &mut [u8]) -> EResult<usize> {
let proc_mutex = Process::get_by_pid(self.0).ok_or_else(|| errno!(ENOENT))?;
let proc = proc_mutex.lock();
let proc = Process::get_by_pid(self.0).ok_or_else(|| errno!(ENOENT))?;
format_content!(off, buf, "{}", CmdlineDisp(&proc))
}
}
1 change: 0 additions & 1 deletion kernel/src/file/fs/proc/proc_dir/cwd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ impl NodeOps for Cwd {
let cwd = vfs::Entry::get_path(
&Process::get_by_pid(self.0)
.ok_or_else(|| errno!(ENOENT))?
.lock()
.cwd,
)?;
format_content!(off, buf, "{cwd}")
Expand Down
3 changes: 1 addition & 2 deletions kernel/src/file/fs/proc/proc_dir/environ.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ impl NodeOps for Environ {
}

fn read_content(&self, _loc: &FileLocation, off: u64, buf: &mut [u8]) -> EResult<usize> {
let proc_mutex = Process::get_by_pid(self.0).ok_or_else(|| errno!(ENOENT))?;
let proc = proc_mutex.lock();
let proc = Process::get_by_pid(self.0).ok_or_else(|| errno!(ENOENT))?;
format_content!(off, buf, "{}", proc.envp)
}
}
3 changes: 1 addition & 2 deletions kernel/src/file/fs/proc/proc_dir/exe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ impl NodeOps for Exe {
}

fn read_content(&self, _loc: &FileLocation, off: u64, buf: &mut [u8]) -> EResult<usize> {
let proc_mutex = Process::get_by_pid(self.0).ok_or_else(|| errno!(ENOENT))?;
let proc = proc_mutex.lock();
let proc = Process::get_by_pid(self.0).ok_or_else(|| errno!(ENOENT))?;
format_content!(off, buf, "{}", proc.exec_path)
}
}
3 changes: 1 addition & 2 deletions kernel/src/file/fs/proc/proc_dir/stat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,7 @@ impl NodeOps for StatNode {
}

fn read_content(&self, _loc: &FileLocation, off: u64, buf: &mut [u8]) -> EResult<usize> {
let proc_mutex = Process::get_by_pid(self.0).ok_or_else(|| errno!(ENOENT))?;
let proc = proc_mutex.lock();
let proc = Process::get_by_pid(self.0).ok_or_else(|| errno!(ENOENT))?;
format_content!(off, buf, "{}", StatDisp(&proc))
}
}
3 changes: 1 addition & 2 deletions kernel/src/file/fs/proc/proc_dir/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,7 @@ impl NodeOps for Status {
}

fn read_content(&self, _loc: &FileLocation, off: u64, buf: &mut [u8]) -> EResult<usize> {
let proc_mutex = Process::get_by_pid(self.0).ok_or_else(|| errno!(ENOENT))?;
let proc = proc_mutex.lock();
let proc = Process::get_by_pid(self.0).ok_or_else(|| errno!(ENOENT))?;
format_content!(off, buf, "{}", StatusDisp(&proc))
}
}
2 changes: 1 addition & 1 deletion kernel/src/file/fs/proc/self_link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl NodeOps for SelfNode {
}

fn read_content(&self, _loc: &FileLocation, off: u64, buf: &mut [u8]) -> EResult<usize> {
let pid = Process::current().lock().get_pid();
let pid = Process::current().get_pid();
format_content!(off, buf, "{pid}")
}
}
2 changes: 1 addition & 1 deletion kernel/src/file/pipe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ impl FileOps for PipeBuffer {
let len = self.wr_queue.wait_until(|| {
let mut inner = self.inner.lock();
if inner.readers == 0 {
Process::current().lock().kill(Signal::SIGPIPE);
Process::current().kill(Signal::SIGPIPE);
return Some(Err(errno!(EPIPE)));
}
let len = inner.buffer.write(buf);
Expand Down
10 changes: 4 additions & 6 deletions kernel/src/file/wait_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ impl WaitQueue {
}
// Queue
{
let proc_mutex = Process::current();
let mut proc = proc_mutex.lock();
let proc = Process::current();
self.0.lock().push(proc.get_pid())?;
proc.set_state(process::State::Sleeping);
}
Expand All @@ -66,8 +65,7 @@ impl WaitQueue {
// something else) Execution resumes. If the current process had received a signal,
// return
{
let proc_mutex = Process::current();
let mut proc = proc_mutex.lock();
let proc = Process::current();
if proc.next_signal(true).is_some() {
return Err(errno!(EINTR));
}
Expand All @@ -93,7 +91,7 @@ impl WaitQueue {
};
break proc;
};
proc.lock().wake();
proc.wake();
}

/// Wakes all processes.
Expand All @@ -104,7 +102,7 @@ impl WaitQueue {
// Process does not exist, try next
continue;
};
proc.lock().wake();
proc.wake();
}
}
}
5 changes: 2 additions & 3 deletions kernel/src/kernel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,8 @@ fn init(init_path: String) -> EResult<()> {
]?,
},
)?;
let proc_mutex = Process::init()?;
let mut proc = proc_mutex.lock();
exec(&mut proc, &mut frame, program_image)?;
let proc = Process::init()?;
exec(&proc, &mut frame, program_image)?;
}
switch::init(&frame);
}
Expand Down
10 changes: 7 additions & 3 deletions kernel/src/process/exec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,12 @@ pub fn build_image(file: &vfs::Entry, info: ExecInfo) -> EResult<ProgramImage> {
///
/// `frame` is the interrupt frame of the current content. The function sets the appropriate values
/// for each register so that the execution beings when the interrupt handler returns.
pub fn exec(proc: &mut Process, frame: &mut IntFrame, image: ProgramImage) -> EResult<()> {
pub fn exec(proc: &Process, frame: &mut IntFrame, image: ProgramImage) -> EResult<()> {
// Note: the implementation makes sure all fallible operations are done before the ones that
// cannot be undone
proc.argv = Arc::new(image.argv)?;
proc.envp = Arc::new(image.envp)?;
// TODO Set exec path
// Set the new memory space to the process
proc.set_mem_space(Some(Arc::new(IntMutex::new(image.mem_space))?));
// Duplicate the file descriptor table
proc.file_descriptors = proc
.file_descriptors
Expand All @@ -110,6 +110,10 @@ pub fn exec(proc: &mut Process, frame: &mut IntFrame, image: ProgramImage) -> ER
Ok(Arc::new(Mutex::new(new_fds))?)
})
.transpose()?;
// Set the new memory space to the process
let mem_space = Arc::new(IntMutex::new(image.mem_space))?;
mem_space.lock().bind();
proc.mem_space = Some(mem_space);
// Reset signals
proc.signal_handlers.lock().fill(SignalHandler::Default);
proc.reset_vfork();
Expand Down
Loading

0 comments on commit 42b7686

Please sign in to comment.