#include #include #include #include "Task.h" #define dprintf if(0)printf Task *thisTask=0; static Task *task_list=0; void TaskList() { Task *t; for (t=task_list; t; t=t->next) { char *rs="Unknown"; switch (t->run_state) { case Task::Running: rs="Running"; break; case Task::Blocked: rs="Blocked"; break; case Task::Waiting: rs="Waiting"; break; case Task::Dead: rs="Dead"; break; } dprintf(" 0x%08x p=0x%08x s=%s\n", t, t->parent, rs); } } static int fall_off_end() { int rv; asm("movl %%eax,%0" : "=g" (rv) ); Return(rv); return 0; } Task::Task(TaskProc proc, int val, void* ptr, int stacksize) { prev = 0; next = task_list; if (task_list) task_list->prev = this; task_list = this; parent = thisTask; run_state = Running; memset(state, 0, sizeof(state)); stack = 0; if (proc) { stack_len = stacksize; stack = new unsigned[stacksize]; unsigned *sp = stack+stacksize; *--sp = (unsigned) ptr; *--sp = (unsigned) val; *--sp = (unsigned) fall_off_end; state->esp = (unsigned)(stack+stacksize-3); state->eip = (unsigned long) proc; } if (thisTask == 0) thisTask = this; dprintf("Task::Task -> 0x%x\n", this); } Task::~Task() { dprintf("Task::~Task <= 0x%x\n", this); if (task_list == this) task_list = next; if (prev) prev->next = next; if (next) next->prev = prev; if (parent) parent->run_state = Running; if (stack) delete stack; if (this == thisTask) Yield(); TaskList(); } int Task::ReturnValue() { return ret_val; } int Wait(Task* child) { int rv; int waiting = 1; if (child) dprintf("Task::Wait for 0x%x\n", child); else dprintf("Task::Wait\n"); while (waiting) { waiting = 0; if (child) { if (child->run_state == Task::Dead) { rv = child->ret_val; delete child; return rv; } } Task *t, *tn; for (t=task_list; t; t=tn) { tn = t->next; if (t->parent == thisTask) { if (t->run_state == Task::Dead) { dprintf("Dead child 0x%x\n", t); delete t; } else { dprintf("Running child 0x%x\n", t); waiting = 1; } } } if (waiting) { dprintf("parent waiting...\n"); thisTask->run_state = Task::Waiting; Yield(); } } } void Return(int rv) { dprintf("Task::Return(%d) <- 0x%x\n", rv, thisTask); thisTask->ret_val = rv; thisTask->run_state = Task::Dead; if (thisTask->parent) thisTask->parent->run_state = Task::Running; Yield(); } void Yield() { dprintf("Task::Yield 0x%x -> ", thisTask); fflush(stdout); if (setjmp(thisTask->state)) return; while (1) { if (thisTask->next) thisTask = thisTask->next; else thisTask = task_list; if (thisTask->run_state == Task::Running) break; } dprintf("0x%x (0x%x)\n", thisTask, thisTask->state->eip); longjmp(thisTask->state,1); }