#!/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 <process.h>
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 <process.h>
#include <debug.h>	/* DELETE */
#include <stream.h>	/* 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 <process.h>
#include <stackdir.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* DELETE */
#include <stackdir.h>
// 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* DELETE */
#include <stackdir.h>
// 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>
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 <stream.h>
#include <string.h>
#include <setjmp.h>
#include <error.h>
#include <stackdir.h>

#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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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 <process.h>
#include <debug.h>	/* 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<b
    int diff(void *a, void *b)
    {
	return grows_up() ?
	       ((char*)a - (char*)b):
	       ((char*)b - (char*)a);
    }

    // Compare two pointers as if the stack grew up.
    int less(void *a, void *b) { return diff(a,b) < 0; }
    int lesseq(void *a, void *b) { return diff(a,b) <= 0; }
    int greater(void *a, void *b) { return diff(a,b) > 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 <stackdir.h>
#include <debug.h>	/* DELETE */
#include <stream.h>

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 <stackdir.h>
#include <debug.h>	/* 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 <debug.h>	/* 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 <process.h>
#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 <debug.h>	/* DELETE */
#include <test2.h>

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 <process.h>

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 <debug.h>	/* DELETE */
#include <test2.h>

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 <debug.h>	/* 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 <process.h>

/* 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; i<NTASKS; i++) {
                char* n = new char[2];	// make a one letter process name
                n[0] = 'a'+i;
                n[1] = 0;

                h = new queue_head;
                (new pc(n,t,h))->exec(); // 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 <debug.h>	/* 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 <process.h>

/* 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 <debug.h>	/* 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 <process.h>

/* 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