Skip to content

Commit

Permalink
scheduler/process: Implement kill()
Browse files Browse the repository at this point in the history
  • Loading branch information
fruhland committed May 31, 2024
1 parent 6aad7eb commit 4463893
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 33 deletions.
10 changes: 5 additions & 5 deletions os/kernel/src/banner.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
 ____  _____ ____ _____ # Version : {}
 / __ \ |__ / / __ \ / ___/ # Git Ref : {} - {}
 / / / / /_ <  / / / / \__ \  # Build Date : {}
 / /_/ /  ___/ / / /_/ / ___/ /  # Compiler : {}
/_____/ /____/ \____/ /____/  # Bootloader : {}
 ____  ____ ____ _____ # Version : {}
 / __ \ |_ / / __ \ / ___/ # Git Ref : {} - {}
 / / / / _/_ <  / / / / \__ \  # Build Date : {}
 / /_/ / /____/ / /_/ / ___/ /  # Compiler : {}
/_____/  \____/ /____/  # Bootloader : {}
33 changes: 31 additions & 2 deletions os/kernel/src/process/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,28 @@ impl ProcessManager {
}
}

pub fn exit(&mut self, id: usize) {
pub fn exit(&mut self, process_id: usize) {
let index = self.active_processes.iter()
.position(|process| process.id == id)
.position(|process| process.id == process_id)
.expect("Process: Trying to exit a non-existent process!");

let process = Arc::clone(&self.active_processes[index]);
process.kill_all_threads_but_current();

self.active_processes.swap_remove(index);
self.exited_processes.push(process);
}

pub fn kill(&mut self, process_id: usize) {
let index = self.active_processes.iter()
.position(|process| process.id == process_id)
.expect("Process: Trying to kill a non-existent process!");

let process = Arc::clone(&self.active_processes[index]);
for thread_id in process.thread_ids() {
scheduler().kill(thread_id);
}

self.active_processes.swap_remove(index);
self.exited_processes.push(process);
}
Expand Down Expand Up @@ -151,4 +167,17 @@ impl Process {
pub fn exit(&self) {
process_manager().write().exit(self.id);
}

pub fn thread_ids(&self) -> Vec<usize> {
scheduler().active_thread_ids().iter()
.filter(|&&thread_id| {
scheduler().thread(thread_id).is_some_and(|thread| thread.process().id() == self.id)
}).copied().collect()
}

fn kill_all_threads_but_current(&self) {
self.thread_ids().iter()
.filter(|&&thread_id| thread_id != scheduler().current_thread().id())
.for_each(|&thread_id| scheduler().kill(thread_id));
}
}
84 changes: 58 additions & 26 deletions os/kernel/src/process/scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ impl ReadyState {
}

pub struct Scheduler {
state: Mutex<ReadyState>,
ready_state: Mutex<ReadyState>,
sleep_list: Mutex<Vec<(Rc<Thread>, usize)>>,
join_map: Mutex<Map<usize, Vec<Rc<Thread>>>>
}
Expand All @@ -40,12 +40,12 @@ unsafe impl Sync for Scheduler {}
/// Called from assembly code, after the thread has been switched
#[no_mangle]
pub unsafe extern "C" fn unlock_scheduler() {
scheduler().state.force_unlock();
scheduler().ready_state.force_unlock();
}

impl Scheduler {
pub fn new() -> Self {
Self { state: Mutex::new(ReadyState::new()), sleep_list: Mutex::new(Vec::new()), join_map: Mutex::new(Map::new()) }
Self { ready_state: Mutex::new(ReadyState::new()), sleep_list: Mutex::new(Vec::new()), join_map: Mutex::new(Map::new()) }
}

pub fn set_init(&self) {
Expand All @@ -65,6 +65,13 @@ impl Scheduler {
return Scheduler::current(&state);
}

pub fn thread(&self, thread_id: usize) -> Option<Rc<Thread>> {
self.ready_state.lock()
.ready_queue.iter().find(|thread| {
thread.id() == thread_id
}).cloned()
}

pub fn start(&self) {
let mut state = self.get_ready_state();
state.current_thread = state.ready_queue.pop_back();
Expand Down Expand Up @@ -113,7 +120,7 @@ impl Scheduler {
}

fn switch_thread(&self, interrupt: bool) {
if let Some(mut state) = self.state.try_lock() {
if let Some(mut state) = self.ready_state.try_lock() {
if !state.initialized {
return;
}
Expand Down Expand Up @@ -174,38 +181,50 @@ impl Scheduler {
}

pub fn exit(&self) {
let mut state;
let mut ready_state;
let current;

{ // Execute in own block, so that join_map is released automatically when it is not needed anymore
let mut join_map;

// See 'ready()' for comments on this loop
loop {
let state_mutex = self.get_ready_state();
let join_map_option = self.join_map.try_lock();

if join_map_option.is_some() {
state = state_mutex;
join_map = join_map_option.unwrap();
break;
} else {
self.switch_thread_no_interrupt();
}
}

current = Scheduler::current(&state);
{ // Execute in own block, so that join_map is released automatically (block() does not return)
let state = self.get_ready_state_and_join_map();
ready_state = state.0;
let mut join_map = state.1;

current = Scheduler::current(&ready_state);
let join_list = join_map.get_mut(&current.id()).expect(format!("Scheduler: Missing join_map entry for thread id {}!", current.id()).as_str());

for thread in join_list {
state.ready_queue.push_front(Rc::clone(thread));
ready_state.ready_queue.push_front(Rc::clone(thread));
}

join_map.remove(&current.id());
}

drop(current); // Decrease Rc manually, because block() does not return
self.block(&mut state);
self.block(&mut ready_state);
}

pub fn kill(&self, thread_id: usize) {
{ // Check if current thread tries to kill itself (illegal)
let ready_state = self.get_ready_state();
let current = Scheduler::current(&ready_state);

if current.id() == thread_id {
panic!("Scheduler: A thread cannot kill itself!");
}
}

let state = self.get_ready_state_and_join_map();
let mut ready_state = state.0;
let mut join_map = state.1;

let join_list = join_map.get_mut(&thread_id).expect(format!("Scheduler: Missing join_map entry for thread id {}!", thread_id).as_str());

for thread in join_list {
ready_state.ready_queue.push_front(Rc::clone(thread));
}

join_map.remove(&thread_id);
ready_state.ready_queue.retain(|thread| thread.id() != thread_id);
}

fn block(&self, state: &mut ReadyState) {
Expand Down Expand Up @@ -262,7 +281,7 @@ impl Scheduler {
// Otherwise, a deadlock may occur: Since we are holding the ready queue lock,
// the scheduler won't switch threads anymore, and none of the locks will ever be released
loop {
let state_tmp = self.state.lock();
let state_tmp = self.ready_state.lock();
if allocator().is_locked() {
continue;
}
Expand All @@ -273,4 +292,17 @@ impl Scheduler {

return state;
}

fn get_ready_state_and_join_map(&self) -> (MutexGuard<ReadyState>, MutexGuard<Map<usize, Vec<Rc<Thread>>>>) {
loop {
let ready_state = self.get_ready_state();
let join_map = self.join_map.try_lock();

if join_map.is_some() {
return (ready_state, join_map.unwrap());
} else {
self.switch_thread_no_interrupt();
}
}
}
}

0 comments on commit 4463893

Please sign in to comment.