Hopefully finished round-robin scheduler.
authorethereal <ethereal.visage@gmail.com>
Mon, 13 May 2013 00:13:12 +0000 (18:13 -0600)
committerethereal <ethereal.visage@gmail.com>
Mon, 13 May 2013 00:13:12 +0000 (18:13 -0600)
13 files changed:
bochsrc.txt
kernel/apic.h
kernel/apic_isrs.s
kernel/klock.h
kernel/kmain.c
kernel/ktime.c
kernel/sched.c
kernel/sched.h
kernel/sched_helper.s
kernel/smp.c
kernel/thread.c
kernel/thread.h
kernel/thread_helper.s

index 5fc70f8..b46cba7 100644 (file)
@@ -637,7 +637,6 @@ panic: action=ask
 error: action=report
 info: action=report
 #debug: action=ignore#, pci=report # report BX_DEBUG from module 'pci'
-debug: action=report
 
 #=======================================================================
 # DEBUGGER_LOG:
index 476b8e1..9de966b 100644 (file)
@@ -3,7 +3,7 @@
 
 #include <stdint.h>
 
-#define APIC_TIMER_INTERVAL 500000
+#define APIC_TIMER_INTERVAL 50000
 
 #define APIC_REG_ID 0x20
 #define APIC_REG_EOI 0xb0
index b8feada..92d24a0 100644 (file)
@@ -34,7 +34,6 @@ apic_empty_isr:
 
 %macro basic_isr 1
 apic_isr_%1:
-       xchg    bx, bx
        isr_prologue
        mov     rdi, %1
        call    apic_isr_callback
index 1a2c89c..b194112 100644 (file)
@@ -3,6 +3,8 @@
 
 #include <stdint.h>
 
+#define KLOCK_INIT_UNLOCKED 0
+
 void klock_acquire(uint64_t *spinlock);
 int klock_tryacquire(uint64_t *spinlock);
 void klock_release(uint64_t *spinlock);
index 5bfa2de..2bc3583 100644 (file)
 #include "ktime.h"
 #include "pit.h"
 
