#include "kthread.h" #include "alloc.h" #include "assert.h" #include "irq.h" #include "klibc.h" #include "list.h" #include "time.h" #include "vga.h" static struct kthread *currentThread; void kthreadExit() { uint32_t flags; disable_IRQs(flags); struct kthread *current = currentThread; struct kthread *next = kthreadSelectNext(); if (next == current) assert("cannot exit thread"); currentThread->state = EXITING; currentThread = next; currentThread->state = RUNNING; cpu_context_exit_to(next->cpuState, (cpu_kstate_function_arg1_t *)kthreadDelete, (uint32_t)current); restore_IRQs(flags); return; } int kthreadSetup(vaddr_t mainStack, size_t mainStackSize) { struct kthread *current = (struct kthread *)malloc(sizeof(struct kthread)); strzcpy(current->name, "[KINIT]", KTHREAD_NAME_MAX_LENGTH); current->stackAddr = mainStack; current->stackSize = mainStackSize; current->state = RUNNING; list_singleton(currentThread, current); return 0; } struct kthread *kthreadCreate(const char *name, cpu_kstate_function_arg1_t func, void *args) { struct kthread *thread = (struct kthread *)malloc(sizeof(struct kthread)); if (!thread) return NULL; thread->stackAddr = (vaddr_t)malloc(KTHREAD_DEFAULT_STACK_SIZE); printf("Alloc stask at 0x%x struct at 0x%x\n", thread->stackAddr, thread); thread->stackSize = KTHREAD_DEFAULT_STACK_SIZE; if (!thread->stackAddr) goto free_mem; if (name) strzcpy(thread->name, name, KTHREAD_NAME_MAX_LENGTH); else strzcpy(thread->name, "[UNKNOW]", KTHREAD_NAME_MAX_LENGTH); if (cpu_kstate_init(&thread->cpuState, (cpu_kstate_function_arg1_t *)func, (vaddr_t)args, thread->stackAddr, thread->stackSize, (cpu_kstate_function_arg1_t *)kthreadExit, 0)) goto free_mem; thread->state = READY; uint32_t flags; disable_IRQs(flags); list_add_tail(currentThread, thread); restore_IRQs(flags); return thread; free_mem: free((void *)thread->stackAddr); free((void *)thread); return NULL; } void kthreadDelete(struct kthread *thread) { uint32_t flags; disable_IRQs(flags); list_delete(currentThread, thread); free((void *)thread->stackAddr); free((void *)thread); restore_IRQs(flags); } struct kthread *kthreadSelectNext() { struct kthread *nextThread; int idx; list_foreach(currentThread->next, nextThread, idx) { if (nextThread->state == READY) { return nextThread; } } return currentThread; } struct cpu_state *kthreadSwitch(struct cpu_state *prevCpu) { uint32_t flags; disable_IRQs(flags); currentThread->cpuState = prevCpu; currentThread->state = READY; struct kthread *nextThread = kthreadSelectNext(); printStringDetails(nextThread->name, RED, BLACK, 40, VGA_HEIGHT - 1); currentThread = nextThread; currentThread->state = RUNNING; restore_IRQs(flags); return nextThread->cpuState; } int kthreadOnJieffiesTick() { struct kthread *nextThread; int idx; uint32_t flags; disable_IRQs(flags); list_foreach(currentThread, nextThread, idx) { if (nextThread->state == SLEEPING) { nextThread->jiffiesSleeping--; if (!nextThread->jiffiesSleeping) { nextThread->state = READY; } } } restore_IRQs(flags); return 0; } int kthreadYield() { uint32_t flags; disable_IRQs(flags); struct kthread *next = kthreadSelectNext(); struct kthread *current = currentThread; if (current == next) { restore_IRQs(flags); return 0; } assert(current->state == RUNNING); assert(next->state == READY); current->state = READY; currentThread = next; currentThread->state = RUNNING; cpu_context_switch(¤t->cpuState, next->cpuState); restore_IRQs(flags); return 0; } int kthreadMsleep(unsigned long msec) { uint32_t flags; disable_IRQs(flags); struct kthread *current = currentThread; assert(current->state == RUNNING); current->state = SLEEPING; struct kthread *next = kthreadSelectNext(); assert(next != current); current->jiffiesSleeping = msecs_to_jiffies(msec); assert(next->state == READY); currentThread = next; currentThread->state = RUNNING; cpu_context_switch(¤t->cpuState, next->cpuState); restore_IRQs(flags); return 0; } struct kthread *getCurrenThread() { return currentThread; }