+#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
+#include <stdatomic.h>
#include <unistd.h>
#include <pthread.h>
#include <assert.h>
{
if (next && prev != next)
{
- while (!next->stack_top)
+ while (!atomic_load(&next->stack_top))
{
}
}
task->next = NULL;
}
queue->tail = task;
+ task->next = NULL;
if (!queue->head)
{
queue->head = queue->tail;
Task_T* task = queue->head;
if (task)
{
+ queue->head = task->next;
task->next = NULL;
- queue->head = queue->head->next;
if (!queue->head)
{
queue->tail = NULL;
" ret\n"
);
-void Kernel_Yield(void)
+void PickNewTask(bool requeue)
{
AcquireLock();
- printf("CPU %d is yielding\n", CpuID);
Task_T* prev = Running[CpuID].task;
Running[CpuID].task = NULL;
- prev->stack_top = NULL;
- Enter(prev);
- printf("CPU %d is picking task\n", CpuID);
+ atomic_store(&prev->stack_top, NULL);
+ if (requeue)
+ {
+ Enter(prev);
+ }
Running[CpuID].task = Select();
- printf("CPU %d switching to task %p\n", CpuID, Running[CpuID].task);
ReleaseLock();
WaitForTaskFree(prev, Running[CpuID].task);
SwapTask(prev, Running[CpuID].task);
}
+void Kernel_Yield(void)
+{
+ PickNewTask(true);
+}
+
void Kernel_Exit(void)
{
- puts("exiting");
- AcquireLock();
- printf("CPU %d is yielding\n", CpuID);
- Task_T* prev = Running[CpuID].task;
- Running[CpuID].task = NULL;
- prev->stack_top = NULL;
- printf("CPU %d is picking task\n", CpuID);
- Running[CpuID].task = Select();
- printf("CPU %d switching to task %p\n", CpuID, Running[CpuID].task);
- ReleaseLock();
- WaitForTaskFree(prev, Running[CpuID].task);
- SwapTask(prev, Running[CpuID].task);
+ PickNewTask(false);
}
static Task_T* CreateTask(void (*task_fn)(void*), void* arg, int stacksize)
{
*(--task->stack_top) = 0xdeadbeef; // initial values for saved registers
}
- printf("created task %p\n", task);
return task;
}
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 */
AcquireLock();
Enter(task);
ReleaseLock();
static void CpuIdle(void* arg)
{
- printf("CPU %d is started\n", CpuID);
while(1)
{
Kernel_Yield();
- printf("CPU %d is idle\n", CpuID);
AcquireLock();
WaitForCondition(&ScheduleCond, &ScheduleLock, COND_WAIT_TIMEOUT_MS);
ReleaseLock();
CpuID = (long int)arg;
Running[CpuID].idle = CreateTask(CpuIdle, 0, 0);
Running[CpuID].task = Running[CpuID].idle;
- printf("CPU %d initializing\n", CpuID);
StartTask(Running[CpuID].idle);
return NULL; /* unreachable */
}
void task1(void* arg)
{
- for (int i = 0; i < 5; i++)
+ int* val = arg;
+ for (int i = 0; i < 1000; i++)
{
- printf("%d Hello from task 1\n", CpuID);
- Kernel_Yield();
- }
-}
-
-void task2(void* arg)
-{
- for (int i = 0; i < 5; i++)
- {
- printf("%d Hello from task 2\n", CpuID);
+ printf("%d %d\n", *val, CpuID);
Kernel_Yield();
}
}
Kernel();
- Kernel_Spawn(task1, 0, 0);
- Kernel_Spawn(task2, 0, 0);
+ for (int i = 0; i < 100; i++)
+ {
+ int* val = malloc(sizeof(int));
+ *val = i;
+ Kernel_Spawn(task1, val, 0);
+ }
/* wait for all jobs to be done */
Kernel_Run();
- puts("done");
return 0;
}
\ No newline at end of file