Skip to content

Commit

Permalink
Refactor context switching. NFCI (#61)
Browse files Browse the repository at this point in the history
* Refactor context switching. NFCI

* Fix compile errors

* Embed the symbol table into unit testing kernel images

* Allow clippy::print_with_newline
  • Loading branch information
nuta authored Nov 7, 2021
1 parent 52b15db commit 9941f4b
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 41 deletions.
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,13 @@ CARGOFLAGS += -Z build-std=core,alloc -Z build-std-features=compiler-builtins-me
CARGOFLAGS += --target $(target_json)
CARGOFLAGS += $(if $(RELEASE),--release,)
TESTCARGOFLAGS += --package kerla -Z unstable-options
TESTCARGOFLAGS += --config "target.$(ARCH).runner = '$(PYTHON3) $(topdir)/tools/run-qemu.py --arch $(ARCH)'"
TESTCARGOFLAGS += --config "target.$(ARCH).runner = './tools/run-unittests.sh'"
WATCHFLAGS += --clear
export CARGO_FROM_MAKE=1
export INITRAMFS_PATH
export ARCH
export PYTHON3
export NM

#
# Build Commands
Expand Down
10 changes: 1 addition & 9 deletions kernel/arch/x64/interrupt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
timer::handle_timer_irq,
};

use x86::{controlregs::cr2, current::rflags::RFlags, irq::*};
use x86::{controlregs::cr2, irq::*};

/// The interrupt stack frame.
#[derive(Debug, Copy, Clone)]
Expand Down Expand Up @@ -195,11 +195,3 @@ unsafe extern "C" fn x64_handle_interrupt(vec: u8, frame: *const InterruptFrame)
}
}
}

pub unsafe fn enable_interrupt() {
asm!("sti");
}

pub fn is_interrupt_enabled() -> bool {
x86::current::rflags::read().contains(RFlags::FLAGS_IF)
}
1 change: 0 additions & 1 deletion kernel/arch/x64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ pub use arch_prctl::arch_prctl;
pub use backtrace::Backtrace;
pub use boot::init;
pub use idle::{halt, idle};
pub use interrupt::{enable_interrupt, is_interrupt_enabled};
pub use ioapic::enable_irq;
pub use lock::{SpinLock, SpinLockGuard};
pub use page_table::{PageFaultReason, PageTable};
Expand Down
7 changes: 4 additions & 3 deletions kernel/printk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use alloc::boxed::Box;
use arrayvec::ArrayVec;
use kerla_utils::ring_buffer::RingBuffer;

use crate::arch::SpinLock;
use crate::arch::{print_str, printchar, Backtrace, VAddr};
use crate::lang_items::PANICKED;
use core::mem::size_of;
Expand All @@ -12,8 +11,10 @@ use core::{fmt, slice};
pub struct Printer;

pub const KERNEL_LOG_BUF_SIZE: usize = 8192;
pub static KERNEL_LOG_BUF: SpinLock<RingBuffer<u8, KERNEL_LOG_BUF_SIZE>> =
SpinLock::new(RingBuffer::new());
// We use spin::Mutex here because SpinLock's debugging features may cause a
// problem (capturing a backtrace requires memory allocation).
pub static KERNEL_LOG_BUF: spin::Mutex<RingBuffer<u8, KERNEL_LOG_BUF_SIZE>> =
spin::Mutex::new(RingBuffer::new());

impl core::fmt::Write for Printer {
fn write_char(&mut self, c: char) -> core::fmt::Result {
Expand Down
27 changes: 10 additions & 17 deletions kernel/process/switch.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::*;
use crate::process::PId;
use crate::{
arch::{self, enable_interrupt, is_interrupt_enabled},
arch::{self},
process::process::PROCESSES,
};

Expand All @@ -11,10 +11,6 @@ use core::mem::{self};

/// Yields execution to another thread.
pub fn switch() {
// Save the current interrupt enable flag to restore it in the next execution
// of the currently running thread.
let interrupt_enabled = is_interrupt_enabled();

let prev = current_process().clone();
let prev_pid = prev.pid();
let prev_state = prev.state();
Expand Down Expand Up @@ -46,10 +42,17 @@ pub fn switch() {
lock.page_table().switch();
}

// Drop `next_thread` here because `switch_thread` won't return when the current
// process is being destroyed (e.g. by exit(2)) and it leads to a memory leak.
// Drop `prev` and `next` here because `switch_thread` won't return when the
// current process is being destroyed (e.g. by exit(2)).
//
// Since processes are referenced from at least the following two places,
// we can safely decrement reference counts without immediately drop here:
//
// - prev or next: they holds Arc<Process> (not &Arc<Process>).
// - Their parent processes's list of children.
//
// To cheat the borrow checker we do so by `Arc::decrement_strong_count`.
debug_assert!(Arc::strong_count(&prev) > 1);
debug_assert!(Arc::strong_count(&next) > 1);
unsafe {
Arc::decrement_strong_count(Arc::as_ptr(&prev));
Expand All @@ -64,14 +67,4 @@ pub fn switch() {
// reference count by `Arc::decrement_strong_count` above.
mem::forget(prev);
mem::forget(next);

// Now we're in the next thread. Release held locks and continue executing.

// Retstore the interrupt enable flag manually because lock guards
// (`prev` and `next`) that holds the flag state are `mem::forget`-ed.
if interrupt_enabled {
unsafe {
enable_interrupt();
}
}
}
20 changes: 10 additions & 10 deletions kernel/test_runner.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#![cfg(test)]
#![allow(clippy::print_with_newline)]

use crate::arch::*;
use core::panic::PanicInfo;
use core::sync::atomic::{AtomicBool, Ordering};
use core::sync::atomic::Ordering;

pub trait Testable {
fn run(&self);
Expand All @@ -15,7 +16,7 @@ where
fn run(&self) {
print!("{} ... ", core::any::type_name::<T>());
self();
println!("\x1b[92mok\x1b[0m");
print!("\x1b[92mok\x1b[0m\n");
}
}

Expand All @@ -24,8 +25,8 @@ pub fn run_tests(tests: &[&dyn Testable]) {
for test in tests {
test.run();
}
println!();
println!("\x1b[92mPassed all tests :)\x1b[0m\n");
print!("\n");
print!("\x1b[92mPassed all tests :)\x1b[0m\n");
}

pub fn end_tests() -> ! {
Expand All @@ -35,18 +36,17 @@ pub fn end_tests() -> ! {
loop {}
}

static ALREADY_PANICED: AtomicBool = AtomicBool::new(false);

#[cfg(test)]
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
if ALREADY_PANICED.load(Ordering::SeqCst) {
use crate::lang_items::PANICKED;

if PANICKED.load(Ordering::SeqCst) {
loop {}
}

ALREADY_PANICED.store(true, Ordering::SeqCst);

print!("\x1b[1;91mfail\x1b[0m\n{}\n", info);
PANICKED.store(true, Ordering::SeqCst);
print!("\x1b[1;91mfail\npanic: {}\x1b[0m", info);
semihosting_halt(ExitStatus::Failure);
loop {}
}
7 changes: 7 additions & 0 deletions tools/run-unittests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/sh
set -ue

executable="$1"
$NM $executable | rustfilt | awk '{ $2=""; print $0 }' > $executable.symbols
$PYTHON3 ../tools/embed-symbol-table.py $executable.symbols $executable
$PYTHON3 ../tools/run-qemu.py --arch $ARCH $executable

0 comments on commit 9941f4b

Please sign in to comment.