/* begincopyright
  Copyright (c) 1988 Xerox Corporation. All rights reserved.
  Use and copying of this software and preparation of derivative works based
  upon this software are permitted. Any distribution of this software or
  derivative works must comply with all applicable United States export
  control laws. This software is made available AS IS, and Xerox Corporation
  makes no warranty about the software, its performance or its conformity to
  any specification. Any person obtaining a copy of this software is requested
  to send their name and post office or electronic mail address to:
    PCR Coordinator
    Xerox PARC
    3333 Coyote Hill Rd.
    Palo Alto, CA 94304
  endcopyright */

/*
 * ThreadsBackdoor.h
 *
 * Demers, December 14, 1990 2:14:47 pm PST
 * Boehm, August 19, 1991 4:48:47 pm PDT
 */

#ifndef	←XR←THREADS←BACKDOOR←
#define ←XR←THREADS←BACKDOOR←	1

#ifndef ←XR←THREADS←
#include "Threads.h"
#endif

#ifndef ←TIME←
#include <sys/time.h>
#endif

/*
 * Configuration constants
 */

extern char XR←threadsVersion[];

/* table sizes */

#define XR←MAX←VPS		4
extern unsigned XR←maxVPs;

#define XR←MAX←SLAVEIOPS	3
extern unsigned XR←maxSlaveIOPs;

#define XR←MAX←STDIOPS		5
extern unsigned XR←maxStdIOPs;

#define XR←MAX←STRIOPS		3
extern unsigned XR←maxStrIOPs;

#define XR←MAX←IOPS		(XR←MAX←SLAVEIOPS+XR←MAX←STDIOPS+XR←MAX←STRIOPS)
extern unsigned XR←maxIOPs;

#define XR←MAX←SYS←MEM		(512*1024)
#define XR←DEFAULT←SYS←MEM	(128*1024)
extern unsigned XR←maxSysMem;


/* From ThreadsSharedMem.h: */

extern char * XR←SetShmType(/* char * shmType */);
extern char * XR←GetShmType();
extern char * XR←SetShmArg(/* char * shmArg */);
extern char * XR←GetShmArg();



#define XR←MAX←IOPE←CLIENT←DATA		12
#define XR←MAX←SA←CLIENT←DATA		8


#define XR←MAX←THREADS		250
extern unsigned XR←maxThreads;

typedef struct XR←ThreadStackGroupRep {
    int tsg←numThreads;
    int tsg←stackBytes;
} *XR←ThreadStackGroup;

#define XR←MAX←THREAD←STACK←GROUPS	8
extern int XR←maxThreadStackGroups;

extern struct XR←ThreadStackGroupRep
    XR←threadStackGroups[XR←MAX←THREAD←STACK←GROUPS];


#ifdef sparc
#   define XR←WARMSTACKSPACE		(8*1024)
#   define XR←OFLOHANDLERSTACKSPACE	(8*1024)
#   define XR←MIN←THREAD←STACK←BYTES	 \
	((16*1024)+XR←WARMSTACKSPACE+XR←OFLOHANDLERSTACKSPACE)
#   define XR←MAX←THREAD←STACK←BYTES ((4*1024)*1024)	/* sanity check */
#   define XR←THREAD←STACK←BYTES (64*1024)		/* default */
#else
    error define stack parameters for architecture ???
#endif /* sparc */

extern int XR←threadStackBytes;


extern int XR←argc;		/* PCR command line argc */
extern char **XR←argv;		/* PCR command line argv */

#define XR←DEFAULT←DBX←SCRIPT←NAME "XRDBXInner"
extern int XR←SetDBXScriptName(/* char *name */);
extern char *(XR←GetDBXScriptName());

#define XR←DEFAULT←TMP←DIRECTORY "/tmp/"
extern int XR←SetTmpDirectory(/* char *dirName */);
extern char *(XR←GetTmpDirectory());

extern int XR←SetPCRFileName(/* char *pcrFileName */);
extern char *(XR←GetPCRFileName());

extern int XR←verbosity; /* signed, default is 0 */


#define XR←SWAP←FILE←NAME←SIZE		256 /* ??? */
extern char XR←swapFileName[XR←SWAP←FILE←NAME←SIZE]; /* ??? */

/*
 * Well-known address of system area
 */


#define XR←SA		struct XR←SARep *

extern XR←SA  XR←sysArea;

/*
 * Time
 */

extern void
XR←SetBootTime ();
/*
    Initialize boot time for later use.
    Called once at the beginning of time.
*/


/*
 * Debugger State
 */

