summaryrefslogtreecommitdiff
path: root/kc/core/task.c
diff options
context:
space:
mode:
authorAda Christine <adachristine18@gmail.com>2026-05-26 21:32:27 +0000
committerAda Christine <adachristine18@gmail.com>2026-05-26 21:32:27 +0000
commita10aabfcd52f702057316018cd7847ab2bfe4aa1 (patch)
treecc4652d2b602798934e8a48b4939cfb20eda1989 /kc/core/task.c
parent90c29fdde317c39384011a6ba97077c138f13ad6 (diff)
we're bringing kjarna back and not doing the crazy stuff with trying to have task management during efi. that was a bit extra.kjarna
Diffstat (limited to 'kc/core/task.c')
-rw-r--r--kc/core/task.c439
1 files changed, 240 insertions, 199 deletions
diff --git a/kc/core/task.c b/kc/core/task.c
index 3e0288d..a298a05 100644
--- a/kc/core/task.c
+++ b/kc/core/task.c
@@ -12,13 +12,9 @@
#include <stdbool.h>
#include <lib/elf.h>
-#include <lib/kstdio.h>
+#include <libc/stdio.h>
-static const size_t INTERRUPT_STACK_SIZE = 4096;
-static const size_t THREAD_SIZE = 16834;
-static const enum vm_alloc_flags ALLOC_FLAGS = VM_ALLOC_ANY|VM_ALLOC_ANONYMOUS;
-
-extern uint64_t *get_tss_rsp0(void);
+#include "arch_thread.h"
static void lock_scheduler(void);
static void unlock_scheduler(void);
@@ -27,7 +23,7 @@ static void unlock_preempt(void);
static void update_time(void);
-static struct kc_thread *create_thread(void (*thread_entry)(void));
+static struct kc_thread *create_thread(void *(*thread_f)(void *), void *p);
static void destroy_thread(struct kc_thread *thread);
static void set_thread(struct kc_thread *thread);
static void block_thread(enum kc_thread_status reason);
@@ -37,10 +33,6 @@ static void sleep_thread_until(uint64_t nanoseconds);
static int sleeping_thread_callback(uint64_t nanoseconds);
-static struct kc_thread *ready_thread_pop(void);
-static void ready_thread_push(struct kc_thread *thread);
-static void ready_thread_push_back(struct kc_thread *thread);
-
const struct timer_source * timesource;
/* static threads that are always present
@@ -50,130 +42,138 @@ static struct kc_thread *idle_thread;
// thread lists for the scheduler to manipulate
static struct kc_thread *current_thread;
-static struct kc_thread *first_ready_thread;
-static struct kc_thread *last_ready_thread;
-static struct kc_thread *sleeping_threads;
+
+struct thread_queue
+{
+ struct kc_thread
+ *first,
+ *last;
+};
+
+static void thread_queue_push(struct thread_queue *queue, struct kc_thread *thread);
+static void thread_queue_push_back(struct thread_queue *queue, struct kc_thread *thread);
+
+static void thread_queue_push(struct thread_queue *queue, struct kc_thread *thread)
+{
+ thread->next = queue->first;
+ queue->first = thread;
+
+ if (!queue->last)
+ {
+ thread_queue_push_back(queue, thread);
+ }
+}
+
+static void thread_queue_push_back(struct thread_queue *queue, struct kc_thread *thread)
+{
+ if (!queue->first)
+ {
+ thread_queue_push(queue, thread);
+ }
+ else if (queue->last)
+ {
+ queue->last->next = thread;
+ }
+
+ queue->last = thread;
+}
+
+struct kc_thread *thread_queue_pop(struct thread_queue *queue)
+{
+ if (!queue->first)
+ {
+ return nullptr;
+ }
+
+ struct kc_thread *thread = queue->first;
+ queue->first = thread->next;
+ thread->next = nullptr;
+ if (!queue->first)
+ {
+ queue->last = nullptr;
+ }
+
+ return thread;
+}
+
+bool thread_queue_any(struct thread_queue queue)
+{
+ return queue.first && queue.last;
+}
+
+static struct thread_queue ready_queue;
+static struct thread_queue sleep_queue;
+static struct thread_queue wait_queue;
static volatile atomic_uint_fast64_t preempt_switch_count = 0;
static volatile atomic_bool preempt_switch_flag = false;
-static void idle_thread_entry(void)
+static void *idle_thread_entry(void *)
{
- kprintf("idle thread started\n");
- unlock_scheduler();
-
- __asm__ ("sti");
+ printf("idle thread started\n");
+ __asm__ ("sti");
+
+
while (true)
{
__asm__ ("hlt;");
}
-}
-
-#define PS2INPUT 0x60
-#define PS2STATUS 0x64
-#define PS2STATUS_IBF 0x1
-static void keyboard_input_loop(void)
-{
- bool has_bytes = true;
- while (has_bytes)
- {
- has_bytes = inb(PS2STATUS) & PS2STATUS_IBF;
- if (has_bytes)
- {
- kprintf("read byte from keyboard input: %hhd\n", inb(PS2INPUT));
- }
- else
- {
- kprintf("no bytes in keyboard input\n");
- }
- }
+ return nullptr;
}
-static void sleepy_thread_entry(void)
+static void *sleepy_thread_entry(void *p)
{
+ uint64_t sleep_nanoseconds = (uint64_t)p;
int thread_slept_count = 0;
while (true)
{
- sleep_thread(1000000000);
+ sleep_thread(sleep_nanoseconds);
thread_slept_count++;
- //keyboard_input_loop();
+ printf("thread slept %d times\n", thread_slept_count);
}
(void)thread_slept_count;
+ return nullptr;
}
-static void create_interrupt_stack(size_t size)
-{
- char *rsp0 = vm_alloc(size, ALLOC_FLAGS);
- memset(rsp0, 0, size);
- *get_tss_rsp0() = (uintptr_t)rsp0 + size;
-}
-noreturn void task_init(void)
-{
- lock_scheduler();
- timesource = &pit8253_timer_source;
- timesource->append_callback(sleeping_thread_callback);
- timesource->start();
- kprintf(
- "starting task management, timesource delta %luns\n",
- timesource->nanoseconds_delta());
- // XXX: unfuck this mess at some point
- // XXX: make this also not demand-allocated or it's gonna fail
- create_interrupt_stack(INTERRUPT_STACK_SIZE);
-
- // initalize static threads
- idle_thread = create_thread(idle_thread_entry);
- struct kc_thread *sleepy_thread = create_thread(sleepy_thread_entry);
-
- current_thread = idle_thread;
- ready_thread_push_back(sleepy_thread);
+static uint64_t scheduler_flags;
- idle_thread->status = RUNNING;
- cpu_set_thread(&idle_thread->state, NULL, get_tss_rsp0());
+static inline bool check_preempt_count()
+{
+ if (atomic_load(&preempt_switch_count) > 0)
+ {
+ return true;
+ }
- // shouldn't ever get here
- PANIC(DEAD_END);
+ return false;
}
void task_schedule(void)
{
- if (atomic_load(&preempt_switch_count))
- {
- preempt_switch_flag = true;
- return;
- }
+ if(check_preempt_count())
+ {
+ preempt_switch_flag = true;
+ return;
+ }
- if (first_ready_thread)
- {
- struct kc_thread *this_thread = ready_thread_pop();
+ struct kc_thread *t = thread_queue_pop(&ready_queue);
- if (this_thread == idle_thread)
- {
- if (first_ready_thread)
- {
- this_thread->status = READY;
- this_thread = ready_thread_pop();
- ready_thread_push(idle_thread);
- }
- else if (current_thread->status == RUNNING)
- {
- return;
- }
- else
- {
- // NULL statement????? idon't like
- }
- }
- set_thread(this_thread);
- }
-}
+ if (t == idle_thread)
+ {
+ thread_queue_push_back(&ready_queue, t);
+ t = thread_queue_pop(&ready_queue);
+ }
-static uint64_t scheduler_flags;
+ if (t && current_thread->status != RUNNING)
+ {
+ set_thread(t);
+ }
+}
static void lock_scheduler(void)
{
@@ -193,7 +193,7 @@ static void unlock_scheduler(void)
static void unlock_preempt(void)
{
- if (atomic_load(&preempt_switch_count) >= 1)
+ if (atomic_load(&preempt_switch_count) > 0)
{
preempt_switch_count--;
}
@@ -220,42 +220,21 @@ void update_time(void)
}
}
-static struct kc_thread *create_thread(void (*thread_f)(void))
-{
- char *task_bottom = vm_alloc(16384, ALLOC_FLAGS);
- struct kc_thread *thread =
- (struct kc_thread *)(task_bottom + 16384 - sizeof(*thread));
-
- thread->next = NULL;
-
- thread->time_elapsed = 0;
- thread->sleep_expiration = 0;
+#define KC_THREAD_SIZE 0x3000
- thread->state.stack = (uintptr_t)thread;
- thread->state.stack_top = *get_tss_rsp0();
- thread->state.page_map = mmu_get_map();
-
- // set up the expected stack values for the state
- struct task_register_state
- {
- uint64_t rbp;
- uint64_t r15;
- uint64_t r14;
- uint64_t r13;
- uint64_t r12;
- uint64_t rbx;
- uint64_t rip;
- }
- *register_state =
- (struct task_register_state *)
- (thread->state.stack -= sizeof(*register_state));
+static struct kc_thread *create_thread(void *(*thread_f)(void *), void *p)
+{
+ void *buffer = vm_alloc(KC_THREAD_SIZE, VM_ALLOC_ANONYMOUS|VM_ALLOC_ANY);
+ memset(buffer, 0, KC_THREAD_SIZE);
- memset(register_state, 0, sizeof(*register_state));
+ uintptr_t stack_head = (uintptr_t)buffer + KC_THREAD_SIZE;
+ struct kc_thread *thread = (struct kc_thread *)(stack_head -= sizeof(*thread));
- register_state->rip = (uint64_t)thread_f;
- register_state->rbp = thread->state.stack;
+ thread->kernel_stack_head = (void *)stack_head;
+ thread->kernel_stack_pointer = (void *)stack_head;
+ thread->status = READY;
- thread->status = READY;
+ arch_create_thread(thread, thread_f, p);
return thread;
}
@@ -267,11 +246,17 @@ static void destroy_thread(struct kc_thread *thread)
static void set_thread(struct kc_thread *thread)
{
+ if (thread == current_thread)
+ {
+ return;
+ }
+
if (atomic_load(&preempt_switch_count))
{
preempt_switch_flag = true;
return;
}
+
update_time();
struct kc_thread *previous_thread = current_thread;
current_thread = thread;
@@ -279,15 +264,11 @@ static void set_thread(struct kc_thread *thread)
if (previous_thread->status == RUNNING)
{
previous_thread->status = READY;
- ready_thread_push(previous_thread);
+ thread_queue_push(&ready_queue, previous_thread);
}
- cpu_set_thread(
- &current_thread->state,
- &previous_thread->state,
- get_tss_rsp0());
-
current_thread->status = RUNNING;
+ arch_swap_thread(previous_thread, current_thread);
}
static void block_thread(enum kc_thread_status reason)
@@ -304,14 +285,14 @@ static void unblock_thread(struct kc_thread *thread)
thread->status = READY;
- if (!first_ready_thread || (current_thread == idle_thread))
+ if (!thread_queue_any(ready_queue) || (current_thread == idle_thread))
{
unlock_preempt();
set_thread(thread);
}
else
{
- ready_thread_push_back(thread);
+ thread_queue_push_back(&ready_queue, thread);
}
unlock_scheduler();
@@ -332,89 +313,149 @@ static void sleep_thread_until(uint64_t nanoseconds)
return;
}
-// kprintf("time elapsed is now %ld\r\n", timesource->nanoseconds_elapsed());
-// kprintf("thread will now sleep until %ld\r\n", nanoseconds);
current_thread->sleep_expiration = nanoseconds;
- current_thread->next = sleeping_threads;
- sleeping_threads = current_thread;
+
+ thread_queue_push_back(&sleep_queue, current_thread);
unlock_preempt();
block_thread(SLEEPING);
}
-static struct kc_thread *ready_thread_pop(void)
+static int sleeping_thread_callback(uint64_t timestamp)
{
- struct kc_thread *thread = first_ready_thread;
+ lock_preempt();
- if (thread)
- {
- first_ready_thread = thread->next;
- }
+ struct thread_queue queue = sleep_queue;
- if (!first_ready_thread)
- {
- last_ready_thread = NULL;
- }
+ sleep_queue = (struct thread_queue){ nullptr, nullptr };
- return thread;
+ {
+ struct kc_thread *t;
+ while((t = thread_queue_pop(&queue)) != nullptr)
+ {
+ if (t->sleep_expiration <= timestamp)
+ {
+ t->sleep_expiration = 0;
+ unblock_thread(t);
+ }
+ else
+ {
+ thread_queue_push(&sleep_queue, t);
+ }
+ }
+ }
+
+ unlock_preempt();
+ lock_scheduler();
+ task_schedule();
+ unlock_scheduler();
+
+ return 0;
}
-static void ready_thread_push(struct kc_thread *thread)
-{
- thread->next = first_ready_thread;
- first_ready_thread = thread;
+typedef void (locked_scheduler_action)(void *);
- if (!last_ready_thread)
- {
- last_ready_thread = first_ready_thread;
- }
+static void with_locked_scheduler(
+ locked_scheduler_action *action,
+ void *action_parameter)
+{
+ lock_scheduler();
+ action(action_parameter);
+ unlock_scheduler();
}
-static void ready_thread_push_back(struct kc_thread *thread)
+static void terminate_action(void *result)
{
- if (last_ready_thread)
- {
- last_ready_thread->next = thread;
- }
- else
- {
- first_ready_thread = thread;
- }
- last_ready_thread = thread;
+ union kc_thread_result *result_value = result;
+ current_thread->result = *result_value;
+ current_thread->kernel_stack_pointer = current_thread->kernel_stack_head;
+
+ struct thread_queue queue = wait_queue;
+
+ lock_preempt();
+
+ wait_queue = (struct thread_queue) { nullptr, nullptr };
+
+ {
+ struct kc_thread *t;
+ while((t = thread_queue_pop(&queue)) != nullptr)
+ {
+ if (t->wait_target == current_thread)
+ {
+ t->wait_target = nullptr;
+ t->status = READY;
+ thread_queue_push_back(&ready_queue, t);
+ }
+ else
+ {
+ thread_queue_push(&wait_queue, t);
+ }
+ }
+ }
+
+ unlock_preempt();
+
+ block_thread(TERMINATED);
}
-static int sleeping_thread_callback(uint64_t nanoseconds)
+void kct_terminate(union kc_thread_result result)
{
- lock_preempt();
+ with_locked_scheduler(terminate_action, &result);
+}
- struct kc_thread *sleeping = sleeping_threads;
- sleeping_threads = NULL;
+union kc_thread_result kct_wait(struct kc_thread *target)
+{
+ current_thread->wait_target = target;
+ thread_queue_push_back(&wait_queue, current_thread);
+ block_thread(WAITING);
+ return target->result;
+}
- while (sleeping != NULL)
- {
- struct kc_thread *this_thread = sleeping;
- sleeping = sleeping->next;
+static void *waited_thread_test(void *)
+{
+ printf("worker thread, sleeping for some time...\n");
+ sleep_thread(30000000000);
+ return (void *)1;
+}
- if (this_thread->sleep_expiration <= nanoseconds)
- {
- //kprintf("thread awakened: %p\n", this_thread);
- this_thread->sleep_expiration = 0;
- unblock_thread(this_thread);
- }
- else
- {
- this_thread->next = sleeping_threads;
- sleeping_threads = this_thread;
- }
- }
+static void *waiting_thread_test(void *)
+{
+ printf("waiting thread\n");
+ struct kc_thread *t = create_thread(waited_thread_test, nullptr);
+ t->status = READY;
+ thread_queue_push_back(&ready_queue, t);
+ union kc_thread_result r = kct_wait(t);
+ printf("waited thread terminated result: %d\n", r);
+ return nullptr;
+}
- unlock_preempt();
+noreturn void task_init(void)
+{
+ struct kc_thread boot_thread;
+ boot_thread.status = RUNNING;
+ current_thread = &boot_thread;
- lock_scheduler();
- task_schedule();
- unlock_scheduler();
+ timesource = &pit8253_timer_source;
+ timesource->append_callback(sleeping_thread_callback);
+ timesource->start();
+ printf(
+ "starting task management, timesource delta %luns\n",
+ timesource->nanoseconds_delta());
- return 0;
+ idle_thread = create_thread(idle_thread_entry, nullptr);
+ struct kc_thread *sleepy_thread = create_thread(sleepy_thread_entry, (void *)3000000000);
+ struct kc_thread *sleepy_thread2 = create_thread(sleepy_thread_entry, (void *)5000000000);
+ struct kc_thread *waiting_thread = create_thread(waiting_thread_test, nullptr);
+ thread_queue_push(&ready_queue, sleepy_thread);
+ thread_queue_push(&ready_queue, sleepy_thread2);
+ thread_queue_push_back(&ready_queue, waiting_thread);
+ __asm__ volatile ("movq %%rsp, %0" : "=g"(boot_thread.kernel_stack_pointer) :);
+ thread_queue_push(&ready_queue, idle_thread);
+ block_thread(BLOCKED);
+ // shouldn't ever get here
+ printf("the idle thread exited somehow. we're back in the boot thread. this is not good.\n");
+ PANIC(DEAD_END);
}
+