static pthread_mutex_t ScheduleLock;
static pthread_cond_t ScheduleCond;
static __thread int CpuID = 0;
+static long int TaskCount = 0;
static TaskQueue_T ReadyQueue = {0};
static TaskQueue_T DeadQueue = {0};
static CpuState_T* Running = NULL;
static int CpuCount;
/***************************************
- Lopck Operations
+ Lock Operations
***************************************/
static void AcquireLock(void)
{
pthread_mutex_unlock(&ScheduleLock);
}
+static void WaitForCondition(pthread_cond_t* cond, pthread_mutex_t* mutex, int ms)
+{
+ struct timespec expire_time;
+ clock_gettime(CLOCK_REALTIME, &expire_time);
+ expire_time.tv_nsec += (ms * 1000);
+ pthread_cond_timedwait(cond, mutex, &expire_time);
+}
+
/***************************************
Queue Operations
***************************************/
static void Enqueue(TaskQueue_T* queue, Task_T* task)
{
- if (task)
+ if (queue->tail)
{
- if (queue->tail)
- {
- queue->tail->next = task;
- task->next = NULL;
- }
- queue->tail = task;
- if (!queue->head)
- {
- queue->head = queue->tail;
- }
+ queue->tail->next = task;
+ task->next = NULL;
+ }
+ queue->tail = task;
+ if (!queue->head)
+ {
+ queue->head = queue->tail;
}
}
Task_T* task = queue->head;
if (task)
{
+ task->next = NULL;
queue->head = queue->head->next;
if (!queue->head)
{
static void Enter(Task_T* task)
{
- if (task)
+ if (task && task != Running[CpuID].idle)
{
Enqueue(&ReadyQueue, task);
pthread_cond_signal(&ScheduleCond);
static Task_T* Select(void)
{
- pthread_cond_signal(&ScheduleCond);
- return Dequeue(&ReadyQueue);
+ Task_T* task = Dequeue(&ReadyQueue);
+ if (!task)
+ {
+ task = Running[CpuID].idle;
+ }
+ else
+ {
+ pthread_cond_signal(&ScheduleCond);
+ }
+ return task;
}
/***************************************
Task Switching Operations
***************************************/
-extern void SwitchTo(Task_T* prev, Task_T* next);
-
+extern void SwapTask(Task_T* prev, Task_T* next);
__asm__(
-"SwitchTo:\n"
+"SwapTask:\n"
" push %rdi\n"
" push %rbp\n"
" push %rbx\n"
" ret\n"
);
+extern void StartTask(Task_T* task);
+__asm__(
+"StartTask:\n"
+" mov (%rdi),%rsp\n"
+" pop %r15\n"
+" pop %r14\n"
+" pop %r13\n"
+" pop %r12\n"
+" pop %rbx\n"
+" pop %rbp\n"
+" pop %rdi\n"
+" ret\n"
+);
+
static void Yield(void)
{
AcquireLock();
- Task_T* next = Select();
- if (next)
- {
- puts("found task");
- Task_T* prev = Running[CpuID].task;
- Enter(prev);
- Running[CpuID].task = next;
- prev = (prev ? prev : &(Task_T){0});
- ReleaseLock();
- SwitchTo(prev, next);
- }
- else
- {
- ReleaseLock();
- }
+ printf("CPU %d is yielding\n", CpuID);
+ Task_T* prev = Running[CpuID].task;
+ Running[CpuID].task = NULL;
+ Enter(prev);
+ 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();
+ SwapTask(prev, Running[CpuID].task);
}
void FinalizeTask(void)
{
- /* mark the current task as dead */
+ puts("exiting");
AcquireLock();
- Running[CpuID].task = NULL;
- pthread_cond_signal(&ScheduleCond);
-// Recycle the task somehow here...
+ TaskCount--;
+ Running[CpuID].task = NULL; // TODO: Enqueue to dead queue
+ Running[CpuID].task = Select();
+ printf("starting task %p\n", Running[CpuID].task);
ReleaseLock();
-
- /* now we loop until there is a task to jump to */
- while(1)
- {
- Yield();
- AcquireLock();
- pthread_cond_wait(&ScheduleCond, &ScheduleLock);
- ReleaseLock();
- }
+ StartTask(Running[CpuID].task);
}
-void CreateTask(void (*task_fn)(void*), void* arg, int stacksize)
+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_top) = 0xdeadbeef; // initial values for saved registers
}
printf("created task %p\n", task);
+ return task;
+}
+void SpawnTask(void (*task_fn)(void*), void* arg, int stacksize)
+{
+ Task_T* task = CreateTask(task_fn, arg, stacksize);
/* put task in the ready queue */
AcquireLock();
+ TaskCount++;
Enter(task);
ReleaseLock();
}
-
+static void CpuIdle(void* arg)
+{
+ printf("CPU %d is started\n", CpuID);
+ while(1)
+ {
+ Yield();
+ printf("CPU %d is idle\n", CpuID);
+ AcquireLock();
+ WaitForCondition(&ScheduleCond, &ScheduleLock, 1);
+ ReleaseLock();
+ }
+}
static void* CpuMain(void* arg)
{
CpuID = (long int)arg;
- FinalizeTask();
- return NULL;
+ 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 */
}
/***************************************
pthread_mutex_init(&ScheduleLock, 0);
pthread_cond_init(&ScheduleCond, NULL);
CpuCount = sysconf(_SC_NPROCESSORS_ONLN);
+// CpuCount = 1;
Running = calloc(CpuCount, sizeof(CpuState_T));
for (long int i = 0; i < CpuCount; i++)
{
pthread_create(&Running[i].thread, NULL, CpuMain, (void*)i);
}
- CreateTask(task1, 0, 0);
- CreateTask(task2, 0, 0);
+ SpawnTask(task1, 0, 0);
+ SpawnTask(task2, 0, 0);
/* wait for all jobs to be done */
while(1)
{
AcquireLock();
- pthread_cond_wait(&ScheduleCond, &ScheduleLock);
- if (!ReadyQueue.head)
+ WaitForCondition(&ScheduleCond, &ScheduleLock, 10);
+// printf("%ld %d %p\n", TaskCount, CpuCount, ReadyQueue.head);
+ if (TaskCount == 0)
{
- long int val = 0;
- for (int i = 0; i < CpuCount; i++)
- {
- val |= (long int)Running[i].task;
- }
- if (!val)
+ break;
+ }
+// else
+ {
+ printf("count: %ld\n", TaskCount);
+ printf("head: %p\n", ReadyQueue.head);
+ printf("tasks:\n");
+ for (long int i = 0; i < CpuCount; i++)
{
- break;
+ if (Running[i].task == Running[i].idle)
+ {
+ printf(" %02ld idle\n", i);
+ }
+ else
+ {
+ printf(" %02ld %p\n", i, Running[i].task);
+ }
}
+
}
ReleaseLock();
}