typedef int XR←DBStat;
#   define XR←DBSTAT←STOP		((XR←DBStat)(-2))
#   define XR←DBSTAT←RUN0		((XR←DBStat)(-1))
#   define XR←DBSTAT←RUN		((XR←DBStat)(0))
#   define XR←DBSTAT←EXAMINE(pid)	((XR←DBStat)(pid))

    /* External debugger sets sv←dbStat, waits for processors	*/
    /* to copy it to vpe←dbStat.        			*/ 

/*
 * Semaphore groups (for inter-processor communication)
 *
 * System V dependent
 */

typedef struct XR←SGRep {
    int sg←semid;		/* Unix semaphore id */
    int sg←numSems;		/* number of semaphores in group */
} * XR←SG;


extern void
XR←InitSG (/* sg, count */);
/*
    XR←SG sg;
    int count;

    Initialize semaphore group to contain `count' semaphores.
*/


extern void
XR←PSem (/* sg, index, count */);
/*
    XR←SG sg;
    int index;
    int count;

    P operation, decrementing `index'th semaphore of `sg' by `count'.
    Retries if interrupted by Unix signal.
*/

extern void
XR←VSem (/* sg, index, count */);
/*
    XR←SG sg;
    int index;
    int count;

    V operation, incrementing `index'th semaphore of `sg' by `count'.
*/


/*
 * VProcessor orders
 */

#define XR←MAX←VPO←ARGS		4

typedef struct XR←VPOrderRep {
    void (*vpo←proc)(/* order */);		/* proc to execute, NIL okay */
    bool vpo←stop;				/* TRUE ==> stop VProcessors */ 
    unsigned vpo←args[XR←MAX←VPO←ARGS];		/* argument buffer */
} * XR←VPOrder;

/*
 * VProcessor descriptor Entry
 */

typedef struct XR←VPERep {
    unsigned vpe←index;		/* index of this vpe in table */
    unsigned vpe←pid;		/* UNIX pid, non-0 => vprocessor running */
    XR←Pri vpe←pri;		/* pri of current process, for sched */
    bool vpe←doSwitch;		/* switch request from e.g. int handler */
    XR←Ticks vpe←ticksSinceBoot;/* per-VP ticks value, see ThreadsTime.c */
    unsigned vpe←orderNum;	/* most recently executed order */
    XR←DBStat vpe←dbStat;	/* most recent sv←dbstat value read */
    XR←Pointer vpe←rusage;	/* --> description of resource use */
} * XR←VPE;


extern XR←VPE XR←vpe;		/* per-processor, non-NIL if this is a vp */

/*
 * IOProcessor orders -- see ThreadsOrders.c
 */

#define XR←MAX←IOPO←ARGS	6
#define XR←MAX←IOPO←RESULTS	2

typedef struct XR←IOPOrderRep {
    struct XR←IOPOrderRep * iopo←next;
    int iopo←done;				/* iop completion code */
    struct XR←CVRep iopo←cv;			/* notify when order done */
    void (*iopo←cancel)(/* order */);		/* proc to cancel request */
    void (*iopo←proc)(/* order */);		/* proc to execute */
    unsigned iopo←args[XR←MAX←IOPO←ARGS];	/* argument buffer */
    unsigned iopo←results[XR←MAX←IOPO←RESULTS];	/* result buffer */
} * XR←IOPOrder;

extern void
XR←InitIOPOrder (/* iopo */);
/*
    XR←IOPOrder iopo;
*/

/*
 * IOProcessor descriptor entry
 */

typedef unsigned XR←IOPEFlags;
#   define XR←IOP←FLAGS←STARTED		0x1

typedef struct XR←IOPERep {
    unsigned iope←index;	/* index of this iope in table	*/
    unsigned iope←pid;		/* UNIX pid, 0 if IOPE not in use */
    unsigned iope←kind;		/* unique value identifies kind of iop */
				/* (currently the run proc address) */
    XR←IOPEFlags iope←flags;	/* flag values -- kind-specific */
    bool (*iope←workerProc)();	/* worker proc -- kind-specific */
    struct XR←VPOrderRep
            iope←vpOrderBuf;	/* buffer for issuing vp order */ 
    struct XR←MLRep
	    iope←orderLock;	/* lock for vp issuing order to me */
    struct XR←CVRep
	    iope←orderAccepted;	/* vp issuing order waits on this */
    XR←IOPOrder iope←order;	/* next order for me to execute */
    unsigned iope←clientData[XR←MAX←IOPE←CLIENT←DATA];
} * XR←IOPE;


extern XR←IOPE XR←iope;		/* per-processor, non-NIL if this is an iop */

/*
 * Issue VP Orders ...
 *     to be called by iop, NOT process
 */

