/* TODO:
-* Recycle dead tasks
-* implement message passing
* implement task-local heap
+* implement message passing
*/
+#define COND_WAIT_TIMEOUT_MS 100u
+
typedef struct Task_T {
- long* stack_top; // top of tasks's stack
- long* stack_base; // allocated memory for stack
- struct Task_T* next; // pointer to next task
+ volatile long* stack_top; // top of tasks's stack
+ long* stack_base; // allocated memory for stack
+ struct Task_T* next; // pointer to next task
} Task_T;
typedef struct {
static void WaitForTaskFree(Task_T* prev, Task_T* next)
{
- if (prev != next)
+ if (next && prev != next)
{
while (!next->stack_top)
{
" ret\n"
);
-static void Yield(void)
+void Kernel_Yield(void)
{
AcquireLock();
printf("CPU %d is yielding\n", CpuID);
SwapTask(prev, Running[CpuID].task);
}
-void ExitTask(void)
+void Kernel_Exit(void)
{
puts("exiting");
AcquireLock();
static Task_T* CreateTask(void (*task_fn)(void*), void* arg, int stacksize)
{
- if (stacksize == 0) { stacksize = 32768; }
- Task_T* task = calloc(1, sizeof(Task_T));
- task->stack_base = calloc(stacksize/sizeof(long), sizeof(long));
+ AcquireLock();
+ Task_T* task = Dequeue(&DeadQueue);
+ WaitForTaskFree(NULL, task);
+ ReleaseLock();
+ if (!task)
+ {
+ task = calloc(1, sizeof(Task_T));
+ }
+
+ /* allocate stack */
+ if (stacksize == 0)
+ {
+ stacksize = 32768;
+ }
+ task->stack_base = realloc(task->stack_base, stacksize);
+
task->stack_top = &task->stack_base[stacksize/sizeof(long)-1]; // top of stack
- *(--task->stack_top) = (long)ExitTask; // coroutine cleanup
- *(--task->stack_top) = (long)task_fn; // user's function to run (rop style!)
- *(--task->stack_top) = (long)arg; // user's function argument (rdi)
+ *(--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)arg; // user's function argument (rdi)
for (int saved = 0; saved < 6; saved++)
{
*(--task->stack_top) = 0xdeadbeef; // initial values for saved registers
return task;
}
-void SpawnTask(void (*task_fn)(void*), void* arg, int stacksize)
+void Kernel_Spawn(void (*task_fn)(void*), void* arg, int stacksize)
{
Task_T* task = CreateTask(task_fn, arg, stacksize);
/* put task in the ready queue */
printf("CPU %d is started\n", CpuID);
while(1)
{
- Yield();
+ Kernel_Yield();
printf("CPU %d is idle\n", CpuID);
AcquireLock();
- WaitForCondition(&ScheduleCond, &ScheduleLock, 10);
+ WaitForCondition(&ScheduleCond, &ScheduleLock, COND_WAIT_TIMEOUT_MS);
ReleaseLock();
}
}
return NULL; /* unreachable */
}
-void Init(void)
+void Kernel(void)
{
pthread_mutex_init(&ScheduleLock, 0);
pthread_cond_init(&ScheduleCond, NULL);
}
}
-void WaitForExit(void)
+void Kernel_Run(void)
{
while(1)
{
AcquireLock();
- WaitForCondition(&ScheduleCond, &ScheduleLock, 10);
+ WaitForCondition(&ScheduleCond, &ScheduleLock, COND_WAIT_TIMEOUT_MS);
if (!ReadyQueue.head)
{
bool done = true;
for (int i = 0; i < 5; i++)
{
printf("%d Hello from task 1\n", CpuID);
- Yield();
+ Kernel_Yield();
}
}
for (int i = 0; i < 5; i++)
{
printf("%d Hello from task 2\n", CpuID);
- Yield();
+ Kernel_Yield();
}
}
(void)argc;
(void)argv;
- Init();
+ Kernel();
- SpawnTask(task1, 0, 0);
- SpawnTask(task2, 0, 0);
+ Kernel_Spawn(task1, 0, 0);
+ Kernel_Spawn(task2, 0, 0);
/* wait for all jobs to be done */
- WaitForExit();
+ Kernel_Run();
puts("done");
return 0;