diff options
Diffstat (limited to 'kc/core/task.c')
| -rw-r--r-- | kc/core/task.c | 210 |
1 files changed, 109 insertions, 101 deletions
diff --git a/kc/core/task.c b/kc/core/task.c index e5933bd..9e0e549 100644 --- a/kc/core/task.c +++ b/kc/core/task.c @@ -33,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 @@ -46,9 +42,67 @@ 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 volatile atomic_uint_fast64_t preempt_switch_count = 0; static volatile atomic_bool preempt_switch_flag = false; @@ -102,10 +156,10 @@ noreturn void task_init(void) 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); - ready_thread_push(sleepy_thread); - ready_thread_push(sleepy_thread2); + thread_queue_push(&ready_queue, sleepy_thread); + thread_queue_push(&ready_queue, sleepy_thread2); __asm__ volatile ("movq %%rsp, %0" : "=g"(boot_thread.kernel_stack_pointer) :); - ready_thread_push(idle_thread); + thread_queue_push(&ready_queue, idle_thread); block_thread(BLOCKED); // shouldn't ever get here kprintf("the idle thread exited somehow. we're back in the boot thread. this is not good.\n"); @@ -124,33 +178,25 @@ static inline bool check_preempt_count() void task_schedule(void) { - if (check_preempt_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; - } - } - set_thread(this_thread); - } -} + if (t == idle_thread) + { + thread_queue_push_back(&ready_queue, t); + t = thread_queue_pop(&ready_queue); + } + if (t && current_thread->status != RUNNING) + { + set_thread(t); + } +} static void lock_scheduler(void) { @@ -223,11 +269,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; @@ -235,7 +287,7 @@ 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); } current_thread->status = RUNNING; @@ -257,14 +309,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(); @@ -285,81 +337,38 @@ 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) -{ - struct kc_thread *thread = first_ready_thread; - - if (thread) - { - first_ready_thread = thread->next; - } - - if (!first_ready_thread) - { - last_ready_thread = NULL; - } - - return thread; -} - -static void ready_thread_push(struct kc_thread *thread) -{ - thread->next = first_ready_thread; - first_ready_thread = thread; - - if (!last_ready_thread) - { - last_ready_thread = first_ready_thread; - } -} - -static void ready_thread_push_back(struct kc_thread *thread) -{ - if (last_ready_thread) - { - last_ready_thread->next = thread; - } - else - { - first_ready_thread = thread; - } - last_ready_thread = thread; -} - -static int sleeping_thread_callback(uint64_t nanoseconds) +static int sleeping_thread_callback(uint64_t timestamp) { lock_preempt(); - struct kc_thread *sleeping = sleeping_threads; - sleeping_threads = NULL; + struct thread_queue queue = sleep_queue; - while (sleeping != NULL) - { - struct kc_thread *this_thread = sleeping; - sleeping = sleeping->next; + sleep_queue = (struct thread_queue){ nullptr, nullptr }; - if (this_thread->sleep_expiration <= nanoseconds) - { - this_thread->sleep_expiration = 0; - unblock_thread(this_thread); - } - else - { - this_thread->next = sleeping_threads; - sleeping_threads = this_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(); @@ -369,7 +378,6 @@ static int sleeping_thread_callback(uint64_t nanoseconds) return 0; } - typedef void (locked_scheduler_action)(void *); static void with_locked_scheduler( |