extern void
XR←IssueVPOrder (/* order, proc, stop */);
/*
    XR←VPOrder order;
    void (*iopo←proc)( (* order *) );
    bool stop;

    Assume caller has stored into order->vpo←args[].
    Caller (iop) becomes sa←vpOrderMaster (if it isn't already).
    Every vprocessor executes `order'.
    Caller waits for this to complete.
    If stop == TRUE, all vp's stop after executing order,
        and caller remains sa←vpOrderMaster on return.
    If stop == FALSE, vp's continue after executing the order,
        and caller is no longer sa←vpOrderMaster on return.
*/

/*
 * Issue IOP Orders ...
 */


typedef int
XR←IOPOResult;

#   define XR←IOPO←RESULT←OK		((XR←IOPOResult)(0))
#   define XR←IOPO←RESULT←ABORTED	((XR←IOPOResult)(-1))
#   define XR←IOPO←RESULT←TIMEDOUT	((XR←IOPOResult)(-2))

extern XR←IOPOResult
XR←IssueIOPOrder (/* iop, order, proc, cancel, abortable, timeout */);
/*
    XR←IOPE iop;
    XR←IOPOrder order;
    void (*proc)( (* order *) );
    void (*cancel)( (* order *) );
    bool abortable;
    XR←Ticks timeout;

    Assumes order->iopo←args[] has been filled,
      and caller has exclusive access to `order'.
    Acquires iop->iope←orderLock and stores order in iop->iope←order,
      unless the calling thread has previously eexcuted an
      XR←AcquireIOPOrderLocks.
    Notifies the IOProcessor that there's an order (using kill()).
    The IOProcessor then executes `order'.  It is the (joint) responsibility
      of `order' and the IOProcessor to make sure that naked notifies of
      iop->iope←orderAccepted and order->iopo←cv will occur at the appropriate
      times.
    Waits on iop->iope←orderAccepted then releases iop->iope←orderLock.
    Waits on order->iopo←cv.  This wait may time out or be aborted,
      in which case the `cancel' order (if non-NIL) is issued to the same
      IOProcessor that was supposed to execute the original order.
    Returns XR←IOPOResult indicating what happened.
    The value of order->iopo←done is significant even if the result is
      ABORTED or TIMEDOUT.
    The IOProcessor is free to modify order->iopo←next and order->iopo←results
      until it notifies order->iopo←cv.
    The IOProcessor must complete a `cancel' order before notifying
      iop->iope←orderAccepted; after that the caller is free to
      deallocate the XR←IOPOrder structure.
*/


extern XR←IOPOResult
XR←IssueIOPOrders (/*
    XR←IOPOrder order,
    void (*remoteProc)(XR←IOPOrder order),
    void (*localProc)(XR←IOPOrder order, XR←IOPE iope)
*/);
/*
    Acquire all locks and issue order to all IOPs simultaneously,
    unless they have already been acquired.

    Invoke the localProc on the issuing VP once for each IOP,
      just before the order is issued to that iop.

    The order cannot timeout or be aborted.

    Since multiple IOPs execute the orders, multiple results are produced.
      The "most interesting" results are stored in order->iopo←results[...]:
      when an IOP returns a result (iopo->iopo←results[...]),
        if( (order->iopo←result[0] == 0) -- prob. no saved result yet --
                || (((int)(iopo←results[0])) < 0) -- error from this IOP -- )
            order->iopo←results[*] = iopo->iopo←results[*];

    IssueIOPOrders may be called only from a VP.
*/

XR←Thread XR←IssueingIOP0Order ();
/*
    Return the running thread currently giving orders to iop0.
    Non-NIL is a hint that other vp's on the same processor might
    want to yield.
*/

extern void
XR←AcquireIOPOrderLocks();
/*
    Require all IOP order locks, in expectation of issuing an order in the
    future.  This is required only when it would be unsafe to acquire the lock
    at the time the order is issued, e.g. because the garbage collector has
    stopped the world.
*/

extern void
XR←ReleaseIOPOrderLocks();
/*
    Release all IOP order locks.  Required if, and to be used only if,
    they were previously acquired with XR←AcquireIOPOrderLocks().
*/

extern void
XR←NotifyIOPODone(/* XR←IOPOrder iopo */);
/*
    To be called by an IOP on completion of an order.
*/


/*
 * Initial process create / destroy
 */


extern unsigned
XR←Root (/* mp */);
/*
    XR←MesaProc mp;

    Provided by client.
    The system starts up by forking XR←MakeMesaProc( XR←Root )
*/


/*
 * System Area
 *
 * There's only one of these, in shared space.
 * It is defined to be the first thing in segment 0,
 *   mapped to a well-known virtual memory address XR←SysArea.
 */

