#!/bin/sh # This is a shar archive. # The rest of this file is a shell script which will extract: # # 7_10main.c 7_10po.h 7_10pr0.h 7_10pr1.h 7_10pr2.h 7_10pr3.h 7_10process.h 7_10q.h 7_10sk1.c 7_10sk2.c int_pending.c makefile mapping p_cons.c p_des.c p_dumpall.c p_exit.c p_kill.c p_main.c p_pause.c p_pending.c p_restore.c p_result.c p_rmlist.c p_runtask.c p_save.c p_schedule.c p_setprior.c p_shuffle.c p_sleep.c p_stime.c p_wait.c p_waitvec.c p_wakeup.c # po_alert.c po_dest.c po_error.c po_forget.c po_pending.c po_print.c process.h ps_print.c qh_cons.c qh_cut.c qh_des.c qh_get.c qh_pending.c qh_putback.c qh_splice.c qh_tail.c qm_print.c qt_cons.c qt_cut.c qt_des.c qt_head.c qt_pending.c qt_put.c qt_splice.c sem_pending.c stackdir.h stchk.c stkdir.c test1.c test1.cmp test2.c test2.cmp test2.h test3.c test3.cmp test4.c test4.cmp test4.err test5.c test5.cmp test6.c test6.cmp # # To extract the files from this shell archive file simply # create a directory for this file, move the archive file # to it and enter the command # # sh filename # # The files will be extracted automatically. # Note: Do not use csh. # # Archive created: Mon Jul 30 23:11:24 EDT 1990 # echo x - 7_10main.c sed 's/^X//' > 7_10main.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ // provide safe access to t_mainprocess, // a pseudo-process for main() inline process *const main_process() { return process::t_mainprocess; } // provide safe access to t_thisprocess inline process *const this_process() { return process::t_thisprocess; } !EOF! ls -l 7_10main.c echo x - 7_10po.h sed 's/^X//' > 7_10po.h << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ // typedefs to ease some declarations typedef void (*PVFPC)(char*); typedef void (*PVFV)(); // for maintaining a list of processes class process_link { friend class process_object; process *pl_process; process_link *pl_next; process_link(process *t, process_link *pl) { pl_process = t; pl_next = pl; } }; // The basis of the process system. class process_object { // protected: friend class process; friend class queue_head; friend class queue_tail; process_object *po_next; // to chain process_objects process_link *po_link; // the process memory // user-supplied error function static void (*po_error_fct)(char*); public: process_object() { po_next = 0; po_link = 0; } ~process_object(); // return T if object is not available yet virtual int pending(); // add process to object's memory void remember(process *t) { po_link = new process_link(t, po_link); } // reschedule all idle remembered processes void alert(); // remove process from object's memory void forget(process *); // main error function void error(char*); // allow user to set po_error_fct PVFPC set_error_function(PVFPC); virtual ostream &print(ostream&); // DELETE }; !EOF! ls -l 7_10po.h echo x - 7_10pr0.h sed 's/^X//' > 7_10pr0.h << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ enum process_states { TASK_IDLE, TASK_RUNNABLE, TASK_TERMINATED, TASK_CURRENT }; extern char *ps_print(process_states); // DELETE !EOF! ls -l 7_10pr0.h echo x - 7_10pr1.h sed 's/^X//' > 7_10pr1.h << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ // class process private data // private: // process state data long t_result; // value to be returned int t_priority; // process priority unsigned long t_desiredtime; // for sleep() process_states t_curstate; // current state of process process *t_next; // for chaining processes // data for the stack swapping char *t_stack; // the place to save the stack unsigned t_stacksize; // the amount of stack saved jmp_buf t_jb; // for setjmp()/longjmp() !EOF! ls -l 7_10pr1.h echo x - 7_10pr2.h sed 's/^X//' > 7_10pr2.h << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ // class process private static variables // private: static process *t_thisprocess; // this for current process static process *t_mainprocess; // this for main() static process *t_runprocesses; // all runnable processes static process *t_waitprocesses; // all waiting processes static process *t_doneprocesses; // all terminated processes static unsigned long t_curtime; // the pseudo-time's clock static char *t_stackbase; // bottom of the stack static void (*t_exit_fct)(); // function called at end !EOF! ls -l 7_10pr2.h echo x - 7_10pr3.h sed 's/^X//' > 7_10pr3.h << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ // class process private member functions // private: // Check if this function is above the low-water mark. int mustrecurse() { return Stackdir.less(Stackdir.plusone(), t_stackbase); } // Used by pause(), wait(), sleep(). // Save the current state of this process. // Returns true when coming back from another process. int contextswitch(); // Used by pause(), wait(), sleep(). // Find the next class to run // and call restore() on it. void schedule(); // Used by schedule(). // Restore a process to be the current process. // It doesn't return but instead comes back // through contextswitch(). // It copies a process' copy of the stack into // the stack and longjmp's there. void restore(); // Used by schedule() and wakeup(). // Move the top process to its place time and // priority-wise in the list of runnable processes. void shufflerunlist(); // Remove a process from a given list. // Return 0 if not found on the list. int rmfromlist(process *, process**); // the real version of the destructor void Rprocessdest(); // Reschedule the process for d time units from now. void wakeup(unsigned long = 0); !EOF! ls -l 7_10pr3.h echo x - 7_10process.h sed 's/^X//' > 7_10process.h << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ // all discrete events are derived from class process class process : public process_object { // private: ... #include "7_10pr1.h" /* DELETE */ #include "7_10pr2.h" /* DELETE */ #include "7_10pr3.h" /* DELETE */ public: friend process_object; char *t_name; // the name of this process process(char *name = 0); ~process(); // process manipulation void exec(); // run the process virtual long main(); // the actual process int pending(); // 1 until process completed void exit(long); // end process with value long result(); // get exit value of process void kill(long = 0); // stop process // allow user to set t_exit_fct PVFV atexit(PVFV); // Stop this process until one of the // objects becomes available int wait(process_object **); int wait(process_object*, process_object* = 0, process_object* = 0, process_object* = 0, process_object* = 0, process_object* = 0); // Stop until rescheduled, then // alert a process_object. void pause(process_object* = 0); // Stop until time comes along void sleep(unsigned long); // pseudo-time manipulation unsigned long time() // Get current time { return t_curtime; } void stime(unsigned long); // Set current time // priority manipulation int getpriority() // Get current priority { return t_priority; } int setpriority(int); // Set current priority // a pseudo-process for main() friend process *const main_process(); // provide safe access to t_thisprocess friend process *const this_process(); ostream &print(ostream&); // DELETE void dumpall(ostream&); // DELETE }; !EOF! ls -l 7_10process.h echo x - 7_10q.h sed 's/^X//' > 7_10q.h << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ // modes for a process_queue enum qmodes { Q_WMODE, // context switch when full/empty Q_ZMODE, // ignore objects when full/empty Q_EMODE // error when full/empty }; extern char *qm_print(qmodes); // DELETE // queue manipulation class process_queue { friend queue_head; friend queue_tail; queue_head *q_head; queue_tail *q_tail; process_object *q_last; unsigned q_max; unsigned q_count; process_queue(unsigned m, queue_head *qh, queue_tail *qt) { q_max = m; q_count = 0; q_head = qh; q_tail = qt; } ~process_queue() { if (q_count) error("delete queue with members"); } }; class queue_head : public process_object { friend queue_tail; process_queue *qh_queue; public: qmodes qh_mode; queue_head(qmodes = Q_WMODE, unsigned = 10000); ~queue_head(); process_object *get(); int unget(process_object*); queue_tail *tail(); queue_head *cut(); void splice(queue_tail*); // manipulate the maximum unsigned rd_max() { return qh_queue->q_max; } void set_max(unsigned m) { qh_queue->q_max = m; } unsigned rd_count() { return qh_queue->q_count; } int pending(); // does queue_head have an object? // T <== rd_count() == 0 }; class queue_tail : public process_object { friend queue_head; process_queue *qt_queue; public: qmodes qt_mode; queue_tail(qmodes = Q_WMODE, unsigned = 10000); ~queue_tail(); int put(process_object*); queue_head *head(); queue_tail *cut(); void splice(queue_head*); // manipulate the maximum unsigned rd_max() { return qt_queue->q_max; } void set_max(unsigned m) { qt_queue->q_max = m; } unsigned rd_space() { return qt_queue->q_max - qt_queue->q_count; } int pending(); // does queue_tail have room? // T <== rd_space() == 0 }; !EOF! ls -l 7_10q.h echo x - 7_10sk1.c sed 's/^X//' > 7_10sk1.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ int main(int argc, char **argv) { int m0; one(); } one(int o0) { int o1; two(); } two(int t0) { int t2; } !EOF! ls -l 7_10sk1.c echo x - 7_10sk2.c sed 's/^X//' > 7_10sk2.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include class A: public process { public: A(); long main() { //... pause(this); //... } }; int main(int, char **) { A a, b; a.exec(); b.exec(); a.alert(); //... } !EOF! ls -l 7_10sk2.c echo x - int_pending.c sed 's/^X//' > int_pending.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ #include /* DELETE */ int interrupt::pending() { if (debug) /*DELETE*/ cerr << "interrupt" << this << "::pending()\n"; if (debug) /*DELETE*/ cerr << "<<<< interrupt" << this << "::pending() <- 1\n"; return 1; // ???????????????? } !EOF! ls -l int_pending.c echo x - makefile sed 's/^X//' > makefile << '!EOF!' CC= b6CC -I. -I../../CC CFLAGS= -g ERROR= ../../error.a all: test1 test2 test3 test4 test5 test6 OBJ= po_dest.o po_error.o po_alert.o po_pending.o \ po_forget.o po_print.o \ qh_cons.o qh_cut.o qh_des.o qh_get.o qh_pending.o qh_putback.o qh_splice.o qh_tail.o \ qt_cons.o qt_cut.o qt_des.o qt_head.o qt_pending.o qt_put.o qt_splice.o \ qm_print.o ps_print.o \ sem_pending.o \ int_pending.o \ stkdir.o \ p_cons.o p_des.o p_dumpall.o \ p_exit.o p_kill.o p_main.o p_pause.o p_pending.o \ p_restore.o p_result.o p_rmlist.o \ p_runtask.o p_save.o p_schedule.o p_stime.o \ p_setprior.o p_shuffle.o p_sleep.o p_wait.o p_waitvec.o p_wakeup.o test1: test1.o $(OBJ) ; $(CC) -o test1 $(CFLAGS) test1.o $(OBJ) $(ERROR) test2: test2.o $(OBJ) ; $(CC) -o test2 $(CFLAGS) test2.o $(OBJ) $(ERROR) test3: test3.o $(OBJ) ; $(CC) -o test3 $(CFLAGS) test3.o $(OBJ) $(ERROR) test4: test4.o $(OBJ) ; $(CC) -o test4 $(CFLAGS) test4.o $(OBJ) $(ERROR) test5: test5.o $(OBJ) ; $(CC) -o test5 $(CFLAGS) test5.o $(OBJ) $(ERROR) test6: test6.o $(OBJ) ; $(CC) -o test6 $(CFLAGS) test6.o $(OBJ) $(ERROR) stchk: stchk.o stkdir.o $(CC) -o stchk $(CFLAGS) stchk.o stkdir.o STHDRS= 7_10po.h 7_10process.h 7_10pr0.h 7_10pr1.h 7_10pr2.h 7_10pr3.h HDRS= process.h stackdir.h 7_10q.h $(STHDRS) int_pending.o: int_pending.c $(HDRS) qm_print.o: qm_print.c $(HDRS) qh_cons.o: qh_cons.c $(HDRS) qh_cut.o: qh_cut.c $(HDRS) qh_des.o: qh_des.c $(HDRS) qh_get.o: qh_get.c $(HDRS) qh_pending.o: qh_pending.c $(HDRS) qh_putback.o: qh_putback.c $(HDRS) qh_splice.o: qh_splice.c $(HDRS) qh_tail.o: qh_tail.c $(HDRS) qt_cons.o: qt_cons.c $(HDRS) qt_cut.o: qt_cut.c $(HDRS) qt_des.o: qt_des.c $(HDRS) qt_head.o: qt_head.c $(HDRS) qt_pending.o: qt_pending.c $(HDRS) qt_put.o: qt_put.c $(HDRS) qt_splice.o: qt_splice.c $(HDRS) sem_pending.o: sem_pending.c $(HDRS) stkdir.o: stkdir.c $(STHDRS) stchk.o: stchk.c $(STHDRS) p_cons.o: p_cons.c $(HDRS) p_des.o: p_des.c $(HDRS) p_dumpall.o: p_dumpall.c $(HDRS) p_exit.o: p_exit.c $(HDRS) p_kill.o: p_kill.c $(HDRS) p_main.o: p_main.c $(HDRS) p_pause.o: p_pause.c $(HDRS) p_pending.o: p_pending.c $(HDRS) p_restore.o: p_restore.c $(HDRS) p_result.o: p_result.c $(HDRS) p_rmlist.o: p_rmlist.c $(HDRS) p_runtask.o: p_runtask.c $(HDRS) p_save.o: p_save.c $(HDRS) p_schedule.o: p_schedule.c $(HDRS) p_setprior.o: p_setprior.c $(HDRS) p_stime.o: p_stime.c $(HDRS) p_shuffle.o: p_shuffle.c $(HDRS) p_sleep.o: p_sleep.c $(HDRS) p_wait.o: p_wait.c $(HDRS) p_waitvec.o: p_waitvec.c $(HDRS) p_wakeup.o: p_wakeup.c $(HDRS) test1.o: test1.c $(HDRS) test2.o: test2.c $(HDRS) test3.o: test3.c $(HDRS) test4.o: test4.c $(HDRS) test5.o: test5.c $(HDRS) test6.o: test6.c $(HDRS) po_alert.o: po_alert.c $(HDRS) po_dest.o: po_dest.c $(HDRS) po_error.o: po_error.c $(HDRS) po_forget.o: po_forget.c $(HDRS) po_pending.o: po_pending.c $(HDRS) po_print.o: po_print.c $(HDRS) ps_print.o: ps_print.c $(HDRS) OUT= test1.out test2.out test3.out test4.out test5.out test6.out CMP= test1.cmp test2.cmp test3.cmp test4.cmp test5.cmp test6.cmp test1.out: test1 ; ./test1 2>/dev/null > test1.out test2.out: test2 ; ./test2 2>/dev/null > test2.out test3.out: test3 ; ./test3 2>/dev/null > test3.out test4.out: test4 ; ./test4 2>/dev/null > test4.out test5.out: test5 ; ./test5 2>/dev/null > test5.out test6.out: test6 ; ./test6 2>/dev/null > test6.out test: $(OUT) $(CMP) cmp test1.out test1.cmp cmp test2.out test2.cmp cmp test3.out test3.cmp cmp test4.out test4.cmp cmp test5.out test5.cmp cmp test6.out test6.cmp !EOF! ls -l makefile echo x - mapping sed 's/^X//' > mapping << '!EOF!' void object::remember(task*) -> void task_object::remember(task*) void object::forget(task*) -> void task_object::forget(task*) void object::alert() -> void task_object::alert() int object::pending() -> int task_object::pending() int object::task_error(int) -> void task_object::error(char*) task* object::this_task() -> task* this_task() PVFPC set_error_function(PVFPC) sched::insert(d) -> task::wakeup(d) sched::remove() -> task::rmfromlist(this,&t_runtasks), set idle task::task() -> task::task(), task::main(), task::runtask() task::save() -> task::save() task::restore() -> task::restore() task::cancel(ret) -> task::kill(ret) task::~task() -> task::~task() task::resultis(ret) -> task::exit(ret) task::sleep(obj*) -> task::rsleep(obj*) task::delay(d) -> task::sleep(d) task::resume() -> ? task::schedule() -> task::save() && task::schedule() !EOF! ls -l mapping echo x - p_cons.c sed 's/^X//' > p_cons.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include #include /* DELETE */ static char _tmpmainprocess; static process *const tmpmainprocess = (process*)&_tmpmainprocess; process::process(char *nname) { // set the local variables t_name = nname ? nname : "no-name"; if (debug) /*DELETE*/ cerr << "process" << this << "::process(" << (nname ? nname : "NULL") << ")\n"; if (debug) /*DELETE*/ cerr << "\tprocess: thisprocess == " << t_thisprocess << "\n"; if (debug) /*DELETE*/ cerr << "\tprocess: t_mainprocess == " << t_mainprocess << "\n"; t_stack = 0; t_stacksize = 0; t_result = 1; t_priority = 0; t_next = 0; t_desiredtime = 0; t_curstate = TASK_IDLE; // create a process for main() if (!t_mainprocess) { if (debug) /*DELETE*/ cerr << "\tcreate main process\n"; t_mainprocess = tmpmainprocess; t_thisprocess = t_mainprocess = new process("main"); if (debug) /*DELETE*/ cerr << "\tmainprocess <- " << t_mainprocess << "\n"; } if (debug) /*DELETE*/ cerr << "<<<< process" << this << "::process()\n"; } // DELETE ostream &process::print(ostream &out) // DELETE { // DELETE if (this) // DELETE { // DELETE out << "["; // DELETE if (debug>1) out << form("%#x", this) << ","; // DELETE if (this == tmpmainprocess) // DELETE out << "tmpmainprocess]"; // DELETE else // DELETE out << this->t_name << "]"; // DELETE } // DELETE else // DELETE out << "[NULL]"; // DELETE return out; // DELETE } // DELETE !EOF! ls -l p_cons.c echo x - p_des.c sed 's/^X//' > p_des.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ process::~process() { Rprocessdest(); } void process::Rprocessdest() { if (debug) /*DELETE*/ cerr << "process" << this << "::~process()\n"; if (debug) /*DELETE*/ cerr << "\t" << this << "->t_curstate == " << ps_print(t_curstate) << "\n"; if (mustrecurse()) Rprocessdest(); else { if (t_curstate != TASK_TERMINATED) error("process not terminated"); if (debug) /*DELETE*/ cerr << "\tt_thisprocess == " << t_thisprocess << "\n"; rmfromlist(this, &t_doneprocesses); if (this == t_thisprocess) { delete (char*) t_thisprocess; t_thisprocess = 0; schedule(); } if (debug) /*DELETE*/ cerr << "<<<< process" << this << "::~process()\n"; } } !EOF! ls -l p_des.c echo x - p_dumpall.c sed 's/^X//' > p_dumpall.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ #define prprocess(p) \ do { \ out << "\t\t" << p << "\n"; \ out << "\t\t\tt_curstate == " << ps_print(p->t_curstate) << "\n"; \ out << "\t\t\tt_result == " << p->t_result << "\n"; \ out << "\t\t\tt_desiredtime == " << p->t_desiredtime << "\n"; \ } while(0) void process::dumpall(ostream &out) { out << "process::dumpall()\n"; out << "\tt_curtime == " << t_curtime << "\n"; out << "\tt_thisprocess:\n"; prprocess(t_thisprocess); out << "\twait processes:\n"; for (process *p = t_waitprocesses; p; p = p->t_next) prprocess(p); out << "\trun processes:\n"; for (p = t_runprocesses; p; p = p->t_next) prprocess(p); out << "\tdone processes:\n"; for (p = t_doneprocesses; p; p = p->t_next) prprocess(p); } !EOF! ls -l p_dumpall.c echo x - p_exit.c sed 's/^X//' > p_exit.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // stop this process with this exitcode void process::exit(long exitcode) { if (debug) /*DELETE*/ cerr << "process" << this << "::exit(" << exitcode << ")\n"; if (mustrecurse()) exit(exitcode); else { kill(exitcode); if (this == t_thisprocess) if (!contextswitch()) schedule(); if (debug) /*DELETE*/ cerr << "<<<< process" << this << "::exit(" << exitcode << ")\n"; } } !EOF! ls -l p_exit.c echo x - p_kill.c sed 's/^X//' > p_kill.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ void process::kill(long res) { if (debug) /*DELETE*/ cerr << "process" << this << "::kill(" << res << ")\n"; if (debug) /*DELETE*/ cerr << "\t" << this << "->t_curstate == " << ps_print(t_curstate) << "\n"; if (t_curstate == TASK_RUNNABLE) rmfromlist(this, &t_runprocesses); else if (t_curstate == TASK_IDLE) rmfromlist(this, &t_waitprocesses); t_curstate = TASK_TERMINATED; t_next = t_doneprocesses; t_doneprocesses = this; if (debug) /*DELETE*/ cerr << "\t" << this << "->t_curstate <- " << ps_print(t_curstate) << "\n"; t_result = res; alert(); if (debug) /*DELETE*/ cerr << "<<<< process" << this << "::kill(" << res << ")\n"; } !EOF! ls -l p_kill.c echo x - p_main.c sed 's/^X//' > p_main.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ long process::main() { error("no derived definition for process::main()"); return 1; } !EOF! ls -l p_main.c echo x - p_pause.c sed 's/^X//' > p_pause.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // Stop this process until rescheduled by something. // Make certain that the process_object alertobj wakes us up. void process::pause(process_object *alertobj) { if (debug) /*DELETE*/ cerr << "process" << this << "::pause(" << alertobj << ")\n"; if (mustrecurse()) pause(); else { if (alertobj) alertobj->remember(this); if ((this == t_thisprocess) || rmfromlist(this, &t_runprocesses) || rmfromlist(this, &t_waitprocesses)) { t_next = t_waitprocesses; t_waitprocesses = this; t_curstate = TASK_IDLE; } if (debug) /*DELETE*/ cerr << "\t" << this << "->t_curstate <- " << ps_print(t_curstate) << "\n"; // save and schedule another process if (this == t_thisprocess) if (!contextswitch()) schedule(); if (debug) /*DELETE*/ cerr << "<<<< process" << this << "::pause(" << alertobj << ")\n"; } } !EOF! ls -l p_pause.c echo x - p_pending.c sed 's/^X//' > p_pending.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ int process::pending() { if (debug) /*DELETE*/ cerr << "process" << this << "::pending()\n"; if (debug) /*DELETE*/ cerr << "\t" << this << "->t_curstate == " << ps_print(t_curstate) << "\n"; if (debug) /*DELETE*/ cerr << "<<<< process" << this << "::pending() <- " << (t_curstate != TASK_TERMINATED) << "\n"; return t_curstate != TASK_TERMINATED; } !EOF! ls -l p_pending.c echo x - p_restore.c sed 's/^X//' > p_restore.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ #include // Restore a process to be the current process. // It doesn't return but instead comes back // through contextswitch(). It works by memcpy()'ing the // process' copy of the stack into the real stack. // First adjust the stack to make certain that // we are above that which needs to be restored. // This is done by recursively invoking restore(). static void restorestack(char *lowerbound, char *from, unsigned size, jmp_buf jb) { memcpy(lowerbound, from, size); longjmp(jb, 1); /* NOTREACHED */ } void process::restore() { char x; char *px = &x; if (debug) /*DELETE*/ cerr << "process" << this << "::restore()\n"; if (debug) /*DELETE*/ cerr << "\tgrows_up == " << Stackdir.grows_up() << "\n"; if (debug) /*DELETE*/ cerr << "\t&x = "; if (debug>1)/*DELETE*/ cerr << form("%#x", px); if (debug) /*DELETE*/ cerr << "\n"; if (debug) /*DELETE*/ cerr << "\tt_stackbase = "; if (debug>1)/*DELETE*/ cerr << form("%#x", t_stackbase); if (debug) /*DELETE*/ cerr << "\n"; if (debug) /*DELETE*/ cerr << "\tt_stacksize = " << t_stacksize << "\n"; // if necessary, bump up the stack size int diff = Stackdir.diff(px, t_stackbase); if (debug) /*DELETE*/ cerr << "\tpx - t_stackbase = " << diff << "\n"; if (diff < t_stacksize) restore(); // restore the stack char *lowerbound = Stackdir.grows_up() ? t_stackbase : t_stackbase - t_stacksize; t_thisprocess = this; if (debug) /*DELETE*/ cerr << "<<<< process" << this << "::restore()\n"; restorestack(lowerbound, t_stack, t_stacksize, t_jb); /* NOTREACHED */ } !EOF! ls -l p_restore.c echo x - p_result.c sed 's/^X//' > p_result.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // wait for termination and retrieve result long process::result() { if (debug) /*DELETE*/ cerr << "process" << this << "::result()\n"; if (mustrecurse()) return result(); else { if (this == t_thisprocess) error("result called for this_process"); if (debug) /*DELETE*/ cerr << "\t" << this << "->t_curstate == " << ps_print(t_curstate) << "\n"; while (t_curstate != TASK_TERMINATED) { t_thisprocess->pause(this); if (debug) /*DELETE*/ cerr << "\t" << this << "->t_curstate == " << ps_print(t_curstate) << "\n"; } if (debug) /*DELETE*/ cerr << "<<<< process" << this << "::result()\n"; return t_result; } } !EOF! ls -l p_result.c echo x - p_rmlist.c sed 's/^X//' > p_rmlist.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // Remove this process from a given list. // Return 0 if not found on the list. int process::rmfromlist(process *srchprocess, process **stacklist) { if (debug) { /*DELETE*/ cerr << "process" << this << "::rmfromlist(" << srchprocess;/*DELETE*/ if (stacklist == &t_runprocesses) /*DELETE*/ { cerr << ", runprocesses)\n"; } /*DELETE*/ else if (stacklist == &t_waitprocesses) /*DELETE*/ { cerr << ", waitprocesses)\n"; } /*DELETE*/ else if (stacklist == &t_doneprocesses) /*DELETE*/ { cerr << ", doneprocesses)\n"; } /*DELETE*/ else /*DELETE*/ { cerr << ", unknown-list)\n"; } /*DELETE*/ } /*DELETE*/ // search the list for (process **pp = stacklist; *pp; pp = &(*pp)->t_next) if (*pp == srchprocess) { process *sv = *pp; *pp = sv->t_next; sv->t_next = 0; if (debug) /*DELETE*/ cerr << "<<<< process" << this << "::rmfromlist(" << srchprocess << ") <- 1\n"; return 1; } if (debug) /*DELETE*/ cerr << "<<<< process" << this << "::rmfromlist(" << srchprocess << ") <- 0\n"; return 0; } !EOF! ls -l p_rmlist.c echo x - p_runtask.c sed 's/^X//' > p_runtask.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // Run the given process void process::exec() { if (debug) /*DELETE*/ cerr << "process" << this << "::exec()\n"; char x; char *px = &x; if (t_stackbase == 0) { if (debug) /*DELETE*/ cerr << "---- setting t_stackbase <- "; if (debug>1) /*DELETE*/ cerr << form("%#x", &x); if (debug) /*DELETE*/ cerr << "\n"; t_stackbase = px; } if (debug) /*DELETE*/ cerr << "t_stackbase == "; if (debug>1)/*DELETE*/ cerr << form("%#x", t_stackbase); if (debug) /*DELETE*/ cerr << "\n"; if (debug) /*DELETE*/ cerr << "st::plusone == "; if (debug>1)/*DELETE*/ cerr << form("%#x", Stackdir.plusone()); if (debug) /*DELETE*/ cerr << "\n"; if (debug) /*DELETE*/ cerr << "st::diff == " << Stackdir.diff(t_stackbase, Stackdir.plusone()) << "\n"; if (Stackdir.less(px, t_stackbase)) exec(); else { // parent <- thisprocess // set the parent as runnable process *parent = t_thisprocess; if (debug) /*DELETE*/ cerr << "\tparent == " << parent << "\n"; parent->t_next = t_runprocesses; t_runprocesses = parent; parent->t_curstate = TASK_RUNNABLE; if (debug) /*DELETE*/ cerr << "\t" << parent << "->t_curstate <- " << ps_print(parent->t_curstate) << "\n"; if (!parent->contextswitch()) { // in child // child <- thisprocess t_thisprocess = this; t_curstate = TASK_RUNNABLE; if (debug) /*DELETE*/ cerr << "\t" << this << "->t_curstate <- " << ps_print(t_curstate) << "\n"; exit(main()); } } if (debug) /*DELETE*/ cerr << "<<<< process" << this << "::exec()\n"; } !EOF! ls -l p_runtask.c echo x - p_save.c sed 's/^X//' > p_save.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ #include // Save the current state of this process. // Returns true when coming back from another process. int process::contextswitch() { // Copy the stack out, but first make // certain we're above t_stackbase if (debug) /*DELETE*/ cerr << "process" << this << "::contextswitch()\n"; if (mustrecurse()) return contextswitch(); char *px = Stackdir.plusone(); t_stacksize = Stackdir.diff(px, t_stackbase); if (debug) /*DELETE*/ cerr << "\tt_stacksize <- " << t_stacksize << "\n"; if (t_stack) delete t_stack; t_stack = new char[t_stacksize]; if (Stackdir.grows_up()) memcpy(t_stack, t_stackbase, t_stacksize); else memcpy(t_stack, px, t_stacksize); int ret = setjmp(t_jb); if (debug) /*DELETE*/ cerr << "<<<< process" << this << "::contextswitch() <- " << (ret ? "from longjmp" : "from setjmp") << "\n"; return ret; } !EOF! ls -l p_save.c echo x - p_schedule.c sed 's/^X//' > p_schedule.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // Find the next class to run and call restore() on it void process::schedule() { if (debug) /*DELETE*/ cerr << "process" << this << "::schedule()\n"; if (debug) /*DELETE*/ dumpall(cerr); // Make sure t_thisprocess is saved on the run list. if (t_thisprocess && t_thisprocess->t_curstate == TASK_CURRENT) { t_thisprocess->t_next = t_runprocesses; t_desiredtime = 0; t_runprocesses = t_thisprocess; shufflerunlist(); } if (!t_runprocesses) { if (t_exit_fct) (*t_exit_fct)(); if (debug) /*DELETE*/ cerr << "There are no runnable processes\n"; if (t_mainprocess->t_curstate == TASK_TERMINATED) ::exit((int)(t_mainprocess->t_result)); else ::exit(1); } // Now pull off the top process from // t_runprocesses and restore it if (debug) /*DELETE*/ dumpall(cerr); process *res = t_runprocesses; if (debug) /*DELETE*/ cerr << "<<<< process" << this << "::schedule() <- " << res << "\n"; t_runprocesses = t_runprocesses->t_next; if (res->t_desiredtime > 0) t_curtime = res->t_desiredtime; res->t_next = 0; res->t_desiredtime = 0; res->t_curstate = TASK_CURRENT; res->restore(); } !EOF! ls -l p_schedule.c echo x - p_setprior.c sed 's/^X//' > p_setprior.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // Set the process' new priority. Return the old priority. int process::setpriority(int p) { if (debug) /*DELETE*/ cerr << "process" << this << "::setpriority(" << p << ")\n"; int ret = t_priority; t_priority = p; if (debug) /*DELETE*/ cerr << "<<<< process" << this << "::setpriority() <- " << ret << "\n"; return ret; } !EOF! ls -l p_setprior.c echo x - p_shuffle.c sed 's/^X//' > p_shuffle.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // Move the top process on the run list down to its // proper place as ordered by time and priority void process::shufflerunlist() { if (debug) /*DELETE*/ cerr << "process" << this << "::shufflerunlist()\n"; for (process **pp = &t_runprocesses; (*pp)->t_next && (((*pp)->t_desiredtime > (*pp)->t_next->t_desiredtime) || (((*pp)->t_desiredtime == (*pp)->t_next->t_desiredtime) && ((*pp)->t_priority > (*pp)->t_next->t_priority))); ) { process *sv = *pp; process *svn = sv->t_next; *pp = svn; sv->t_next = svn->t_next; svn->t_next = sv; pp = &svn->t_next; } if (debug) /*DELETE*/ cerr << "<<<< process" << this << "::shufflerunlist()\n"; } !EOF! ls -l p_shuffle.c echo x - p_sleep.c sed 's/^X//' > p_sleep.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // delay for a given amount of pseudo-time void process::sleep(unsigned long t) { if (debug) /*DELETE*/ cerr << "process" << this << "::sleep(" << t << ")\n"; if (debug) /*DELETE*/ cerr << "\tt_curtime == " << t_curtime << "\n"; if (mustrecurse()) sleep(t); else { // remove this from other lists // and place back on run queue // ordered by new desired time wakeup(t); // save and schedule another process if (t_thisprocess == this) if (!contextswitch()) schedule(); if (debug) /*DELETE*/ cerr << "<<<< process" << this << "::sleep(" << t << ")\n"; } } !EOF! ls -l p_sleep.c echo x - p_stime.c sed 's/^X//' > p_stime.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // Set the pseudo-clock. void process::stime(unsigned long t) { if (debug) /*DELETE*/ cerr << "process" << this << "::stime(" << t << ")\n"; t_curtime = t; // skip past the beginning processes for (process **pp = &t_runprocesses; *pp && ((*pp)->t_desiredtime == 0); pp = &(*pp)->t_next) if (debug) /*DELETE*/ cerr << "\t" << (*pp) << "-> desiredtime = " << (*pp)->t_desiredtime << ", skipped\n" ; // move all passed-by processes to a safe place process *saveprocs = 0; while (*pp && ((*pp)->t_desiredtime <= t)) { if (debug) /*DELETE*/ cerr << "\t" << (*pp) << "-> desiredtime = " << (*pp)->t_desiredtime << ", saved\n"; process *sv = *pp; process *svn = sv->t_next; *pp = svn; sv->t_next = saveprocs; saveprocs = sv; } // move the processes back onto the run queue while (saveprocs) { if (debug) /*DELETE*/ cerr << "\t" << saveprocs << ", shuffled\n"; process *sv = saveprocs; saveprocs = sv->t_next; sv->t_desiredtime = 0; sv->t_next = t_runprocesses; t_runprocesses = sv; shufflerunlist(); } if (debug) /*DELETE*/ cerr << "<<<< process" << this << "::stime(" << t << ")\n"; } !EOF! ls -l p_stime.c echo x - p_wait.c sed 's/^X//' > p_wait.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // pause until one of the objects // listed becomes available. int process::wait(process_object *obj0, process_object *obj1, process_object *obj2, process_object *obj3, process_object *obj4, process_object *obj5) { if (debug) /*DELETE*/ cerr << "process" << this << "::wait(...)\n"; if (mustrecurse()) return wait(obj0, obj1, obj2, obj3, obj4, obj5); else { process_object *nwaitvec[7]; nwaitvec[0] = obj0; nwaitvec[1] = obj1; nwaitvec[2] = obj2; nwaitvec[3] = obj3; nwaitvec[4] = obj4; nwaitvec[5] = obj5; nwaitvec[6] = 0; int ret = wait(nwaitvec); if (debug) /*DELETE*/ cerr << "<<<< process" << this << "::wait(...) <- " << ret << "\n"; return ret; } } !EOF! ls -l p_wait.c echo x - p_waitvec.c sed 's/^X//' > p_waitvec.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // pause until one of the objects listed // in the vector becomes available. int process::wait(process_object **wv) { if (debug) /*DELETE*/ cerr << "process" << this << "::wait(vec)\n"; if (mustrecurse()) return wait(wv); else { t_desiredtime = 0; for (;;) { // look for object not pending for (int i = 0; wv[i] != 0; i++) { if (!wv[i]->pending()) { // tell everyone to forget us for (int j = 0; wv[j] != 0; j++) wv[j]->forget(this); if (debug) /*DELETE*/ cerr << "<<<< process" << this << "::wait(vec) <- " << i << "\n"; return i; } wv[i]->remember(this); } if ((i == 0) && (wv[0] == (process_object*)this)) error("trying to wait for self"); pause(); } } } !EOF! ls -l p_waitvec.c echo x - p_wakeup.c sed 's/^X//' > p_wakeup.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // Wake up the given process by // moving it to the run list, // possibly with a time offset. void process::wakeup(unsigned long t) { if (debug) /*DELETE*/ cerr << "process" << this << "::wakeup(" << t << ")\n"; if (debug) /*DELETE*/ cerr << "\tt_curtime == " << t_curtime << "\n"; switch (t_curstate) { case TASK_TERMINATED: error("trying to wakeup terminated process"); return; case TASK_IDLE: rmfromlist(this, &t_waitprocesses); break; case TASK_CURRENT: break; case TASK_RUNNABLE: rmfromlist(this, &t_runprocesses); break; } t_desiredtime = t ? t_curtime + t : 0; t_curstate = TASK_RUNNABLE; if (debug) /*DELETE*/ cerr << "\tt_desiredtime <- " << t_desiredtime << "\n"; t_next = t_runprocesses; t_runprocesses = this; shufflerunlist(); if (debug) /*DELETE*/ cerr << "<<<< process" << this << "::wakeup(" << t << ")\n"; } !EOF! ls -l p_wakeup.c echo x - po_alert.c sed 's/^X//' > po_alert.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // schedule idle remembered processes // and flush out the memory void process_object::alert() { if (debug) /*DELETE*/ cerr << "process_object" << this << "::alert()\n"; for (process_link **lp = &po_link; *lp; ) { process_link *sv = *lp; *lp = sv->pl_next; process *tp = sv->pl_process; if (tp->t_curstate == TASK_IDLE) tp->wakeup(0); delete sv; } po_link = 0; if (debug) /*DELETE*/ cerr << "<<<< process_object" << this << "::alert()\n"; } !EOF! ls -l po_alert.c echo x - po_dest.c sed 's/^X//' > po_dest.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ process_object::~process_object() { if (debug) /*DELETE*/ cerr << "process_object" << this << "::~process_object()\n"; if (po_next) error("~process_object(): process_object on chain"); if (po_link) error("~process_object(): process_object has links"); if (debug) /*DELETE*/ cerr << "<<<< process_object" << this << "::~process_object()\n"; } !EOF! ls -l po_dest.c echo x - po_error.c sed 's/^X//' > po_error.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // print an error message and exit // or invoke the user-defined error function void process_object::error(char *s) { static int in_error_fct = 0; // recursive errors aren't allowed if (in_error_fct) ::exit(1); in_error_fct = 1; if (po_error_fct) (*po_error_fct)(s); else { cerr << s << "\n"; ::exit(1); } in_error_fct = 0; } !EOF! ls -l po_error.c echo x - po_forget.c sed 's/^X//' > po_forget.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // remove a process from this object's memory void process_object::forget(process *tp) { if (debug) /*DELETE*/ cerr << "process_object" << this << "::forget(" << tp << ")\n"; if (!po_link) return; for (process_link **lp = &po_link; *lp; ) if ((*lp)->pl_process == tp) { process_link *sv = *lp; *lp = sv->pl_next; delete sv; } else lp = &(*lp)->pl_next; if (debug) /*DELETE*/ cerr << "<<<< process_object::forget(" << tp << ")\n"; } !EOF! ls -l po_forget.c echo x - po_pending.c sed 's/^X//' > po_pending.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // Return 1 if the object should be waited for. // By default say yes and assume that alert() // will be called somehow. int process_object::pending() { if (debug) /*DELETE*/ cerr << "process_object" << this << "::pending()\n"; if (debug) /*DELETE*/ cerr << "<<<< process_object" << this << "::pending() <- 1\n"; return 1; } !EOF! ls -l po_pending.c echo x - po_print.c sed 's/^X//' > po_print.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include ostream &operator<<(ostream &out, process_object *po) { return po->print(out); } ostream &process_object::print(ostream &out) { out << "["; if (debug > 1) out << form("%#x", this); out << "]"; return out; } !EOF! ls -l po_print.c echo x - process.h sed 's/^X//' > process.h << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ // Exercise 7.10 // Implement a library for writing event-driven simulations. #ifndef PROCESS_H # define PROCESS_H #include #include #include #include #include #include "7_10pr0.h" /* EXPAND */ class queue_head; class queue_tail; class process; #include "7_10po.h" /* EXPAND: PVFPC, process_link, process_object */ #include "7_10q.h" /* EXPAND: process_queue, queue_head, queue_tail */ class semaphore : public process_object { public: int pending(); // is semaphore lock clear? }; class interrupt : public process_object { public: int pending(); // is interrupt clear? }; #include "7_10process.h" /* EXPAND class process */ #include "7_10main.c" /* EXPAND main_process(), this_process() */ #endif /* PROCESS_H */ !EOF! ls -l process.h echo x - ps_print.c sed 's/^X//' > ps_print.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ char *ps_print(process_states st) { switch (st) { case TASK_IDLE: return "TASK_IDLE"; case TASK_RUNNABLE: return "TASK_RUNNABLE"; case TASK_TERMINATED: return "TASK_TERMINATED"; case TASK_CURRENT: return "TASK_CURRENT"; default: return "default"; } } !EOF! ls -l ps_print.c echo x - qh_cons.c sed 's/^X//' > qh_cons.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // construct a queue_head and a process_queue queue_head::queue_head(qmodes mode, unsigned max) : qh_mode(mode) { if (debug) /*DELETE*/ cerr << "queue_head" << this << "::queue_head(" << qm_print(mode) << ", " << max << ")\n"; if (max != 0) qh_queue = new process_queue(max, this, 0); if (debug) /*DELETE*/ cerr << "<<<< queue_head" << this << "::queue_head()\n"; } !EOF! ls -l qh_cons.c echo x - qh_cut.c sed 's/^X//' > qh_cut.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // Change // old_queue_head -- old_queue -- old_queue_tail // into // old_queue_head -- new_queue // new_queue_head -- old_queue -- old_queue_tail // where old_queue_head == this // Return new_queue_head. queue_head *queue_head::cut() { if (debug) /*DELETE*/ cerr << "queue_head" << this << "::cut()\n"; process_queue *oldQ = qh_queue; queue_head *new_head = new queue_head(qh_mode, oldQ->q_max); process_queue *newQ = new_head->qh_queue; // put the new head on the old queue oldQ->q_head = new_head; new_head->qh_queue = oldQ; // put the old head on the new queue qh_queue = newQ; newQ->q_head = this; if (debug) /*DELETE*/ cerr << "<<<< queue_head" << this << "::cut() <- " << new_head << "\n"; return new_head; } !EOF! ls -l qh_cut.c echo x - qh_des.c sed 's/^X//' > qh_des.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // delete the queue_head and also the process_queue // if it is not also pointed to by a queue_tail queue_head::~queue_head() { if (debug) /*DELETE*/ cerr << "queue_head" << this << "::~queue_head()\n"; process_queue *q = qh_queue; if (q->q_tail) q->q_head = 0; else delete q; if (debug) /*DELETE*/ cerr << "<<<< queue_head" << this << "::~queue_head()\n"; } !EOF! ls -l qh_des.c echo x - qh_get.c sed 's/^X//' > qh_get.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // Return an object from the head of the queue. // If necessary, pause and loop // until one becomes available. process_object *queue_head::get() { if (debug) /*DELETE*/ cerr << "queue_head" << this << "::get()\n"; register process_queue *q = qh_queue; while (q->q_count == 0) switch (qh_mode) { case Q_WMODE: this_process()->pause(this); break; case Q_EMODE: error("queue_head::get(): empty queue"); break; case Q_ZMODE: if (debug) /*DELETE*/ cerr << "<<<< queue_head" << this << "::get() <- 0\n"; return 0; } process_object *last = q->q_last; process_object *first = last->po_next; // the queue was full int wasfull = (q->q_count-- == q->q_max); // is the queue now empty if (q->q_count == 0) first->po_next = q->q_last = 0; // does the queue still have some objects on it else { last->po_next = first->po_next; first->po_next = 0; } if (wasfull && q->q_tail) q->q_tail->alert(); if (debug) /*DELETE*/ cerr << "<<<< queue_head" << this << "::get()\n"; return first; } !EOF! ls -l qh_get.c echo x - qh_pending.c sed 's/^X//' > qh_pending.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ int queue_head::pending() { if (debug) /*DELETE*/ cerr << "queue_head" << this << "::pending()\n"; if (debug) /*DELETE*/ cerr << "\trd_count == " << rd_count() << "\n"; if (debug) /*DELETE*/ cerr << "<<<< queue_head::pending() <- " << (rd_count() == 0) << "\n"; return rd_count() == 0; } !EOF! ls -l qh_pending.c echo x - qh_putback.c sed 's/^X//' > qh_putback.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // Insert object at the beginning of the process_queue. // It is an error if there is no room. int queue_head::unget(process_object *p) { if (debug) /*DELETE*/ cerr << "queue_head" << this << "::unget()\n"; process_queue *q = qh_queue; if (p->po_next) error("queue_head::unget(): object on another queue"); if (q->q_count >= q->q_max) switch (qh_mode) { case Q_WMODE: case Q_EMODE: error("queue_tail::unget(): full queue"); /* FALLTHROUGH */ case Q_ZMODE: if (debug) /*DELETE*/ cerr << "<<<< queue_head" << this << "::unget() <- 0\n"; return 0; } // new object on empty queue if (q->q_count++ == 0) q->q_last = p->po_next = p; // objects are already on the queue else { process_object *last = q->q_last; p->po_next = last->po_next; last->po_next = p; } if (debug) /*DELETE*/ cerr << "<<<< queue_head" << this << "::unget() <- 1\n"; return 1; } !EOF! ls -l qh_putback.c echo x - qh_splice.c sed 's/^X//' > qh_splice.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ /* this qhead is supposed to be upstream to the qtail old_tail add the contents of this's queue to old_tail's queue destroy this, old_tail, and this's queue alert the spliced qhead and qtail if a significant state change happened */ void queue_head::splice(queue_tail *old_tail) { if (debug) /*DELETE*/ cerr << "queue_head" << this << "::splice(" << old_tail << ")\n"; process_queue *tailsQ = old_tail->qt_queue; process_queue *headsQ = qh_queue; int tails_count = tailsQ->q_count; int heads_count = headsQ->q_count; tailsQ->q_count = 0; /* either merge the two lists ... */ if (heads_count) { if (tails_count) { process_object *heads_last = headsQ->q_last; process_object *tails_last = tailsQ->q_last; process_object *tails_first = tails_last->po_next; tails_last->po_next = heads_last->po_next; heads_last->po_next = tails_first; headsQ->q_count += tails_count; } } /* ... or move the tail's queue to the head */ else { headsQ->q_count = tails_count; headsQ->q_last = tailsQ->q_last; tailsQ->q_last = 0; } /* patch tail's head onto head's queue */ headsQ->q_head = tailsQ->q_head; tailsQ->q_head->qh_queue = headsQ; tailsQ->q_head = 0; qh_queue = 0; /* delete the throwaways */ delete old_tail; delete this; /* alert the head if its queue becomes non-empty */ if ((tails_count == 0) && (heads_count > 0)) headsQ->q_head->alert(); if (debug) /*DELETE*/ cerr << "<<<< qhead" << this << "::splice(" << old_tail << ")\n"; } !EOF! ls -l qh_splice.c echo x - qh_tail.c sed 's/^X//' > qh_tail.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // Return the queue_tail associated with this queue. // If it doesn't already exist, create it. queue_tail *queue_head::tail() { if (debug) /*DELETE*/ cerr << "queue_head" << this << "::tail()\n"; process_queue *q = qh_queue; register queue_tail *t = q->q_tail; if (!t) { q->q_tail = t = new queue_tail(qh_mode, 0); t->qt_queue = q; } if (debug) /*DELETE*/ cerr << "<<<< queue_head" << this << "::tail() <- " << t << "\n"; return t; } !EOF! ls -l qh_tail.c echo x - qm_print.c sed 's/^X//' > qm_print.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ char *qm_print(qmodes qm) { switch (qm) { case Q_EMODE: return "Q_EMODE"; case Q_WMODE: return "Q_WMODE"; case Q_ZMODE: return "Q_ZMODE"; default: return "default"; } } !EOF! ls -l qm_print.c echo x - qt_cons.c sed 's/^X//' > qt_cons.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // construct a queue_tail and a process_queue queue_tail::queue_tail(qmodes mode, unsigned max) : qt_mode(mode) { if (debug) /*DELETE*/ cerr << "queue_tail" << this << "::queue_tail(" << qm_print(mode) << ", " << max << ")\n"; if (max != 0) qt_queue = new process_queue(max, 0, this); if (debug) /*DELETE*/ cerr << "<<<< queue_tail" << this << "::queue_tail(" << qm_print(mode) << ", " << max << ")\n"; } !EOF! ls -l qt_cons.c echo x - qt_cut.c sed 's/^X//' > qt_cut.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // Change // old_queue_head -- old_queue -- old_queue_tail // into // old_queue_head -- old_queue -- new_queue_tail // new_queue -- old_queue_tail // where old_queue_tail == this // Return new_queue_tail. queue_tail *queue_tail::cut() { if (debug) /*DELETE*/ cerr << "queue_tail" << this << "::cut()\n"; process_queue *oldQ = qt_queue; queue_tail *new_tail = new queue_tail(qt_mode, oldQ->q_max); process_queue *newQ = new_tail->qt_queue; // put the new tail on the old queue new_tail->qt_queue = oldQ; oldQ->q_tail = new_tail; // put the old tail on the new queue newQ->q_tail = this; qt_queue = newQ; if (debug) /*DELETE*/ cerr << "<<<< queue_tail" << this << "::cut() <- " << new_tail << "\n"; return new_tail; } !EOF! ls -l qt_cut.c echo x - qt_des.c sed 's/^X//' > qt_des.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // delete the queue_tail and also the process_queue // if it is not also pointed to by a queue_head queue_tail::~queue_tail() { if (debug) /*DELETE*/ cerr << "queue_tail" << this << "::~queue_tail()\n"; process_queue *q = qt_queue; if (q->q_head) q->q_tail = 0; else delete q; if (debug) /*DELETE*/ cerr << "<<<< queue_tail" << this << "::~queue_tail()\n"; } !EOF! ls -l qt_des.c echo x - qt_head.c sed 's/^X//' > qt_head.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // Return the queue_head associated with this queue. // If it doesn't already exist, create it. queue_head *queue_tail::head() { if (debug) /*DELETE*/ cerr << "queue_tail" << this << "::head()\n"; process_queue *q = qt_queue; register queue_head *h = q->q_head; if (!h) { q->q_head = h = new queue_head(qt_mode, 0); h->qh_queue = q; } if (debug) /*DELETE*/ cerr << "queue_tail" << this << "::head() <- " << h << "\n"; return h; } !EOF! ls -l qt_head.c echo x - qt_pending.c sed 's/^X//' > qt_pending.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ int queue_tail::pending() { if (debug) /*DELETE*/ cerr << "queue_tail" << this << "::pending()\n"; if (debug) /*DELETE*/ cerr << "\trd_space() == " << rd_space() << "\n"; if (debug) /*DELETE*/ cerr << "<<<< queue_tail" << this << "::pending() <- " << (rd_space() == 0) << "\n"; return rd_space() == 0; } !EOF! ls -l qt_pending.c echo x - qt_put.c sed 's/^X//' > qt_put.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ // Append object to the rear of the process_queue. // If necessary, pause and loop until // room becomes available. int queue_tail::put(process_object *p) { if (debug) /*DELETE*/ cerr << "queue_tail" << this << "::put()\n"; register process_queue *q = qt_queue; while (q->q_count >= q->q_max) switch (qt_mode) { case Q_WMODE: this_process()->pause(this); break; case Q_EMODE: error("queue_head::put(): full queue"); break; case Q_ZMODE: if (debug) /*DELETE*/ cerr << "<<<< queue_tail" << this << "::put() <- 0\n"; return 0; } if (p->po_next) error("queue_tail::put(): object on another queue"); // new object on empty queue if (q->q_count++ == 0) { q->q_last = p->po_next = p; if (q->q_head) q->q_head->alert(); } // objects are already on the queue else { process_object *last = q->q_last; p->po_next = last->po_next; q->q_last = last->po_next = p; } if (debug) /*DELETE*/ cerr << "<<<< queue_tail" << this << "::put() <- 1\n"; return 1; } !EOF! ls -l qt_put.c echo x - qt_splice.c sed 's/^X//' > qt_splice.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ /* this qtail is supposed to be downstream from the qhead old_head */ void queue_tail::splice(queue_head* old_head) { if (debug) /*DELETE*/ cerr << "qtail" << this << "::splice(" << old_head << ")\n"; old_head->splice(this); if (debug) /*DELETE*/ cerr << "<<<< qtail" << this << "::splice(" << old_head << ")\n"; } !EOF! ls -l qt_splice.c echo x - sem_pending.c sed 's/^X//' > sem_pending.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ int semaphore::pending() { if (debug) /*DELETE*/ cerr << "semaphore" << this << "::pending()\n"; if (debug) /*DELETE*/ cerr << "<<<< semaphore" << this << "::pending() <- 1\n"; return 1; // ???????????????? } !EOF! ls -l sem_pending.c echo x - stackdir.h sed 's/^X//' > stackdir.h << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #ifndef STACKDIR_H #define STACKDIR_H class stackdir { int dir; public: stackdir(); // Return a pointer to a local variable // beyond the current stack frame. char *plusone(); char *plustwo(); // T if the stack grows up int grows_up() { return dir; } // Subtract two pointers as if the stack grew up. // a-b = >0 if a>b // 0 if a==b // <0 if a 0; } int greatereq(void *a, void *b) { return diff(a,b) >= 0; } }; extern stackdir Stackdir; #endif /* STACKDIR_H */ !EOF! ls -l stackdir.h echo x - stchk.c sed 's/^X//' > stchk.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ #include main() { int gu = Stackdir.grows_up(); cout << (gu ? "grows up\n" : "grows down\n"); return 0; } !EOF! ls -l stchk.c echo x - stkdir.c sed 's/^X//' > stkdir.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include /* DELETE */ stackdir::stackdir() { dir = (plustwo() - plusone()) > 0; } char *stackdir::plusone() { char x; return &x; } char *stackdir::plustwo() { return plusone(); } stackdir Stackdir; !EOF! ls -l stkdir.c echo x - test1.c sed 's/^X//' > test1.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ /* based on cfront 2.0 b5 demo program alph.C */ #include /* DELETE */ /*ident "@(#)ctrans:demo/task/alph.C 1.1" */ /************************************************************************** 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. *****************************************************************************/ // Demonstration of two processes communicating via semaphores. #include #define K 10 class Semaphore : public process_object { int sigs; public: Semaphore(int i =0) { sigs = i; } int pending(); void wait(); void signal() { if (sigs++ == 0) alert(); } }; void Semaphore::wait() { for (;;) { if (--sigs >= 0) return; sigs++; this_process()->pause(this); } } int Semaphore::pending() { return sigs <= 0; } Semaphore* sema[2]; class Test : public process { int svi; public: Test(int i) : (i ? "Alphonse" : "Gaston") { svi = i; } long main(); }; long Test::main() { for (register int n = K / 2; n--; ) { sema[!svi]->wait(); sema[svi]->signal(); printf("%s: %d\n", svi ? "Alphonse" : "Gaston", n); } return 0; // "return" sets the exitcode } main() { sema[0] = new Semaphore(1); sema[1] = new Semaphore; (new Test(0))->exec(); // create "Gaston" process; switch to it (new Test(1))->exec(); // create "Alphonse" process; switch to it printf("back in main\n"); main_process()->exit(0); // terminate main process printf("should not get here\n"); return 0; } !EOF! ls -l test1.c echo x - test1.cmp sed 's/^X//' > test1.cmp << '!EOF!' Alphonse: 4 Gaston: 4 Alphonse: 3 Gaston: 3 Alphonse: 2 Gaston: 2 Alphonse: 1 Gaston: 1 Alphonse: 0 Gaston: 0 back in main !EOF! ls -l test1.cmp echo x - test2.c sed 's/^X//' > test2.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ /* based on cfront 2.0 release notes Spaces example */ #include /* DELETE */ #include main() { Spaces *ss = new Spaces("a line with four spaces"); ss->exec(); long count = ss->result(); cout << "count = " << count << "\n"; main_process()->exit(0); printf("should not get here\n"); return 0; } !EOF! ls -l test2.c echo x - test2.cmp sed 's/^X//' > test2.cmp << '!EOF!' count = 4 !EOF! ls -l test2.cmp echo x - test2.h sed 's/^X//' > test2.h << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ /* based on cfront 2.0 release notes Spaces example */ #include class Spaces : public process { char *s; public: Spaces(char *ns); long main(); }; Spaces::Spaces(char *ns) : ("spaces") { s = ns; } long Spaces::main() { int i = 0; while (*s) if (*s++ == ' ') i++; return i; } !EOF! ls -l test2.h echo x - test3.c sed 's/^X//' > test3.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ /* based on cfront 2.0 release notes Spaces example */ #include /* DELETE */ #include main() { Spaces ss("a line with four spaces"); ss.exec(); long count = ss.result(); cout << "count = " << count << "\n"; main_process()->exit(0); printf("should not get here\n"); return 0; } !EOF! ls -l test3.c echo x - test3.cmp sed 's/^X//' > test3.cmp << '!EOF!' count = 4 !EOF! ls -l test3.cmp echo x - test4.c sed 's/^X//' > test4.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ /* based on cfront 2.0 b5 demo program triv.C */ #include /* DELETE */ /*ident "@(#)ctrans:demo/task/triv.C 1.1" */ /************************************************************************** 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. *****************************************************************************/ #include /* trivial process example: Make a set of processes which pass an object round between themselves. Each process gets an object from the head of one queue, and puts the object on the tail of another queue. Main creates each process, then puts the object on a queue. Each process quits after getting the object MAX_CYCLES times. */ const int NTASKS = 1; const int MAX_CYCLES = 5; struct pc : process { // derive a class from process queue_tail *t; queue_head *h; char *n; pc(char*nn, queue_tail*nt, queue_head*nh) // process is not intended to be used directly : (nn) { if (debug) /*DELETE*/ cerr << "!!!!!!!!!!!!!!!! new pc(" << nn << ")\n"; cout << "new pc(" << nn << ")\n"; t = nt; h = nh; n = nn; } long main(); }; long pc::main() // process body serves as { // "main" program for process for (int i = 0; i < MAX_CYCLES; i++) { process_object* p = h->get(); if (debug) /*DELETE*/ cerr << "!!!!!!!!!!!!!!!! process " << n << "\n"; cout << "process " << n << "\n"; t->put(p); } if (debug) /*DELETE*/ cerr << "!!!!!!!!!!!!!!!! process " << n << ": done.\n"; cout << "process " << n << ": done.\n"; return 0; // Always end process constructors with return. } main() { queue_head* hh = new queue_head; queue_tail* t = hh->tail(); // hh and t refer to same queue. queue_head* h; if (debug) /*DELETE*/ cerr << "!!!!!!!!!!!!!!!! main\n"; cout << "main\n"; for (int i=0; iexec(); // create a new process and start execution if (debug) /*DELETE*/ cerr << "!!!!!!!!!!!!!!!! main()'s loop\n"; cout << "main()'s loop\n"; t = h->tail(); } (new pc("first pc",t,hh))->exec(); // create another new process if (debug) /*DELETE*/ cerr << "!!!!!!!!!!!!!!!! main: here we go\n"; cout << "main: here we go\n"; t->put(new process_object); // put the object on a queue if (debug) /*DELETE*/ cerr << "!!!!!!!!!!!!!!!! main: exit\n"; cout << "main: exit\n"; main_process()->exit(0); // main is a process too; it must also // end with exit (to allow any // remaining processes to run, otherwise // the whole process would exit). printf("should not get here\n"); return 0; } !EOF! ls -l test4.c echo x - test4.cmp sed 's/^X//' > test4.cmp << '!EOF!' main new pc(a) main()'s loop new pc(first pc) main: here we go main: exit process a process first pc process a process first pc process a process first pc process a process first pc process a process a: done. process first pc process first pc: done. !EOF! ls -l test4.cmp echo x - test4.err sed 's/^X//' > test4.err << '!EOF!' qhead[0x80884d84]::qhead(Q_WMODE, 10000) <<<< qhead[0x80884d84]::qhead() qhead[0x80884d84]::tail() qtail[0x80884db0]::qtail(Q_WMODE, 0) <<<< qtail[0x80884db0]::qtail(Q_WMODE, 0) <<<< qhead[0x80884d84]::tail() <- [0x80884db0] !!!!!!!!!!!!!!!! main qhead[0x80884dcc]::qhead(Q_WMODE, 10000) <<<< qhead[0x80884dcc]::qhead() task[0x80884df8,a]::task(a) task: thistask == [0] task: t_maintask == [0] create main task task[0x80884e5c,main]::task(main) task: thistask == [0] task: t_maintask == [0x80882258,tmpmaintask] <<<< task[0x80884e5c,main]::task() maintask <- [0x80884e5c,main] <<<< task[0x80884df8,a]::task() !!!!!!!!!!!!!!!! new pc(a) ---- setting t_stackbase <- 0xc0020954 task[0x80884df8,a]::runtask() parent == [0x80884e5c,main] [0x80884e5c,main]->t_curstate <- TASK_RUNNABLE task[0x80884e5c,main]::save() grows_up == 1 px = 0xc00209e0 t_stackbase = 0xc0020954 t_stacksize <- 140 <<<< task[0x80884e5c,main]::save() <- 0 [0x80884df8,a]->t_curstate <- TASK_RUNNABLE qhead[0x80884dcc]::get() task_object::this_task() t_thistask == [0x80884df8,a] task[0x80884df8,a]::wait(vec) nwaitvec[0] = 0x80884dcc 2 objects +1 task[0x80884df8,a]::pause() task[0x80884df8,a]::rmfromlist([0x80884df8,a], runtasks) <<<< task[0x80884df8,a]::rmfromlist([0x80884df8,a]) <- 0 [0x80884df8,a]->t_curstate <- TASK_IDLE task[0x80884df8,a]::save() grows_up == 1 px = 0xc0020b5c t_stackbase = 0xc0020954 t_stacksize <- 520 <<<< task[0x80884df8,a]::save() <- 0 task[0x80884df8,a]::schedule() task::dumpall() t_curtime == 0 t_thistask: [0x80884df8,a] t_curstate == TASK_IDLE t_result == 0 t_desiredtime == 0 t_waitvec[0] == 0x80884dcc idle tasks: [0x80884df8,a] t_curstate == TASK_IDLE t_result == 0 t_desiredtime == 0 t_waitvec[0] == 0x80884dcc run tasks: [0x80884e5c,main] t_curstate == TASK_RUNNABLE t_result == 0 t_desiredtime == 0 done tasks: task[0x80884df8,a]::check4runnable([0x80884df8,a]) qhead[0x80884dcc]::pending() rd_count == 0 qhead::pending() still pending <<<< task[0x80884df8,a]::check4runnable([0x80884df8,a]) <- 0 task::dumpall() t_curtime == 0 t_thistask: [0x80884df8,a] t_curstate == TASK_IDLE t_result == 0 t_desiredtime == 0 t_waitvec[0] == 0x80884dcc idle tasks: [0x80884df8,a] t_curstate == TASK_IDLE t_result == 0 t_desiredtime == 0 t_waitvec[0] == 0x80884dcc run tasks: [0x80884e5c,main] t_curstate == TASK_RUNNABLE t_result == 0 t_desiredtime == 0 done tasks: <<<< task[0x80884df8,a]::schedule() <- [0x80884e5c,main] task[0x80884e5c,main]::restore() grows_up == 1 &x = 0xc0020b88 t_stackbase = 0xc0020954 t_stacksize = 140 px - t_stackbase = 564 <<<< task[0x80884e5c,main]::restore() <<<< task[0x80884e5c,main]::save() <- 1 <<<< task[0x80884df8,a]::runtask() !!!!!!!!!!!!!!!! main()'s loop qhead[0x80884dcc]::tail() qtail[0x8088515c]::qtail(Q_WMODE, 0) <<<< qtail[0x8088515c]::qtail(Q_WMODE, 0) <<<< qhead[0x80884dcc]::tail() <- [0x8088515c] task[0x80885170,first pc]::task(first pc) task: thistask == [0x80884e5c,main] task: t_maintask == [0x80884e5c,main] <<<< task[0x80885170,first pc]::task() !!!!!!!!!!!!!!!! new pc(first pc) ---- setting t_stackbase <- 0xc0020954 task[0x80885170,first pc]::runtask() parent == [0x80884e5c,main] [0x80884e5c,main]->t_curstate <- TASK_RUNNABLE task[0x80884e5c,main]::save() grows_up == 1 px = 0xc00209e0 t_stackbase = 0xc0020954 t_stacksize <- 140 <<<< task[0x80884e5c,main]::save() <- 0 [0x80885170,first pc]->t_curstate <- TASK_RUNNABLE qhead[0x80884d84]::get() task_object::this_task() t_thistask == [0x80885170,first pc] task[0x80885170,first pc]::wait(vec) nwaitvec[0] = 0x80884d84 2 objects +1 task[0x80885170,first pc]::pause() task[0x80885170,first pc]::rmfromlist([0x80885170,first pc], runtasks) <<<< task[0x80885170,first pc]::rmfromlist([0x80885170,first pc]) <- 0 [0x80885170,first pc]->t_curstate <- TASK_IDLE task[0x80885170,first pc]::save() grows_up == 1 px = 0xc0020b5c t_stackbase = 0xc0020954 t_stacksize <- 520 <<<< task[0x80885170,first pc]::save() <- 0 task[0x80885170,first pc]::schedule() task::dumpall() t_curtime == 0 t_thistask: [0x80885170,first pc] t_curstate == TASK_IDLE t_result == 0 t_desiredtime == 0 t_waitvec[0] == 0x80884d84 idle tasks: [0x80885170,first pc] t_curstate == TASK_IDLE t_result == 0 t_desiredtime == 0 t_waitvec[0] == 0x80884d84 [0x80884df8,a] t_curstate == TASK_IDLE t_result == 0 t_desiredtime == 0 t_waitvec[0] == 0x80884dcc run tasks: [0x80884e5c,main] t_curstate == TASK_RUNNABLE t_result == 0 t_desiredtime == 0 done tasks: task[0x80885170,first pc]::check4runnable([0x80885170,first pc]) qhead[0x80884d84]::pending() rd_count == 0 qhead::pending() still pending <<<< task[0x80885170,first pc]::check4runnable([0x80885170,first pc]) <- 0 task[0x80885170,first pc]::check4runnable([0x80884df8,a]) qhead[0x80884d84]::pending() rd_count == 0 qhead::pending() still pending <<<< task[0x80885170,first pc]::check4runnable([0x80884df8,a]) <- 0 task::dumpall() t_curtime == 0 t_thistask: [0x80885170,first pc] t_curstate == TASK_IDLE t_result == 0 t_desiredtime == 0 t_waitvec[0] == 0x80884d84 idle tasks: [0x80885170,first pc] t_curstate == TASK_IDLE t_result == 0 t_desiredtime == 0 t_waitvec[0] == 0x80884d84 [0x80884df8,a] t_curstate == TASK_IDLE t_result == 0 t_desiredtime == 0 t_waitvec[0] == 0x80884dcc run tasks: [0x80884e5c,main] t_curstate == TASK_RUNNABLE t_result == 0 t_desiredtime == 0 done tasks: <<<< task[0x80885170,first pc]::schedule() <- [0x80884e5c,main] task[0x80884e5c,main]::restore() grows_up == 1 &x = 0xc0020b88 t_stackbase = 0xc0020954 t_stacksize = 140 px - t_stackbase = 564 <<<< task[0x80884e5c,main]::restore() <<<< task[0x80884e5c,main]::save() <- 1 <<<< task[0x80885170,first pc]::runtask() !!!!!!!!!!!!!!!! main: here we go qtail[0x8088515c]::put() task_object::alert() task_object::this_task() t_thistask == [0x80884e5c,main] ---- setting t_stackbase <- 0xc00209b0 task[0x80884e5c,main]::pause() task[0x80884e5c,main]::rmfromlist([0x80884e5c,main], runtasks) <<<< task[0x80884e5c,main]::rmfromlist([0x80884e5c,main]) <- 0 [0x80884e5c,main]->t_curstate <- TASK_IDLE task[0x80884e5c,main]::save() grows_up == 1 px = 0xc0020a38 t_stackbase = 0xc00209b0 t_stacksize <- 136 <<<< task[0x80884e5c,main]::save() <- 0 task[0x80884e5c,main]::schedule() task::dumpall() t_curtime == 0 t_thistask: [0x80884e5c,main] t_curstate == TASK_IDLE t_result == 0 t_desiredtime == 0 idle tasks: [0x80884e5c,main] t_curstate == TASK_IDLE t_result == 0 t_desiredtime == 0 [0x80885170,first pc] t_curstate == TASK_IDLE t_result == 0 t_desiredtime == 0 t_waitvec[0] == 0x80884d84 [0x80884df8,a] t_curstate == TASK_IDLE t_result == 0 t_desiredtime == 0 t_waitvec[0] == 0x80884dcc run tasks: done tasks: task[0x80884e5c,main]::check4runnable([0x80884e5c,main]) t_desiredtime,t_waitvec == 0 <<<< task[0x80884e5c,main]::check4runnable([0x80884e5c,main]) <- 1 sv[0x80884e5c,main]->t_curstate == TASK_RUNNABLE task[0x80884e5c,main]::check4runnable([0x80885170,first pc]) t_desiredtime,t_waitvec == 0 <<<< task[0x80884e5c,main]::check4runnable([0x80885170,first pc]) <- 1 sv[0x80885170,first pc]->t_curstate == TASK_RUNNABLE task[0x80884e5c,main]::check4runnable([0x80884df8,a]) t_desiredtime,t_waitvec == 0 <<<< task[0x80884e5c,main]::check4runnable([0x80884df8,a]) <- 1 sv[0x80884df8,a]->t_curstate == TASK_RUNNABLE task::dumpall() t_curtime == 0 t_thistask: [0x80884e5c,main] t_curstate == TASK_RUNNABLE t_result == 0 t_desiredtime == 0 idle tasks: run tasks: [0x80884df8,a] t_curstate == TASK_RUNNABLE t_result == 0 t_desiredtime == 0 t_waitvec[0] == 0x80884dcc [0x80885170,first pc] t_curstate == TASK_RUNNABLE t_result == 0 t_desiredtime == 0 t_waitvec[0] == 0x80884d84 [0x80884e5c,main] t_curstate == TASK_RUNNABLE t_result == 0 t_desiredtime == 0 done tasks: <<<< task[0x80884e5c,main]::schedule() <- [0x80884df8,a] task[0x80884df8,a]::restore() grows_up == 1 &x = 0xc0020a64 t_stackbase = 0xc00209b0 t_stacksize = 520 px - t_stackbase = 180 task[0x80884df8,a]::restore() grows_up == 1 &x = 0xc0020a9c t_stackbase = 0xc00209b0 t_stacksize = 520 px - t_stackbase = 236 task[0x80884df8,a]::restore() grows_up == 1 &x = 0xc0020ad4 t_stackbase = 0xc00209b0 t_stacksize = 520 px - t_stackbase = 292 task[0x80884df8,a]::restore() grows_up == 1 &x = 0xc0020b0c t_stackbase = 0xc00209b0 t_stacksize = 520 px - t_stackbase = 348 task[0x80884df8,a]::restore() grows_up == 1 &x = 0xc0020b44 t_stackbase = 0xc00209b0 t_stacksize = 520 px - t_stackbase = 404 task[0x80884df8,a]::restore() grows_up == 1 &x = 0xc0020b7c t_stackbase = 0xc00209b0 t_stacksize = 520 px - t_stackbase = 460 task[0x80884df8,a]::restore() grows_up == 1 &x = 0xc0020bb4 t_stackbase = 0xc00209b0 t_stacksize = 520 px - t_stackbase = 516 task[0x80884df8,a]::restore() grows_up == 1 &x = 0xc0020bec t_stackbase = 0xc00209b0 t_stacksize = 520 px - t_stackbase = 572 <<<< task[0x80884df8,a]::restore() !EOF! ls -l test4.err echo x - test5.c sed 's/^X//' > test5.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ /*ident "@(#)ctrans:demo/task/shared.C 1.1.1.1" */ #include /* DELETE */ /************************************************************************** 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. *****************************************************************************/ #include /* non-trivial process example: Make a set of SHARED processes which pass an object round between themselves. Each process but the last creates the next process. Each process gets an object from the head of one queue, and puts the object on the tail of another queue. Each process quits after getting the object MAX_CYCLES times. */ const int NTASKS = 1; const int MAX_CYCLES = 5; struct pc : process { // derive a class from process queue_tail *t; queue_head *h; char *n; pc(char*nn, queue_tail*nt, queue_head*nh) // process is not intended to be used directly : (nn) { t = nt; h = nh; n = nn; } long main(); }; long pc::main() // process body serves as { // "main" program for process int cycles; printf("new pc(%s)\n",n); if (*n < 'a'+ NTASKS) { char* c = new char[2]; c[0] = *n + 1; c[1] = '\0'; queue_tail* qt = new queue_tail; pc* next = new pc(c, t, qt->head()); next->exec(); t = qt; } else { printf("%s: here we go\n", n); t->put(new process_object); } for (cycles = 0; cycles < MAX_CYCLES; cycles++) { process_object* p = h->get(); printf("process %s\n",n); t->put(p); } printf("process %s: done.\n", n); exit(0); // Always end process constructors with exit or return. } main() { queue_head* hh = new queue_head; queue_tail* t = hh->tail(); queue_head* h; int cycles; printf("main\n"); char* n = "a"; // make a one letter process name h = new queue_head; (new pc(n,t,h))->exec(); printf("main()'s loop\n"); t = h->tail(); for (cycles = 0; cycles < MAX_CYCLES; cycles++) { process_object* p = hh->get(); printf("main process\n"); t->put(p); } printf("main process: done.\n", n); main_process()->exit(0); // main is a process too; it must also // end with resultis (to allow any // remaining processes to run, otherwise // the whole process would exit). printf("should not get here\n"); return 0; } !EOF! ls -l test5.c echo x - test5.cmp sed 's/^X//' > test5.cmp << '!EOF!' main new pc(a) new pc(b) b: here we go main()'s loop main process process a process b main process process a process b main process process a process b main process process a process b main process main process: done. process a process a: done. process b process b: done. !EOF! ls -l test5.cmp echo x - test6.c sed 's/^X//' > test6.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ /*ident "@(#)ctrans:demo/task/regtest.C 1.1" */ #include /* DELETE */ /************************************************************************** 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. *****************************************************************************/ #include /* non-trivial process example: Make a set of processes which pass an object round between themselves. Each process but the last creates the next process. Each process gets an object from the head of one queue, and puts the object on the tail of another queue. Each process quits after getting the object MAX_CYCLES times. Each process uses lots of registers that must be preserved across a switch. */ const int NTASKS = 1; const int MAX_CYCLES = 5; void dirty() { register i, j, k, l, m, z; i = -1; j = -2; k = -3; l = -4; m = -5; z = -6; } struct pc : process { // derive a class from process queue_tail *t; queue_head *h; char *n; pc(char*nn, queue_tail*nt, queue_head*nh) // process is not intended to be used directly : (nn) { t = nt; h = nh; n = nn; } long main(); }; long pc::main() // process body serves as { register int i, j, k, l, m, z; i = *n + 11; j = *n + 12; k = *n + 13; l = *n + 14; m = *n + 15; z = *n + 16; printf("new pc(%s)\n",n); if (*n < 'a'+ NTASKS) { char* c = new char[2]; c[0] = *n + 1; c[1] = '\0'; queue_tail* qt = new queue_tail; pc* next = new pc(c, t, qt->head()); next->exec(); t = qt; } else { printf("%s: here we go\n", n); t->put(new process_object); } if (this_process() != this) abort(); if (i != *n + 11 || j != *n + 12 || k != *n + 13 || l != *n + 14 || m != *n + 15 || z != *n + 16) { printf("pc: lost regs! i==%d, j==%d, k==%d, l==%d, m==%d, z==%d\n", i, j, k, l, m, z); printf("vals should be: i: %d, j: %d, k: %d, l: %d, m: %d, z: %d\n", *n + 11, *n + 12, *n + 13, *n + 14, *n + 15, *n + 16); abort(); } for (int cycles = 0; cycles < MAX_CYCLES; cycles++) { process_object* p = h->get(); dirty(); printf("process %s\n",n); t->put(p); } printf("process %s: done.\n", n); exit(0); // Always end process constructors with resultis. // Behavior of those using return or running // off the end of the function is undefined. // Alternatively, use an infinite loop in // constructor body. } main() { register int i, j, k, l, m, z; queue_head* hh = new queue_head; queue_tail* t = hh->tail(); queue_head* h; printf("main\n"); char* n = "a"; // make a one letter process name i = *n + 1; j = *n + 2; k = *n + 3; l = *n + 4; m = *n + 5; z = *n + 6; h = new queue_head; (new pc(n,t,h))->exec(); printf("main()'s loop\n"); if (i != *n + 1 || j != *n + 2 || k != *n + 3 || l != *n + 4 || m != *n + 5 || z != *n + 6) { printf("main: lost regs! i==%d, j==%d, k==%d, l==%d, m==%d, z==%d\n", i, j, k, l, m, z); printf("values should be: i: %d, j: %d, k: %d, l: %d, m: %d, z: %d\n", *n + 1, *n + 2, *n + 3, *n + 4, *n + 5, *n + 6); abort(); } t = h->tail(); for (int cycles = 0; cycles < MAX_CYCLES; cycles++) { process_object* p = hh->get(); if (i != *n + 1 || j != *n + 2 || k != *n + 3 || l != *n + 4 || m != *n + 5 || z != *n + 6) { printf("main (after get): lost regs! i==%d, j==%d, k==%d, l==%d, m==%d, z==%d\n", i, j, k, l, m, z); printf("values should be: i: %d, j: %d, k: %d, l: %d, m: %d, z: %d\n", *n + 1, *n + 2, *n + 3, *n + 4, *n + 5, *n + 6); abort(); } printf("main process\n"); t->put(p); } printf("main process: done.\n", n); main_process()->exit(0); // main is a process too; it must also // end with exit (to allow any // remaining processes to run, otherwise // the whole process would exit). printf("should not get here\n"); return 0; } !EOF! ls -l test6.c echo x - test6.cmp sed 's/^X//' > test6.cmp << '!EOF!' main new pc(a) new pc(b) b: here we go main()'s loop main process process a process b main process process a process b main process process a process b main process process a process b main process main process: done. process a process a: done. process b process b: done. !EOF! ls -l test6.cmp # The following exit is to ensure that extra garbage # after the end of the shar file will be ignored. exit 0