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