wasmrun 0.19.0

A WebAssembly Runtime
use std::collections::VecDeque;
use std::sync::{Arc, Mutex};

use super::microkernel::Pid;

#[allow(dead_code)]
pub struct ProcessScheduler {
    ready_queue: Arc<Mutex<VecDeque<Pid>>>,
    current_process: Arc<Mutex<Option<Pid>>>,
    time_slice_ms: u64,
}

impl Default for ProcessScheduler {
    fn default() -> Self {
        Self::new()
    }
}

#[allow(dead_code)]
impl ProcessScheduler {
    pub fn new() -> Self {
        Self {
            ready_queue: Arc::new(Mutex::new(VecDeque::new())),
            current_process: Arc::new(Mutex::new(None)),
            time_slice_ms: 100,
        }
    }

    pub fn add_process(&self, pid: Pid) {
        let mut queue = self.ready_queue.lock().unwrap();
        queue.push_back(pid);
    }

    pub fn remove_process(&self, pid: Pid) {
        let mut queue = self.ready_queue.lock().unwrap();
        queue.retain(|&p| p != pid);

        let mut current = self.current_process.lock().unwrap();
        if *current == Some(pid) {
            *current = None;
        }
    }

    pub fn schedule_next(&self) -> Option<Pid> {
        let mut queue = self.ready_queue.lock().unwrap();
        let mut current = self.current_process.lock().unwrap();

        if let Some(current_pid) = *current {
            queue.push_back(current_pid);
        }

        let next_pid = queue.pop_front();
        *current = next_pid;
        next_pid
    }

    pub fn get_current(&self) -> Option<Pid> {
        *self.current_process.lock().unwrap()
    }

    pub fn get_time_slice(&self) -> u64 {
        self.time_slice_ms
    }

    pub fn set_time_slice(&mut self, ms: u64) {
        self.time_slice_ms = ms;
    }

    pub fn queue_size(&self) -> usize {
        self.ready_queue.lock().unwrap().len()
    }

    pub fn block_current(&self) -> Option<Pid> {
        let mut current = self.current_process.lock().unwrap();
        let blocked_pid = *current;
        *current = None;
        blocked_pid
    }

    pub fn unblock_process(&self, pid: Pid) {
        self.add_process(pid);
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_scheduler_creation() {
        let scheduler = ProcessScheduler::new();
        assert_eq!(scheduler.queue_size(), 0);
        assert_eq!(scheduler.get_current(), None);
    }

    #[test]
    fn test_add_process() {
        let scheduler = ProcessScheduler::new();
        scheduler.add_process(1);
        scheduler.add_process(2);
        assert_eq!(scheduler.queue_size(), 2);
    }

    #[test]
    fn test_schedule_next() {
        let scheduler = ProcessScheduler::new();
        scheduler.add_process(1);
        scheduler.add_process(2);

        let next = scheduler.schedule_next();
        assert_eq!(next, Some(1));
        assert_eq!(scheduler.get_current(), Some(1));
    }

    #[test]
    fn test_round_robin() {
        let scheduler = ProcessScheduler::new();
        scheduler.add_process(1);
        scheduler.add_process(2);
        scheduler.add_process(3);

        assert_eq!(scheduler.schedule_next(), Some(1));
        assert_eq!(scheduler.schedule_next(), Some(2));
        assert_eq!(scheduler.schedule_next(), Some(3));
        assert_eq!(scheduler.schedule_next(), Some(1));
    }

    #[test]
    fn test_remove_process() {
        let scheduler = ProcessScheduler::new();
        scheduler.add_process(1);
        scheduler.add_process(2);
        scheduler.remove_process(1);

        assert_eq!(scheduler.queue_size(), 1);
        assert_eq!(scheduler.schedule_next(), Some(2));
    }

    #[test]
    fn test_block_unblock() {
        let scheduler = ProcessScheduler::new();
        scheduler.add_process(1);
        scheduler.schedule_next();

        let blocked = scheduler.block_current();
        assert_eq!(blocked, Some(1));
        assert_eq!(scheduler.get_current(), None);

        scheduler.unblock_process(1);
        assert_eq!(scheduler.queue_size(), 1);
    }
}