summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDanny Holman <dholman@gymli.org>2024-03-28 22:00:16 -0500
committerDanny Holman <dholman@gymli.org>2024-03-28 22:00:16 -0500
commitdb684b8653d93f4a374d8d692bb0afb31db67987 (patch)
tree83dc7939470b4c9302538fbf220c7a02fc249a51
parent3b66779d9a8325c77c6cfbf1565885f98da5378f (diff)
kernel: add a basic thread scheduler
Add a basic thread scheduler. This should allow the kernel to schedule threads according to the round robin algorithm. Signed-off-by: Danny Holman <dholman@gymli.org>
-rw-r--r--Makefile1
-rw-r--r--arch/i386/kernel/switch_thread.s28
-rw-r--r--arch/i386/make.config2
-rw-r--r--include/kernel/sched.h27
-rw-r--r--kernel/sched.c64
5 files changed, 122 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index 874f614..043e883 100644
--- a/Makefile
+++ b/Makefile
@@ -29,6 +29,7 @@ KERNEL_OBJS=$(KERNEL_ARCH_OBJS) \
kernel/string.o \
kernel/io.o \
kernel/panic.o \
+ kernel/sched.o \
OBJS=$(ARCHDIR)/boot/crti.o \
$(ARCHDIR)/crtbegin.o \
diff --git a/arch/i386/kernel/switch_thread.s b/arch/i386/kernel/switch_thread.s
new file mode 100644
index 0000000..f1168d5
--- /dev/null
+++ b/arch/i386/kernel/switch_thread.s
@@ -0,0 +1,28 @@
+.global switch_thread
+.type switch_thread, @function
+switch_thread:
+ pushl %ebp
+ movl %esp, %ebp
+
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+ pushl %ebp
+
+ movl 8(%ebp), %esi
+ movl 12(%ebp), %edi
+
+ movl %esp, (%edi);
+ movl %cr3, %ecx
+ movl %ecx, 4(%edi)
+
+ movl (%esi), %esp
+ movl 4(%esi), %ecx
+ movl %ecx, %cr3
+
+ popl %ebp
+ popl %edi
+ popl %esi
+ popl %ebx
+ popl %ebp
+ ret
diff --git a/arch/i386/make.config b/arch/i386/make.config
index 8499f1a..d4d98a7 100644
--- a/arch/i386/make.config
+++ b/arch/i386/make.config
@@ -17,3 +17,5 @@ KERNEL_ARCH_OBJS=$(ARCHDIR)/boot/boot.o \
$(ARCHDIR)/kernel/paging.o \
$(ARCHDIR)/kernel/pmem.o \
$(ARCHDIR)/kernel/kmalloc.o \
+ $(ARCHDIR)/kernel/jump_userspace.o \
+ $(ARCHDIR)/kernel/switch_thread.o \
diff --git a/include/kernel/sched.h b/include/kernel/sched.h
new file mode 100644
index 0000000..fef36b8
--- /dev/null
+++ b/include/kernel/sched.h
@@ -0,0 +1,27 @@
+#ifndef KERNEL_SCHED_H
+#define KERNEL_SCHED_H
+
+#include <kernel/asm.h>
+#include <kernel/data/list.h>
+
+#define THREAD_READY 0
+#define THREAD_RUNNING 1
+#define THREAD_WAIT 2
+
+struct task_block {
+ unsigned int pid;
+ unsigned int parent_pid;
+ int nice;
+ unsigned int num_threads;
+ struct thread_block *threads;
+ struct list_head list;
+};
+
+void sched_init(void);
+void schedule_next(void);
+
+struct task_block* init_task(int nice, unsigned int ppid);
+void schedule_thread(struct thread_block *thread);
+void switch_thread(struct thread_block *old, struct thread_block *new);
+
+#endif
diff --git a/kernel/sched.c b/kernel/sched.c
new file mode 100644
index 0000000..8aab675
--- /dev/null
+++ b/kernel/sched.c
@@ -0,0 +1,64 @@
+#include <kernel/sched.h>
+#include <kernel/container_of.h>
+#include <kernel/data/list.h>
+#include <kernel/string.h>
+#include <kernel/kmalloc.h>
+#include <stddef.h>
+
+static struct list_head *ready_queue;
+static struct list_head *wait_queue;
+
+static struct task_block *cur = NULL;
+static long int next_id = 1;
+
+static void _enqueue(struct list_head *queue, struct task_block *task) {
+ struct list_head *temp = queue;
+ while (temp->next != NULL)
+ temp = temp->next;
+ list_add(&task->list, temp);
+}
+
+static struct task_block* _dequeue(struct list_head *queue) {
+ if (queue->next == NULL)
+ return NULL;
+ struct list_head *temp = queue->next;
+ list_del(temp);
+ struct task_block *ret = container_of(temp, struct task_block, list);
+ return ret;
+}
+
+void sched_init(void) {
+ ready_queue = kmalloc(sizeof(struct list_head));
+ wait_queue = kmalloc(sizeof(struct list_head));
+ struct task_block *boot_task = init_task(0, 0);
+ boot_task->threads->state = THREAD_RUNNING;
+ cur = boot_task;
+
+ switch_thread(boot_task->threads, boot_task->threads);
+}
+
+void schedule_next(void) {
+ struct task_block *task = _dequeue(ready_queue);
+ if (task == NULL)
+ return;
+ if (cur != NULL)
+ _enqueue(ready_queue, cur);
+ disable_ints();
+ switch_thread(cur->threads, task->threads);
+ enable_ints();
+ task->threads->state = THREAD_RUNNING;
+ cur->threads->state = THREAD_READY;
+ cur = task;
+}
+
+struct task_block* init_task(int nice, unsigned int ppid) {
+ struct task_block *ret = kmalloc(sizeof(struct task_block));
+ ret->pid = next_id++;
+ ret->parent_pid = ppid;
+ ret->nice = nice;
+ ret->num_threads = 1;
+ ret->threads = kmalloc(sizeof(struct thread_block));
+ ret->threads->tid = ret->pid;
+ ret->threads->tgid = ret->pid;
+ return ret;
+}