#include "task.h" void setclock(long t) { if (clock) task_error(E_SETCLOCK,0); clock = t; } int in_error = 0; int task_error(int n, object* oo) { if (in_error) exit(in_error); else in_error = n; if (error_fct) { n = (*error_fct)(n,oo); if (n) exit(n); } else { print_error(n); exit(n); } in_error = 0; return 0; } char* error_name[] = { "", "object.delete(): has chain", "object.delete(): on chain", "qhead.get(): empty", "qhead.putback(): object on other queue", "qhead.putback(): full", "qtail.put(): object on other queue", "qtail.put(): full", "set_clock(): clock!=0", "schedule(): clock_task not idle", "schedule: terminated", "schedule: running", "schedule: clock<0", "schedule: task or timer on other queue", "histogram.new(): bad arguments", "task.save(): stack overflow", "new: free store exhausted", "task.new(): bad mode", "task.delete(): not terminated", "task.preempt(): not running", "timer.delete(): not terminated", "schedule: bad time", "schedule: bad object", "queue.delete(): not empty", "thistask->result()", "task.wait(thistask)", }; void print_error(int n) { register i = (n<1 || MAXERR<n) ? 0 : n; printf("\n\n***** task_error(%d) %s\n",n,error_name[i]); if (thistask) { printf("thistask: "); thistask->print(VERBOSE|STACK); } if (run_chain) { printf("run_chain:\n"); run_chain->print(CHAIN); } } /* task_error */ sched* run_chain = 0; task* task_chain = 0; long clock = 0; task* thistask = 0; task* clock_task = 0; PFIO error_fct = 0; /*PFIO sched_fct = 0;*/ PFV exit_fct = 0; void sched.cancel(int res) { if (s_state==RUNNING) remove(); s_state = TERMINATED; s_time = res; alert(); } int sched.result() /* wait for termination and retrieve result */ { if (this == (sched*)thistask) task_error(E_RESULT,0); while (s_state != TERMINATED) { remember(thistask); thistask->sleep(); forget(thistask); } return (int) s_time; } void sched.schedule() /* schedule either clock_task or front of run_chain */ { register sched* p; register long tt; lll: if (p = run_chain) { run_chain = (sched*) p->o_next; p->o_next = 0; } else { if (exit_fct) (*exit_fct)(); exit(0); } tt = p->s_time; if (tt != clock) { if (tt < clock) task_error(E_SCHTIME,this); clock = tt; if (clock_task) { if (clock_task->s_state != IDLE) task_error(E_CLOCKIDLE,this); /* clock_task preferred */ p->o_next = (object*) run_chain; run_chain = p; p = (sched*) clock_task; } } switch (p->o_type) { case TIMER: /* time is up; "delete" timer & schedule next task */ p->s_state = TERMINATED; p->alert(); goto lll; case TASK: if (p != this) { if (thistask && thistask->s_state != TERMINATED) thistask->save(); thistask = (task*) p; thistask->restore(); } break; default: task_error(E_SCHOBJ,this); } } /* schedule */ void sched.insert(int d, object* who) /* schedule THIS to run in ``d'' time units inserted by who */ { register sched * p; register sched * pp; register long tt = s_time = clock + d; switch (s_state) { case TERMINATED: task_error(E_RESTERM,this); break; case IDLE: break; case RUNNING: if (this != (class sched *)thistask) task_error(E_RESRUN,this); } if (d<0) task_error(E_NEGTIME,this); if (o_next) task_error(E_RESOBJ,this); s_state = RUNNING; if (o_type == TASK) ((task *) this)->t_alert = who; /* run_chain ordered by s_time */ if (p = run_chain) { if (tt < p->s_time) { o_next = (object*) run_chain; run_chain = this; } else { while (pp = (sched *) p->o_next) { if (tt < pp->s_time) { o_next = pp; p->o_next = this; return; } else p = pp; } p->o_next = this; } } else run_chain = this; } void sched.remove() /* remove from run_chain and make IDLE */ { register class sched * p; register class sched * pp; if (p = run_chain) if (p == this) run_chain = (sched*) o_next; else for (; pp = (sched*) p->o_next; p=pp) if (pp == this) { p->o_next = pp->o_next; goto ll; } ll: s_state = IDLE; o_next = 0; } void sched.print(int n) { int m = n & ~CHAIN; switch (o_type) { case TIMER: ((timer*)this)->print(m); break; case TASK: ((task*)this)->print(m); break; } if (n&CHAIN) { if (o_next) ((sched*) o_next)->print(n); } }