/* 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 */ /* * XR←Threads.h * * Demers, July 13, 1992 4:43:12 pm PDT */ #ifndef ←←XR←Threads←h #define ←←XR←Threads←h 1 #include <xr/XR←Basics.h> #include <th/PCR←Th.h> /* * IMPORTANT NOTE: * * compiler and other runtime support assumes every data structure * can be initialized to zeroes! */ typedef struct XR←ThreadRep * XR←Thread; /* * Time * * ... for cv timeouts, pausing, etc. */ typedef unsigned XR←Ticks; #define XR←TICKS←PER←SECOND 20 #define XR←MSECS←PER←TICK (1000/XR←TICKS←PER←SECOND) #define XR←WAIT←FOREVER ((XR←Ticks) 0) extern XR←Ticks XR←TicksSinceBoot (void); /* Return time in ticks since boot. Wraparound is ignored. */ extern XR←Ticks XR←MsecToTicks (unsigned msec); /* Convert milliseconds to ticks. Rounds up. Overflow if msec > LAST(unsigned)-1000. */ extern unsigned XR←TicksToMsec (XR←Ticks ticks); /* Convert ticks to milliseconds. Undefined if it would overflow. */ extern bool XR←TicksLater (XR←Ticks a, XR←Ticks b); /* Return PCR←Bool←true iff a is strictly later than b. */ /* * BEWARE: the following is private to implementation. * It depends on XR←WAIT←FOREVER being 0. */ #define XR←TimeoutDataFromTimeout(timeout) ((PCR←Msec)(\ ((long)(timeout)) * XR←MSECS←PER←TICK )) #define XR←TimeoutFromTimeoutData(td) ((XR←Ticks)(\ ((long)(td)) / XR←MSECS←PER←TICK )) #define XR←WakeupFromTimeoutData(td) (\ PCR←Th←WakeMsec( (PCR←Msec)((long)(td)+(long)(PCR←waitForever)) )) /* * Monitor Locks */ typedef struct XR←MLRep { PCR←Th←ML ml←ml; long ml←pad[1]; } *XR←ML; struct XR←MLRep XR←MLRep←null; extern void XR←InitializeMonitor (XR←ML ml); /* Initialize `ml'. Call only once, before handing out the object. */ extern void XR←MonitorEntry (XR←ML ml); extern void XR←MonitorExit (XR←ML ml); /* * Condition Variables (CV's) */ typedef struct XR←CVRep { PCR←Th←CV cv←cv; long cv←timeoutData; /* coded -- see impl */ const PCR←sigset←t *cv←sigMask; /* either NIL or alertable */ long cv←pad[1]; } *XR←CV; struct XR←CVRep XR←CVRep←null; #define XR←sigmaskForAbortable (&(PCR←sigset←t←readonlyEmpty)) /* implementation detail */ #define XR←sigmaskForNotAbortable (NIL) /* implementation detail */ extern void XR←InitializeCondition (XR←CV cv, XR←Ticks timeout); /* Initialize `cv'. Call only once per variable. */ extern void XR←SetTimeout (XR←CV cv, XR←Ticks timeout); /* Set the timeout associated with `cv'. Has no effect on currently waiting threads. */ extern void XR←DisableTimeout (XR←CV cv); /* Disable timeouts for `cv'. Has no effect on currently waiting threads. */ extern XR←Ticks XR←GetTimeout (XR←CV cv); /* Get the timeout associated with `cv'. */ extern void XR←EnableAborts (XR←CV cv); /* Enable aborts on `cv'. No effect on threads currently waiting. */ extern void XR←DisableAborts (XR←CV cv); /* Disable aborts on `cv'. No effect on threads currently waiting. */ extern int XR←WaitCV (XR←CV cv, XR←ML ml); /* Wait for `cv'. Assumes `ml' is held; releases it while waiting. If `ml' is NIL, that's okay - this is a wait on an icv. Return 0 if okay, -1 if ABORTED. */ extern void XR←Notify (XR←CV cv); /* Notify `cv'. */ extern void XR←Broadcast (XR←CV cv); /* Broadcast `cv'. */ /* * The following is very delicate ... * * It depends on JMPBUFSIZE being at least as big as * PCR←setjmp←JBLEN from posix/setjmp.h (it is) * and probably on other things I'm not aware of. * The implementation must be assembly code that jumps * to setjmp ... */ #define JMPBUFSIZE 3 /* could be 2 ... */ typedef struct XR←JmpBufRep { unsigned jb←data[JMPBUFSIZE]; } *XR←JmpBuf; extern int XR←setjmp(XR←JmpBuf jb); /* Save context in *jb. On a sparc this is very cheap. */ #pragma unknown←control←flow(XR←setjmp) /* * signal/error interface * * * A handler proc is invoked * - as a result of a trap (in Unix, one of a collection of signals) * - explicitly by XR←CallHandler(...). * * When it is invoked: * It can call XR←RestartHandlee(...) instead of returning. * It can terminate the thread by calling XR←Exit. * IF the handlee is prepared to resume, the handler can resume it * by just returning. * * A handler proc is registered globally. * * It is okay to register NIL; a NIL handler just calls the debugger. */ /* Args to Unix signal handler -- these are inadequately dummied up */ typedef struct XR←TrapArgsRep { int ta←sig; int ta←code; void *ta←scp; XR←Pointer ta←addr; } *XR←TrapArgs; /* type code for handler */ typedef unsigned XR←HandlerWhich; /* 0 => not a handler call */ /* low values are reserved for machine- or OS- traps */ /* low-order bit => not resumable */ # define XR←HANDLER←WHICH←NULL 0 # define XR←HANDLER←WHICH←MK←FATAL(which) ((which) | 0x1) # define XR←HANDLER←WHICH←IS←FATAL(which) ((which) & 0x1) # define XR←HANDLER←WHICH←TRAP←UNIX (0x2) # define XR←HANDLER←WHICH←TRAP←UNIX←FATAL \ XR←HANDLER←WHICH←MK←FATAL(XR←HANDLER←WHICH←TRAP←UNIX) # define XR←HANDLER←WHICH←STACK←OVERFLOW \ XR←HANDLER←WHICH←MK←FATAL(1022) #define XR←HANDLER←WHICH←TRAP←LIM ((XR←HandlerWhich)(1024)) /* registered handler proc */ typedef void (*XR←HandlerProc)(/* XR←Thread handlee, -- obsolete, always XR←currThread XR←HandlerWhich which, -- exception type code XR←Pointer arg -- XR←TrapArgs for trap, else arbitrary XR←Pointer clientData -- client data registered with proc */); extern void XR←RegisterHandler (XR←HandlerProc proc, XR←Pointer data); /* Register (globally) a handler `proc'. */ extern void XR←RestartHandlee(XR←Thread t, XR←JmpBuf where, unsigned result); /* t is ignored. where must not be NIL. This just does a longjmp(where, result) */ XR←Thread XR←GetNextHandlee (XR←Thread t); /* return( (t == NIL) ? current thread : NIL ); */ /* Debugger request/response messages */ /* This stuff is NYI */ typedef int XR←DBMsg; # define XR←DB←MSG←NONE 0 # define XR←DB←MSG←IS←REQUEST(msg) ((msg) > 0) # define XR←DB←MSG←NO←HANDLER←REQUEST 1 # define XR←DB←MSG←HANDLER←REQUEST 2 # define XR←DB←MSG←BAD←PROCEED←REQUEST 3 # define XR←DB←MSG←BREAK←REQUEST 4 # define XR←DB←MSG←CLIENT←REQUEST 5 /* etc */ # define XR←DB←MSG←IS←REPLY(msg) ((msg) < 0) # define XR←DB←MSG←PROCEED←REPLY (-1) # define XR←DB←MSG←EXIT←REPLY (-2) # define XR←DB←MSG←ABORT←REPLY (-3) /* etc */ extern XR←DBMsg XR←CallDebugger2(XR←Pointer arg, XR←DBMsg msg); /* Call the debugger, making arg and msg available to it. The supplied msg should be of kind XR←DB←MSG←xxx←REQUEST. Result is of kind XR←DB←MSG←xxx←REPLY. */ extern XR←DBMsg XR←CallDebugger(XR←Pointer arg); /* Equivalent to XR←CallDebugger2(arg, XR←DB←MSG←CLIENT←REQUEST). */ /* * Thread (NOT world) exit ... */ extern void XR←Exit(void); /* Simulate return from top level procedure of the current thread. Do not release monitor locks, ... */ /* * Storage management -- imports */ extern XR←Pointer XR←ExtensionAlloc (int nWords); /* Allocate a frame extension of given size (in words). */ extern XR←Pointer XR←ExtensionFree (XR←Pointer x); /* Assuming x is the address of a frame extension allocated with XR←ExtensionAlloc, free it and return NIL. */ /* Thread Data Structure */ struct XR←ThreadRep { long youCantLookInHere; }; extern XR←Thread XR←currThread; /* current thread, OOPS! */ /* * Thread Priorities */ typedef unsigned XR←Pri; # define XR←PRI←IDLE ((XR←Pri)(0)) # define XR←PRI←USER←BACKGROUND ((XR←Pri)(1)) # define XR←PRI←SYS←BACKGROUND ((XR←Pri)(2)) # define XR←PRI←USER←NORMAL ((XR←Pri)(3)) # define XR←PRI←USER←FOREGROUND ((XR←Pri)(4)) # define XR←PRI←SYS←NORMAL ((XR←Pri)(5)) # define XR←PRI←SYS←FOREGROUND ((XR←Pri)(6)) # define XR←PRI←SYS←EXCLUSIVE ((XR←Pri)(7)) # define XR←PRI←LAST 7 extern XR←Pri XR←GetPriority (void); /* Return priority of current thread. */ extern void XR←SetPriority (XR←Pri pri); /* Set priority of current thread. */ extern void XR←Yield (void); /* Yield processor. */ /* * Checked Thread Data Structure -- includes ref and generation number */ typedef struct XR←CTRep { XR←Thread ct←thread; /* -> thread */ unsigned ct←gen; /* generation number */ } *XR←CT; extern void XR←GetCurrent (struct XR←CTRep *result); /* struct XR←CTRep *result; Return the current thread in *result. */ /* * Thread Create/Destroy runtime support */ extern void XR←Fork ( struct XR←CTRep *result, XR←MesaProc mp ); /* `mp' takes no arguments and returns a result record (possibly NIL?). It is the responsibility of the joiner to free this record using XR←ExtensionFree. Fork a new thread running `mp'. Return the checked thread in *result. XR←TryFork returns 0 on success or (-1) if thread slot is unavailable. XR←TryFork3 returns 0 on success or (-1) if no thread slot with at least the requested number of stack bytes is available. XR←Fork waits (not abortable) if no thread slot is available. */ /* OBSOLESCENT */ extern void XR←RegisterThreadStartProc (XR←MesaProc startProc); /* Register startProc as the "start proc" for this thread and its descendants. Ordinarily, the effect of XR←Fork(result, forkProc); is result = (*forkProc->mp←proc)(forkProc); After RegisterThreadStartProc(startProc) the effect will be result = (*startProc->mp←proc)(forkProc, startProc); allowing the startProc to catch uncaught signals, etc. It is okay to register NIL. */ extern int XR←TryJoinCT( XR←CT ct, bool abortable, XR←Pointer *resultp ); /* Try to join thread ct, storing (pointer to) its results in *resultp. Return 0 on success, -EINVAL, -ESRCH or -EABORTED on failure. */ extern int XR←PauseAbortable (XR←Ticks ticks); /* Pause the specified number of ticks, with aborts enabled. Ticks may be XR←WAIT←FOREVER. Return 0 ordinarily, or -1 if aborted. */ extern bool XR←AbortPending (void); /* Check whether an abort has been requested. This does not clear the p←abortRequest flag. */ extern int XR←CancelAbort (XR←CT ct); /* Cancel any abort request for `ct' (i.e. clear the t←abortRequest flag). If `ct' == NIL it means the current thread. Return 0 if okay, or -1 if `ct' is invalid. */ extern int XR←DetachCT (XR←CT ct); /* Detach `ct'. Return 0 if okay, or -1 if `ct' is invalid. */ extern int XR←AbortCT (XR←CT ct); /* Abort `ct'. Return 0 if okay, or -1 if `ct' is invalid. */ extern int XR←ValidateCT (XR←CT ct); /* Return 0 if okay, -1 if `ct' is invalid. */ /* * Per-Thread data */ extern XR←Pointer XR←GetThreadProperty (void); /* Return property value of current thread. */ extern void XR←SetThreadProperty (XR←Pointer p); /* Set property value of current thread. */ /* * Terminate the world ... */ extern void XR←ExitWorld (int status); /* Terminate PCR; in Unix(tm) this looks like ←exit(status); to the invoker of PCR. Tries to free all allocated resources (e.g. system semaphores, swap file, ...). */ #endif /* ←←XR←Threads←h */