/*ident "@(#)C++env:incl-master/const-headers/task.h 1.6" */ /************************************************************************** Copyright (c) 1984 AT&T All Rights Reserved THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T The copyright notice above does not evidence any actual or intended publication of such source code. *****************************************************************************/ #ifndef TASKH #define TASKH #pragma "ape/libap.a" #pragma "c++/libC.a" #pragma "c++/libtask.a" /* HEADER FILE FOR THE TASK SYSTEM */ #include #include "label.h" /* like setjmp, but really works */ class object; class sched; /* : public object */ class timer; /* : public sched */ class task; /* : public sched */ class qhead; /* : public object */ class qtail; /* : public object */ class team; #if defined(_SHARED_ONLY) #define DEFAULT_MODE SHARED #else #define DEFAULT_MODE DEDICATED #endif /* error codes */ #define task_error_messages \ macro_start \ macro(0,E_ERROR,"") \ macro(1,E_OLINK,"object::delete(): has chain") \ macro(2,E_ONEXT,"object::delete(): on chain") \ macro(3,E_GETEMPTY,"qhead::get(): empty") \ macro(4,E_PUTOBJ,"qtail::put(): object on other queue") \ macro(5,E_PUTFULL,"qtail::put(): full") \ macro(6,E_BACKOBJ,"qhead::putback(): object on other queue") \ macro(7,E_BACKFULL,"qhead::putback(): full") \ macro(8,E_SETCLOCK,"sched::setclock(): clock!=0") \ macro(9,E_CLOCKIDLE,"sched::schedule(): clock_task not idle") \ macro(10,E_RESTERM,"sched::insert(): cannot schedule terminated sched") \ macro(11,E_RESRUN,"sched::schedule(): running") \ macro(12,E_NEGTIME,"sched::schedule(): clock<0") \ macro(13,E_RESOBJ,"sched::schedule(): task or timer on other queue") \ macro(14,E_HISTO,"histogram::histogram(): bad arguments") \ macro(15,E_STACK,"task::restore() or task::task(): stack overflow") \ macro(16,E_STORE,"new: free store exhausted") \ macro(17,E_TASKMODE,"task::task(): bad mode") \ macro(18,E_TASKDEL,"task::~task(): not terminated") \ macro(19,E_TASKPRE,"task::preempt(): not running") \ macro(20,E_TIMERDEL,"timer::~timer(): not terminated") \ macro(21,E_SCHTIME,"sched::schedule(): runchain corrupted: bad time") \ macro(22,E_SCHOBJ,"sched object used directly (not as base)") \ macro(23,E_QDEL,"queue::~queue(): not empty") \ macro(24,E_RESULT,"task::result(): thistask->result()") \ macro(25,E_WAIT,"task::wait(): wait for self") \ macro(26,E_FUNCS,"FrameLayout::FrameLayout(): function start") \ macro(27,E_FRAMES,"FrameLayout::FrameLayout(): frame size") \ macro(28,E_REGMASK,"task::fudge_return(): unexpected register mask") \ macro(29,E_FUDGE_SIZE,"task::fudge_return(): frame too big") \ macro(30,E_NO_HNDLR,"sigFunc - no handler for signal") \ macro(31,E_BADSIG,"illegal signal number") \ macro(32,E_LOSTHNDLR,"Interrupt_handler::~Interrupt_handler(): signal handler not on chain") \ macro_end(E_LOSTHNDLR) #define macro_start #define macro(num,name,string) const name = num ; #define macro_end(last_name) const MAXERR = last_name; task_error_messages #undef macro_start #undef macro #undef macro_end typedef int (*PFIO)(int,object*); typedef void (*PFV)(); /* print flags, used as arguments to class print functions */ #define CHAIN 1 #define VERBOSE 2 #define STACK 4 /* DATA STRUCTURES */ /* object --> olink --> olink ... | | | ... V V | task task V object --> ... */ class olink /* the building block for chains of task pointers */ { friend object; olink* l_next; task* l_task; olink(task* t, olink* l) { l_task=t; l_next=l; }; }; class object { friend sched; friend task; public: enum objtype { OBJECT, TIMER, TASK, QHEAD, QTAIL, INTHANDLER }; private: olink* o_link; static task* thxstxsk; public: object* o_next; virtual objtype o_type() { return OBJECT; } object() { o_link=0; o_next=0; } virtual ~object(); void remember(task*); // save for alert void forget(task*); // remove all occurrences of task from chain void alert(); // prepare IDLE tasks for scheduling virtual int pending(); // TRUE if this object should be waited for virtual void print(int, int =0); // 1st arg VERBOSE, CHAIN, or STACK static int task_error(int, object*); // the central error function int task_error(int); // obsolete; use static version static task* this_task() { return thxstxsk; } static PFIO error_fct; // user-supplied error function }; // fake compatibility with previous version #define thistask (object::this_task()) void _print_error(int); class sched : public object { // only instances of subclasses are used friend timer; friend task; friend object; friend void _print_error(int n); //friend SIG_FUNC_TYP sigFunc; public: enum statetype { IDLE=1, RUNNING=2, TERMINATED=4 }; private: static int keep_waiting_count; static sched* runchain; // list of ready-to-run scheds (by s_time) static sched* priority_sched; // if non-zero, sched to run next static long clxck; static int exit_status; long s_time; /* time to sched; result after cancel() */ statetype s_state; /* IDLE, RUNNING, TERMINATED */ void schedule(); /* sched clock_task or front of runchain */ virtual void resume(); void insert(long,object*); /* sched for long time units, t_alert=obj */ void remove(); /* remove from runchain & make IDLE */ protected: sched() : s_time(0), s_state(IDLE) {} public: static void setclock(long); static long get_clock() { return clxck; } static sched* get_run_chain() { return runchain; } static int get_exit_status() { return exit_status; } static void set_exit_status( int i ) { exit_status = i; } sched* get_priority_sched() { return priority_sched; } static task* clock_task; // awoken at each clock tick long rdtime() { return s_time; }; statetype rdstate() { return s_state; }; int pending() { return s_state != TERMINATED; } int keep_waiting() { return keep_waiting_count++; } int dont_wait() { return keep_waiting_count--; } void cancel(int); int result(); virtual void setwho(object* t); // who alerted me void print(int, int =0); static PFV exit_fct; // user-supplied exit function }; // for compatibility with pre-2.0 releases, // but conflicts with time.h //#define clock (sched::get_clock()) inline void setclock(long i) { sched::setclock(i); } // for compatibility with pre-2.0 releases #define run_chain (sched::get_run_chain()) class timer : public sched { void resume(); public: timer(long); ~timer(); void reset(long); object::objtype o_type() { return TIMER; } void setwho(object*) { } // do nothing void print(int, int =0); }; /* check stack size if set */ extern _hwm; class task : public sched { friend sched; friend void __task__init(); public: enum modetype { DEDICATED=1, SHARED=2 }; private: static task* txsk_chxin; // list of all tasks static team* team_to_delete; // delete this team after task switch int curr_hwm(); // "high water mark" // (how high stack has risen) int swap_stack(int*,int*); // initialize child stack */ void fudge_return(int*); //used in starting new tasks void copy_share(); // used in starting shared tasks void get_size(); // ditto -- saves size of active stack void resume(); void swap(int); void swapjmp(); void doswap(task *, int); Label copy_task(Label, unsigned long *, unsigned long *); // simple check for stack overflow--not used for main task void settrap(); void checktrap(); /* WARNING: t_framep, th, and t_ap are manipulated as offsets from * task by swap(); those, and t_basep, t_size, and t_savearea are * manipulated as offsets by sswap(). * Do not insert new data members before these. */ Label t_env; // stuff needed to restore process unsigned long t_size; // size of active stack (used for SHARED) // holds hwm after cancel() long t_trap; // used for stack overflow check team *t_team; // stack and info for sharing char *t_savearea; // area SHARED stack saved char *t_save; // area SHARED stack saved modetype t_mode; /* DEDICATED/SHARED stack */ int t_stacksize; object* t_alert; /* object that inserted you */ protected: task(char *name=0, modetype mode=DEFAULT_MODE, int stacksize=0); public: ~task(); object::objtype o_type() { return TASK; } task* t_next; /* insertion in "task_chain" */ char* t_name; static task* get_task_chain() { return txsk_chxin; } int waitvec(object**); int waitlist(object* ...); void wait(object* ob); void delay(long); long preempt(); void sleep(object* t =0); // t is remembered void resultis(int); void cancel(int); void setwho(object* t) { t_alert = t; } void print(int, int =0); object* who_alerted_me() { return t_alert; } }; // for compatibility #define task_chain (task::get_task_chain()) // an Interrupt_handler supplies an interrupt routine that runs when the // interrupt occurs (real time). Also the Interrupt_handler can be waited for. class Interrupt_handler : public object { friend class Interrupt_alerter; //friend SIG_FUNC_TYP sigFunc; int id; // signal or interrupt number int got_interrupt; // an interrupt has been received // but not alerted Interrupt_handler *old; // previous handler for this signal virtual void interrupt(); // runs at real time public: Interrupt_handler(int sig_num); ~Interrupt_handler(); object::objtype o_type() { return INTHANDLER; } int pending(); // FALSE once after interrupt }; /* QUEUE MANIPULATION (see queue.c) */ /* qhead <--> oqueue <--> qtail (qhead, qtail independent) oqueue ->> circular queue of objects */ /* qh_modes */ enum qmodetype { EMODE, WMODE, ZMODE }; class oqueue { friend qhead; friend qtail; int q_max; int q_count; object* q_ptr; qhead* q_head; qtail* q_tail; oqueue(int m) { q_max=m; q_count=0; q_head=0; q_tail=0; }; ~oqueue() { (q_count)?object::task_error(E_QDEL,0):0; }; void print(int); }; class qhead : public object { friend qtail; qmodetype qh_mode; /* EMODE,WMODE,ZMODE */ oqueue* qh_queue; public: qhead(qmodetype = WMODE, int = 10000); ~qhead(); object::objtype o_type() { return QHEAD; } object* get(); int putback(object*); int rdcount() { return qh_queue->q_count; } int rdmax() { return qh_queue->q_max; } qmodetype rdmode() { return qh_mode; } qtail* tail(); qhead* cut(); void splice(qtail*); void setmode(qmodetype m) { qh_mode = m; }; void setmax(int m) { qh_queue->q_max = m; }; int pending() { return rdcount() == 0; } void print(int, int =0); }; class qtail : public object { friend qhead; qmodetype qt_mode; oqueue* qt_queue; public: qtail(qmodetype = WMODE, int = 10000); ~qtail(); object::objtype o_type() { return QTAIL; } int put(object*); int rdspace() { return qt_queue->q_max - qt_queue->q_count; }; int rdmax() { return qt_queue->q_max; }; qmodetype rdmode() { return qt_mode; }; qtail* cut(); void splice(qhead*); qhead* head(); void setmode(qmodetype m) { qt_mode = m; }; void setmax(int m) { qt_queue->q_max = m; }; int pending() { return rdspace() == 0; } void print(int, int =0); }; struct histogram /* "nbin" bins covering the range [l:r] uniformly nbin*binsize == r-l */ { int l, r; int binsize; int nbin; int* h; long sum; long sqsum; histogram(int=16, int=0, int=16); void add(int); void print(); }; /* the result of randint() is always >= 0 */ #define DRAW (randx = randx*1103515245 + 12345) #define ABS(x) (x&0x7fffffff) #define MASK(x) ABS(x) class randint /* uniform distribution in the interval [0,MAXINT_AS_FLOAT] */ { long randx; public: randint(long s = 0) { randx=s; } void seed(long s) { randx=s; } int draw() { return MASK(DRAW); } float fdraw(); }; class urand : public randint /* uniform distribution in the interval [low,high] */ { public: int low, high; urand(int l, int h) { low=l; high=h; } int draw(); }; class erand : public randint /* exponential distribution random number generator */ { public: int mean; erand(int m) { mean=m; }; int draw(); }; // This task will alert Interrupt_handler objects. class Interrupt_alerter : public task { public: Interrupt_alerter(); ~Interrupt_alerter() { cancel (0); } }; extern Interrupt_alerter interrupt_alerter; #endif