]> git.mdlowis.com Git - proto/cerise-os.git/commitdiff
added task local heap using bump pointer
authorMichael D. Lowis <mike.lowis@gentex.com>
Mon, 12 Sep 2022 20:39:42 +0000 (16:39 -0400)
committerMichael D. Lowis <mike.lowis@gentex.com>
Mon, 12 Sep 2022 20:39:42 +0000 (16:39 -0400)
Kernel.c

index 3d56af7ccc2004ef5ef7e784d49fdbcba466d81a..4b0acb55b3898a4d7b9e768923d300c6dde8b4e2 100644 (file)
--- a/Kernel.c
+++ b/Kernel.c
 #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 */