From: Michael D. Lowis Date: Mon, 12 Sep 2022 20:39:42 +0000 (-0400) Subject: added task local heap using bump pointer X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=7dbe6a490fcf5f4411c81d57b244ba401fb3d3d5;p=proto%2Fcerise-os.git added task local heap using bump pointer --- diff --git a/Kernel.c b/Kernel.c index 3d56af7..4b0acb5 100644 --- a/Kernel.c +++ b/Kernel.c @@ -20,12 +20,10 @@ #define WORD_ALIGN(x) (((x) + WORD_SIZE) & ~(WORD_SIZE)) typedef struct Task_T { - volatile long* stack_top; // top of tasks's stack - long* stack_base; // allocated memory for stack - struct Task_T* next; // pointer to next task - long* heap_beg; - long* heap_ptr; - long* heap_end; + long* stack_top; // top of task's stack + long* heap_top; // top of task's heap + struct Task_T* next; // pointer to next task + long memory[]; } Task_T; typedef struct { @@ -36,6 +34,7 @@ typedef struct { typedef struct { Task_T* task; Task_T* idle; + Task_T* dead; pthread_t thread; } CpuState_T; @@ -46,7 +45,6 @@ static pthread_mutex_t ScheduleLock; static pthread_cond_t ScheduleCond; static __thread int CpuID = 0; static TaskQueue_T ReadyQueue = {0}; -static TaskQueue_T DeadQueue = {0}; static CpuState_T* Running = NULL; static int CpuCount; @@ -183,13 +181,25 @@ __asm__( " ret\n" ); -void PickNewTask(bool requeue) +void PickNewTask(bool dead) { AcquireLock(); + + /* unload the current task, and clear the stack top. + the stack top pointer is used as a spinlock to ensure + another thread does not start the task before we have + saved off our context */ Task_T* prev = Running[CpuID].task; Running[CpuID].task = NULL; atomic_store(&prev->stack_top, NULL); - if (requeue) + + + /* decide what to do with the task */ + if (dead) + { + Running[CpuID].dead = prev; + } + else { Enter(prev); } @@ -197,55 +207,41 @@ void PickNewTask(bool requeue) ReleaseLock(); WaitForTaskFree(prev, Running[CpuID].task); SwapTask(prev, Running[CpuID].task); + if (Running[CpuID].dead) + { + free(Running[CpuID].dead); + Running[CpuID].dead = NULL; + } } void Kernel_Yield(void) -{ - PickNewTask(true); -} - -void Kernel_Exit(void) { PickNewTask(false); } -static void* TaskAllocate(Task_T* task, size_t sz) +void Kernel_Exit(void) { - sz = WORD_ALIGN(sz); - size_t free_sz = (size_t)task->heap_end - (size_t)task->heap_ptr; - assert(sz <= free_sz); - void* ptr = task->heap_ptr; - task->heap_ptr = (void*)((size_t)task->heap_end + sz); - return ptr; + PickNewTask(true); } -static Task_T* CreateTask(void (*task_fn)(void*), void* arg, long int argsz, long int stacksz, long int heapsz) +static Task_T* CreateTask(void (*task_fn)(void*), void* arg, long int argsz, long int memsz) { - AcquireLock(); - Task_T* task = Dequeue(&DeadQueue); - WaitForTaskFree(NULL, task); - ReleaseLock(); - if (!task) + /* allocate a new task. default memory size is used if 0 provided */ + if (memsz == 0) { - task = calloc(1, sizeof(Task_T)); + memsz = 32768; } - - /* create the task's heap and copy the argument onto the tasks heap */ - task->heap_beg = malloc(WORD_ALIGN(heapsz)); - task->heap_ptr = task->heap_beg; - task->heap_end = (void*)((size_t)task->heap_beg + heapsz); - void* newarg = TaskAllocate(task, argsz); + memsz = WORD_ALIGN(memsz); + Task_T* task = calloc(1, sizeof(Task_T) + memsz); + task->heap_top = task->memory; + task->stack_top = (void*)((size_t)task->memory + (size_t)memsz - sizeof(long)); + + /* copy the argument to the task's heap */ + void* newarg = (arg ? task->memory : NULL); + task->heap_top = (void*)((ssize_t)task->heap_top + WORD_ALIGN(argsz)); memcpy(newarg, arg, argsz); - /* allocate stack (default size of 32768) */ - if (stacksz == 0) - { - stacksz = 32768; - } - task->stack_base = realloc(task->stack_base, stacksz); - /* populate the initial context on the stack so SwapTasks works */ - task->stack_top = &task->stack_base[stacksz / sizeof(long)-1]; // top of stack *(--task->stack_top) = (long)Kernel_Exit; // coroutine cleanup *(--task->stack_top) = (long)task_fn; // user's function to run (rop style!) *(--task->stack_top) = (long)newarg; // user's function argument (rdi) @@ -257,9 +253,9 @@ static Task_T* CreateTask(void (*task_fn)(void*), void* arg, long int argsz, lon return task; } -void Kernel_Spawn(void (*task_fn)(void*), void* arg, long int argsz, long int stacksz, long int heapsz) +void Kernel_Spawn(void (*task_fn)(void*), void* arg, long int argsz, long int memsz) { - Task_T* task = CreateTask(task_fn, arg, argsz, stacksz, heapsz); + Task_T* task = CreateTask(task_fn, arg, argsz, memsz); AcquireLock(); Enter(task); ReleaseLock(); @@ -279,7 +275,7 @@ static void CpuIdle(void* arg) static void* CpuMain(void* arg) { CpuID = (long int)arg; - Running[CpuID].idle = CreateTask(CpuIdle, 0, 0, 0, 0); + Running[CpuID].idle = CreateTask(CpuIdle, 0, 0, 0); Running[CpuID].task = Running[CpuID].idle; StartTask(Running[CpuID].idle); return NULL; /* unreachable */ @@ -319,6 +315,18 @@ void Kernel_Run(void) } } +void* Kernel_Allocate(size_t sz) +{ + Task_T* task = Running[CpuID].task; + task->stack_top = &(long){0}; + sz = WORD_ALIGN(sz); + ssize_t free_sz = (ssize_t)task->stack_top - (ssize_t)task->heap_top; + assert(sz <= free_sz); + void* ptr = task->heap_top; + task->heap_top = (void*)((ssize_t)task->heap_top + sz); + return ptr; +} + /*************************************** Main Routine ***************************************/ @@ -342,9 +350,7 @@ int main(int argc, char** argv) for (int i = 0; i < 100; i++) { - int* val = malloc(sizeof(int)); - *val = i; - Kernel_Spawn(task1, &i, sizeof(int), 0, sizeof(int)); + Kernel_Spawn(task1, &i, sizeof(int), 0); } /* wait for all jobs to be done */