typedef struct XR←SARep {

    /* "metaLock" -- locks system process & timeout queues */

    struct XR←PSLRep sa←metaLock;

    /* thread queues */

    struct XR←CVRep sa←threadAvail;	/* NOTIFYed just before thread freed */
    					/* 1 sec timeout => waiter awakens */

    struct XR←TQRep sa←preFreeTQ;	/* free threads not by stacksize */
    struct XR←TQRep sa←freeTQ[XR←MAX←THREAD←STACK←GROUPS];
    					/* free threads, by stacksize */
    struct XR←TQRep sa←readyTQ[XR←PRI←LAST+1];
    					/* ready threads, by priority */

    /* scheduling control */

    struct XR←MLRep sa←mlSchedCtl;	/* lock for sched ctl mutex */
    XR←Thread sa←schedCtlMaster;	/* master for sched ctl */
    struct XR←CVRep sa←cvSchedCtl;	/* NOTIFied when master = NIL */
    
    /* time, processes awaiting timeout */
    
    struct XR←PSLRep sa←ticksSinceBootLock;
    struct timeval sa←bootTime;		/* when system was booted */
    unsigned sa←ticksSinceBoot;		/* cached ticks since boot */
    int sa←ticksSinceBootDeficit;	/* prevent clock running backwards */
    bool sa←doTimeouts;			/* hint */
    int sa←nTimeouts;			/* number threads in timeout heap */

    /* stdin */

    unsigned sa←ttinRecvd;		/* unix SIGTTIN from stdin */

    /* "tele"-debugger stuff */

    unsigned sa←dbpid;			/* UNIX pid of debugger */
    XR←Pointer sa←dbData;		/* debugger private data */
    XR←DBStat sa←dbStat;		/* state-change cmd from debugger */
    XR←Thread sa←examinee;		/* thread being examined */

    /* VProcessor, IOProcessor configuration */

    unsigned sa←numVP;			/* number of VProcessors */
    unsigned sa←pgrpVP;			/* UNIX vprocessor process group */
    unsigned sa←numIOP;			/* number of IOProcessors */
    struct XR←MLRep sa←mlIOP;		/* for allocating IOPs */

    /* Issuing VP Orders */

    unsigned sa←vpOrderNum;		/* seq number of sa←vpOrder */
    XR←VPOrder sa←vpOrder;		/* order to execute */
    struct XR←SGRep sa←vpOrderSem;	/* sem group for vp order processing */
#	define XR←VP←ORDER←SEM←LOCK 0	/* lock sa←vpOrder */
#	define XR←VP←ORDER←SEM←WAIT 1	/* wait for vp's to finish order */
#	define XR←VP←ORDER←SEM←LAST 1
    XR←IOPE sa←vpOrderMaster;		/* iop issuing orders */

    /* memory map */

    unsigned sa←heapNum;		/* heap map generation number */
    struct XR←SegRep sa←heapSeg;	/* the system heap */
    XR←Pointer sa←heapLimit;		/* it can't grow beyond here */

    struct XR←SegRep sa←sharedDataSeg;
#ifdef XXXX
    struct XR←SegRep sa←sharedCommonSeg;
    struct XR←SegRep sa←sharedBSSSeg;
#endif

    /* statistics, debugging, ... */

    int *sa←stats;			/* -> stats buffer */
    struct XR←MLRep sa←mlRUsage;	/* lock on vpe←rusage entries */

    /* termination */

    struct XR←PSLRep sa←terminating;	/* held => terminating */
    int sa←terminationStatus;		/* status for exiting processes */
    bool sa←suspendOnPanic;		/* suspend or terminate? */
    char * sa←panicMsg;			/* system panic message */

    /* buffer space */

    XR←Thread sa←timeouts[XR←MAX←THREADS+1];

    struct XR←VPERep sa←vpe[XR←MAX←VPS];

    struct XR←IOPERep sa←iope[XR←MAX←IOPS];

    struct XR←ThreadRep sa←threadPool[XR←MAX←THREADS];

    XR←Pointer sa←clientData[XR←MAX←SA←CLIENT←DATA];

#undef XR←SA
} * XR←SA;


/*
 * enumerate all active threads
 */

extern bool
XR←ApplyToActiveThreadStacks (/*
    bool (*proc)(void *stackp, void *stacklimit, void *clientData),
    void *clientData
*/);
/*
    Apply proc to stacks of all active threads.
    Return TRUE if enumeration finishes.
    Abort enumeration and return FALSE if proc ever returns FALSE.

    This is reliable only if called from IOP with VProcessors stopped!
*/

#endif ←XR←THREADS←BACKDOOR←