tscs37's Blog

Boring Task Scheduling

I’ve recently dived into OS Development to learn a bit of Rust. It’s probably a bit like wanting to learn how to use a hammer so you build a skyscraper or some equally insane level of yakshaving.

One of the goals I set for any progress I make on my Kernel/OS is to make boring, simple and safe choices. For example, I don’t plan to make a microkernel, such things are complicated and slow. Rather, I will build a modular kernel, a much more robust construction which doesn’t suffer any overhead from IPC or Syscalls.

One of the core tasks a kernel must solve is Task Scheduling, a.k.a. “What do?”. The complicated answer is to have the poor kernel do the scheduling all on it’s own. However, I think I found a workaround.

By reducing the Kernel to a sort of meta-scheduler the amount of code in the kernel responsible for task scheduling is reduced to a minimum. The meta-scheduler only keeps track of two things; a list of all tasks the system knows about and the next task to run. In pseudo-code (aka Rust but without the lifetimes);

struct TaskScheduler {
    tasks: BTree<u64, Task>,
    next_task: u64,
}

impl TaskScheduler {
    pub fn run_next_task(&self) {
        let task_to_run = self.next_task;
        self.next_task = 0;
        self.run(task_to_run);
    }
}

As you might have noticed, this implementation will always run 0, it doesn’t set any other next_task value at all. But how does it work then?

The solution for this problem is to have Task 0 be the actual Task Scheduler. So everytime we don’t have anything to run, we run the task scheduler. And after we run something, we also run the task scheduler. We run the task scheduler at any time we don’t run anything else. The variable next_task must then only be exposed to it.

This can either happen through compiling the task scheduler into the kernel or alternatively by exposing the TaskScheduler struct to kernel modules.

How does the actual task scheduler look then? No idea to be honest, it could have a wide range of interesting and since the task scheduler is also only a task, it simplifies the OS model greatly. I think this is a great approach to handling tasks in a modular kernel, compared to putting the entire scheduler into the kernel itself.