Metropoli BBS
VIEWER: task.cc MODE: TEXT (ASCII)
#include <stdio.h>
#include <string.h>
#include <pc.h>

#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);
}
[ RETURN TO DIRECTORY ]