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