diff options
-rw-r--r-- | arch/x86/machine/lapic.c | 4 | ||||
-rw-r--r-- | arch/x86/machine/trap.c | 3 | ||||
-rw-r--r-- | kern/kernel.c | 22 | ||||
-rw-r--r-- | kern/thread.c | 107 | ||||
-rw-r--r-- | kern/thread.h | 5 |
5 files changed, 83 insertions, 58 deletions
diff --git a/arch/x86/machine/lapic.c b/arch/x86/machine/lapic.c index e65d5a3b..10d6b40e 100644 --- a/arch/x86/machine/lapic.c +++ b/arch/x86/machine/lapic.c @@ -340,10 +340,8 @@ lapic_intr_timer(struct trap_frame *frame) { (void)frame; -#if 0 - thread_tick(); -#endif lapic_eoi(); + thread_tick(); } void diff --git a/arch/x86/machine/trap.c b/arch/x86/machine/trap.c index a26212a2..18bff6bc 100644 --- a/arch/x86/machine/trap.c +++ b/arch/x86/machine/trap.c @@ -150,10 +150,7 @@ trap_main(struct trap_frame *frame) { assert(frame->vector < ARRAY_SIZE(trap_handlers)); trap_handlers[frame->vector].fn(frame); - -#if 0 thread_reschedule(); -#endif } #ifdef __LP64__ diff --git a/kern/kernel.c b/kern/kernel.c index 70cc8c71..760f68e8 100644 --- a/kern/kernel.c +++ b/kern/kernel.c @@ -22,31 +22,16 @@ #include <kern/thread.h> #include <machine/cpu.h> -static void __init -kernel_setup(void *arg) -{ - (void)arg; - - for (;;) - cpu_idle(); -} - void __init kernel_main(void) { - struct thread *thread; - int error; - assert(!cpu_intr_enabled()); task_setup(); thread_setup(); - cpu_mp_setup(); - - error = thread_create(&thread, "core", kernel_task, kernel_setup, NULL); - if (error) - panic("kernel: unable to create kernel thread"); + /* Interrupts are enabled by this call */ + cpu_mp_setup(); thread_run(); @@ -58,8 +43,7 @@ kernel_ap_main(void) { assert(cpu_intr_enabled()); - for (;;) - cpu_idle(); + thread_run(); /* Never reached */ } diff --git a/kern/thread.c b/kern/thread.c index 463c4416..dcf038c3 100644 --- a/kern/thread.c +++ b/kern/thread.c @@ -22,8 +22,10 @@ #include <kern/list.h> #include <kern/macros.h> #include <kern/param.h> +#include <kern/sprintf.h> #include <kern/stddef.h> #include <kern/string.h> +#include <kern/task.h> #include <kern/thread.h> #include <machine/cpu.h> #include <machine/tcb.h> @@ -50,12 +52,14 @@ thread_runq_init(struct thread_runq *runq, struct thread *idle) idle->flags = 0; idle->preempt = 1; runq->current = idle; + runq->idle = idle; list_init(&runq->threads); } static void thread_runq_enqueue(struct thread_runq *runq, struct thread *thread) { + assert(!cpu_intr_enabled()); list_insert_tail(&runq->threads, &thread->runq_node); } @@ -64,6 +68,8 @@ thread_runq_dequeue(struct thread_runq *runq) { struct thread *thread; + assert(!cpu_intr_enabled()); + if (list_empty(&runq->threads)) thread = NULL; else { @@ -106,15 +112,36 @@ thread_main(void) thread->fn(thread->arg); + /* TODO Thread destruction */ for (;;) cpu_idle(); } +static void +thread_init(struct thread *thread, struct task *task, void *stack, + const char *name, void (*fn)(void *), void *arg) +{ + tcb_init(&thread->tcb, stack, thread_main); + + if (name == NULL) + name = task->name; + + thread->flags = 0; + thread->preempt = 0; + thread->task = task; + thread->stack = stack; + strlcpy(thread->name, name, sizeof(thread->name)); + thread->fn = fn; + thread->arg = arg; + task_add_thread(task, thread); +} + int -thread_create(struct thread **threadp, const char *name, struct task *task, +thread_create(struct thread **threadp, struct task *task, const char *name, void (*fn)(void *), void *arg) { struct thread *thread; + unsigned long flags; void *stack; int error; @@ -132,22 +159,11 @@ thread_create(struct thread **threadp, const char *name, struct task *task, goto error_stack; } - tcb_init(&thread->tcb, stack, thread_main); - - if (name == NULL) - name = task->name; - - thread->flags = 0; - thread->preempt = 0; - thread->task = task; - thread->stack = stack; - strlcpy(thread->name, name, sizeof(thread->name)); - thread->fn = fn; - thread->arg = arg; + thread_init(thread, task, stack, name, fn, arg); - /* XXX Assign all threads to the main processor for now */ - thread_runq_enqueue(&thread_runqs[0], thread); - task_add_thread(task, thread); + flags = cpu_intr_save(); + thread_runq_enqueue(&thread_runqs[cpu_id()], thread); + cpu_intr_restore(flags); *threadp = thread; return 0; @@ -158,18 +174,48 @@ error_thread: return error; } +static void +thread_idle(void *arg) +{ + (void)arg; + + for (;;) + cpu_idle(); +} + +static void __init +thread_setup_idle(void) +{ + char name[THREAD_NAME_SIZE]; + struct thread_runq *runq; + void *stack; + + stack = kmem_cache_alloc(&thread_stack_cache); + + if (stack == NULL) + panic("thread: unable to allocate idle thread stack"); + + snprintf(name, sizeof(name), "idle%u", cpu_id()); + runq = thread_runq_local(); + thread_init(runq->idle, kernel_task, stack, name, thread_idle, NULL); +} + void __init thread_run(void) { struct thread_runq *runq; struct thread *thread; - runq = thread_runq_local(); + assert(cpu_intr_enabled()); + thread_setup_idle(); + + cpu_intr_disable(); + runq = thread_runq_local(); thread = thread_runq_dequeue(runq); - /* TODO Idle thread */ - assert(thread != NULL); + if (thread == NULL) + thread = runq->idle; runq->current = thread; tcb_load(&thread->tcb); @@ -182,20 +228,24 @@ thread_schedule(void) struct thread *prev, *next; unsigned long flags; + assert(thread_preempt_enabled()); + flags = cpu_intr_save(); runq = thread_runq_local(); prev = runq->current; - thread_runq_enqueue(runq, prev); + assert(prev != NULL); + + if (prev != runq->idle) + thread_runq_enqueue(runq, prev); + next = thread_runq_dequeue(runq); - /* TODO Idle thread */ - assert(next != NULL); + if (next == NULL) + next = runq->idle; - if (prev != next) { - runq->current = next; + if (prev != next) tcb_switch(&prev->tcb, &next->tcb); - } cpu_intr_restore(flags); } @@ -210,11 +260,9 @@ thread_reschedule(void) runq = thread_runq_local(); thread = runq->current; - - /* TODO Idle thread */ assert(thread != NULL); - if (thread->flags & THREAD_RESCHEDULE) + if ((thread->preempt == 0) && (thread->flags & THREAD_RESCHEDULE)) thread_schedule(); } @@ -228,9 +276,6 @@ thread_tick(void) runq = thread_runq_local(); thread = runq->current; - - /* TODO Idle thread */ assert(thread != NULL); - thread->flags |= THREAD_RESCHEDULE; } diff --git a/kern/thread.h b/kern/thread.h index b7debddc..0022591d 100644 --- a/kern/thread.h +++ b/kern/thread.h @@ -57,6 +57,7 @@ struct thread { */ struct thread_runq { struct thread *current; + struct thread *idle; struct list threads; } __aligned(CPU_L1_SIZE); @@ -80,13 +81,13 @@ void thread_setup(void); * * If the given name is null, the task name is used instead. */ -int thread_create(struct thread **threadp, const char *name, struct task *task, +int thread_create(struct thread **threadp, struct task *task, const char *name, void (*fn)(void *), void *arg); /* * Start running threads on the local processor. * - * Interrupts are implicitely enabled when the first thread is dispatched. + * Interrupts must be enabled when calling this function. */ void __noreturn thread_run(void); |