-static void thread1_main(void *unused) {
+static void thread_main(void *idv) {
+    uint64_t id = (uint64_t)idv;
+    klog("Thread #%i starting . . .", id);
+    ktime_t last = ktime_current();
     while(1) {
-        //klog("A!");
+        ktime_t now = ktime_current();
+        if(ktime_getsec(last) != ktime_getsec(now)) {
+            klog("Thread #%i: time: %i seconds", id, ktime_getsec(now));
+        }
+        last = now;
     }
 }
 
@@ -123,14 +130,14 @@ void kmain(uint64_t *memmap) {
     //apic_enable_interrupts();
     //apic_find_bus_ratio();
 
-    //apic_set_isr(APIC_TIMER_INTR, sched_swap);
+    apic_set_isr(APIC_TIMER_INTR, sched_swap);
 
-    //klog("Enabling timer . . .");
-    //apic_enable_timer();
+    klog("Enabling timer . . .");
+    apic_enable_timer();
 
-    thread_t *t1 = thread_create_kworker(thread1_main, NULL, 0x1000);
-
-    sched_add_thread(t1);
+    for(uint64_t i = 0; i < 20; i ++) {
+        sched_add_thread(thread_create_kworker(thread_main, (void *)i, 0x1000));
+    }
     //klog("scheduler has thread %p", t1);
 
     //sched_kyield();
index 503e751..aa28907 100644 (file)
@@ -4,7 +4,7 @@ ktime_updater_t ktime_updater;
 ktime_t ktime_last;
 
 void ktime_init(void) {
-    
+    ktime_last = 0;
 }
 
 void ktime_set_updater(ktime_updater_t updater) {
index 170f786..764fa33 100644 (file)
@@ -3,16 +3,19 @@
 #include "apic.h"
 #include "smp.h"
 #include "kutil.h"
+#include "klock.h"
 
 thread_t *sched_threads[SCHED_MAX_THREADS];
 uint32_t sched_thread_count;
 uint32_t sched_current_thread;
+uint64_t sched_spinlock;
 
 static void sched_enter_idle(void);
 
 void sched_init(void) {
     sched_thread_count = 0;
     sched_current_thread = 0;
+    sched_spinlock = KLOCK_INIT_UNLOCKED;
 
     sched_cpu_init();
 }
@@ -57,29 +60,74 @@ void sched_kyield(void) {
 }
 
 thread_t *sched_findnext(void) {
-    //klog("Finding next thread to schedule . . .");
-    //uint32_t next = (sched_current_thread+1)%sched_thread_count;
-    uint32_t next = 0;
+    thread_t *result = NULL;
 
-    sched_current_thread = next;
+    for(uint32_t off = 1; off <= sched_thread_count; off ++) {
+        uint32_t cursor = (sched_current_thread + off) % sched_thread_count;
 
-    return sched_threads[next];
+        thread_t *thread = sched_threads[cursor];
+
+        klock_acquire(&thread->thread_lock);
+
+        // if not running, not waiting, not sleeping or
+        if(thread_isready(thread)) {
+            result = thread;
+            sched_current_thread = cursor;
+        }
+
+        klock_release(&thread->thread_lock);
+        if(result) break;
+    }
+
+    return result;
 }
 
 void sched_swap(void) {
-    // save old registers
-    if(PERCPU(sched_thread)) PERCPU(sched_thread)->regs = *PERCPU(saveregs);
+    // acquire sched spinlock.
+    klock_acquire(&sched_spinlock);
+    // make old thread not running, if necessary.
+    if(PERCPU(sched_thread)) {
+        thread_t *t = PERCPU(sched_thread);
+        klock_acquire(&t->thread_lock);
+        PERCPU(sched_thread)->status &= ~THREAD_RUNNING;
+        klock_release(&t->thread_lock);
+    }
 
     thread_t *next = sched_findnext();
-    /*klog("next: %p", next);
-    klog("next RIP: %x", next->regs.r.rip);
-    klog("next gs: %x", next->regs.r.gs);
-    klog("next gs_base: %x", next->regs.r.gs_base);*/
+
+    if(next != NULL) {
+        //klog("Selected next thread (%p), setting status flags . . .", next);
+
+        PERCPU(sched_thread) = next;
+
+        //klog("Grabbing lock.");
+        klock_acquire(&next->thread_lock);
+        next->status |= THREAD_RUNNING;
+
+        if(next->context) {
+            //klog("Swapping to new context!");
+            context_switch(next->context);
+        }
+
+        //PERCPU(sched_thread)->regs = *PERCPU(saveregs);
+        //klog("Setting saveregs to %p", &next->regs);
+        PERCPU(saveregs) = &next->regs;
+
+        klock_release(&next->thread_lock);
+
+        //klog("Status flags set.");
+    }
+
+    // nothing more to do with the sched spinlock.
+    klock_release(&sched_spinlock);
 
     apic_send_eoi();
 
-    if(next->context) context_switch(next->context);
-    thread_begin(next);
+    if(next) {
+        //klog("Beginning.");
+        thread_begin(next);
+    }
+    else sched_enter_idle();
 }
 
 static void sched_enter_idle(void) {
index 9b0d91c..16fa49f 100644 (file)
@@ -15,6 +15,7 @@ void sched_add_thread(thread_t *context);
 // yields the current timeslice. Only useful for kernel threads.
 void sched_kyield(void);
 
+// finds the next thread to run, round-robin. Assumes sched spinlock held.
 thread_t *sched_findnext(void);
 void sched_swap(void);
 
index 4f1efa2..5513311 100644 (file)
@@ -4,13 +4,13 @@
 
 [global sched_isr]
 sched_isr:
-       xchg bx, bx
        push    rax
        ; grab address of percpu structure
        mov     rax, [gs:0x0]
        ; grab address of saveregs structure
        mov     rax, [rax]
 
+       xchg bx,bx
        cmp     rax, 0
        je      .skipsave
 
@@ -65,10 +65,12 @@ sched_isr:
        mov     qword [rax + THREAD_REG_GS*8], 0
        mov     word [rax + THREAD_REG_GS*8], bx
 
+       ; need rax for rdmsr.
+       mov     rdi, rax
        mov     ecx, 0xc0000101
        rdmsr
-       mov     dword [rax + THREAD_REG_GS_BASE*8], eax
-       mov     dword [rax + THREAD_REG_GS_BASE*8 + 4], edx
+       mov     dword [rdi + THREAD_REG_GS_BASE*8], eax
+       mov     dword [rdi + THREAD_REG_GS_BASE*8 + 4], edx
 
        ; all set!
 
@@ -76,5 +78,6 @@ sched_isr:
 
        .skipsave:
        add     rsp, 6*8
+       ;xchg bx,bx
 
        jmp     sched_swap
index 0029973..3bdaa1e 100644 (file)
@@ -48,18 +48,7 @@ static void smp_add_bsp(void) {
     scp->used = 1;
 
     smp_cpu_count ++;
-    klog("Setting MSR_GS_BASE to %p", (uint64_t) scp);
     msr_write(MSR_GS_BASE, (uint64_t)scp);
-    klog("MSR_GS_BASE is: %x", msr_read(MSR_GS_BASE));
-    klog("First few bytes of scp: %x %x %x %x",
-        ((uint8_t *)scp)[0],
-        ((uint8_t *)scp)[1],
-        ((uint8_t *)scp)[2],
-        ((uint8_t *)scp)[3]);
-    uint64_t ff;
-    __asm__ __volatile__("mov rax, gs:0x0" : "=a"(ff));
-    klog("First few bytes of gs: %x", ff);
-    __asm__("xchg bx,bx");
 
     tss_t *tss = tss_create();
     gdt_add_tss(tss);
index da0974f..67be0c0 100644 (file)
@@ -3,6 +3,9 @@
 #include "gdt.h"
 #include "kutil.h"
 #include "msr.h"
+#include "klock.h"
+#include "sched.h"
+#include "klog.h"
 
 extern void thread_setregs(thread_regs_t *regs);
 
@@ -11,14 +14,16 @@ static void thread_kworker_wrapper(thread_kworker_entry_t entry, void *param,
 
 thread_t *thread_create(void) {
     thread_t *thread = kheap_alloc(sizeof(thread_t));
+
+    thread->thread_lock = KLOCK_INIT_UNLOCKED;
+
     for(int i = 0; i < THREAD_REG_COUNT; i ++) {
         thread->regs.array[i] = 0;
     }
     // default RFLAGS
     thread->regs.r.rflags = 0x00200282;
 
-    thread->status = THREAD_INITIALIZING;
-    thread->active = 0;
+    thread->status = 0;
     thread->use_kernel_gs = 0;
 
     return thread;
@@ -29,7 +34,14 @@ static void thread_kworker_wrapper(thread_kworker_entry_t entry, void *param,
 
     entry(param);
 
+    klock_acquire(&thread->thread_lock);
+
     thread->status = THREAD_TERMINATED;
+
+    klock_release(&thread->thread_lock);
+
+    // yield back to scheduler
+    sched_kyield();
 }
 
 thread_t *thread_create_kworker(thread_kworker_entry_t entry, void *data,
@@ -50,8 +62,6 @@ thread_t *thread_create_kworker(thread_kworker_entry_t entry, void *data,
     thread->regs.r.rsp =
         (uint64_t)(kheap_alloc_aligned(stack_size, 8)) + stack_size;
 
-    thread->status = THREAD_RUNNING;
-
     thread->context = NULL;
 
     thread->use_kernel_gs = 1;
@@ -60,6 +70,7 @@ thread_t *thread_create_kworker(thread_kworker_entry_t entry, void *data,
 }
 
 void thread_begin(thread_t *thread) {
+    //klog("beginning thread %p . . .", thread);
     if(thread->use_kernel_gs) {
         thread->regs.r.gs = GDT_KERNEL_DS;
         thread->regs.r.gs_base = msr_read(MSR_GS_BASE);
@@ -67,7 +78,20 @@ void thread_begin(thread_t *thread) {
     thread_setregs(&thread->regs);
 }
 
-void thread_sleep(thread_t *thread, uint64_t at) {
+void thread_wakeat(thread_t *thread, ktime_t at) {
     thread->thread_wake = at;
     thread->status |= THREAD_SLEEPING;
 }
+
+uint8_t thread_isready(thread_t *thread) {
+    // if already running, definitely not.
+    if(thread->status & THREAD_RUNNING) return 0;
+    // if waiting, no.
+    if(thread->status & THREAD_WAITING) return 0;
+    // if sleeping and not enough time has passed, then no.
+    if((thread->status & THREAD_SLEEPING)
+        && thread->thread_wake < ktime_current()) return 0;
+
+    // otherwise, yes.
+    return 1;
+}
index 9b8aaff..587aa09 100644 (file)
@@ -4,6 +4,7 @@
 #include <stdint.h>
 
 #include "context.h"
+#include "ktime.h"
 
 /* NOTE: keep these #defines and those in thread_regs.s synched. */
 typedef union thread_regs_t {
@@ -68,14 +69,19 @@ typedef union thread_regs_t {
 } thread_regs_t;
 
 typedef enum thread_status_t {
-    THREAD_INITIALIZING = 0,
+    // set if the thread is active on a processor
     THREAD_RUNNING = 1,
+    // set if the thread is waiting for a particular time
     THREAD_SLEEPING = 2,
+    // set if the thread is waiting on a synchronization primitive
     THREAD_WAITING = 4,
+    // set if the thread has terminated and is awaiting garbage collection
     THREAD_TERMINATED = 8
 } thread_status_t;
 
 typedef struct thread_t {
+    // spinlock for thread
+    uint64_t thread_lock;
     // current thread state
     thread_status_t status;
     // saved registers
@@ -84,14 +90,12 @@ typedef struct thread_t {
     context_t *context;
 
     // time to wake, if sleeping.
-    uint64_t thread_wake;
+    ktime_t thread_wake;
 
     // TODO: add synch primitive being waited on
 
-    // zero if waiting to be scheduled, 1 if in-progress
-    uint8_t active;
-
     // 1 if the current PERCPU GS_BASE should be used, 0 o/w.
+    // only useful for kernel threads.
     uint8_t use_kernel_gs;
 } thread_t;
 
@@ -107,6 +111,10 @@ void thread_begin(thread_t *thread);
 // i.e. stores 0 for rax.
 uint64_t thread_ksaveregs(thread_regs_t *regs);
 
-void thread_wakeat(thread_t *thread, uint64_t at);
+void thread_wakeat(thread_t *thread, ktime_t at);
+
+// returns 1 if thread is ready to run again. Assumes thread lock is held by
+// caller.
+uint8_t thread_isready(thread_t *thread);
 
 #endif
index ac13920..7b54c83 100644 (file)
@@ -51,7 +51,7 @@ thread_setregs:
        mov     rbx, [rax + THREAD_REG_DS*8]
        mov     ds, bx
 
-       ; pop rbx/rax off stack
+       ; pop rbx/rax off stack, SS is still good (changed by iretq)
        pop     rdx
        pop     rcx
        pop     rbx
@@ -98,8 +98,10 @@ thread_ksaveregs:
        mov     ax, gs
        mov     [rdi + THREAD_REG_GS*8], ax
 
+       mov     rdx, rax
        mov     ecx, 0xc0000101
        rdmsr
+       ; NOTE: THIS WILL BLOW UP
        mov     dword [rax + THREAD_REG_GS_BASE*8], eax
        mov     dword [rax + THREAD_REG_GS_BASE*8 + 4], edx