/* 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 */ /* * Threads.h * * * Basic public type definitions * for Xerox Runtime threads package. * * Demers, January 25, 1991 4:24:55 pm PST */ #ifndef _XR_THREADS_ #define _XR_THREADS_ 1 #ifndef _XR_BASIC_TYPES_ # include "BasicTypes.h" #endif #ifndef _XR_THREADS_INLINES_ # include "ThreadsInlines.h" #endif #ifndef _XR_THREADS_SHARED_MEM_ # include "ThreadsSharedMem.h" #endif /* * Exported to CedarExtra.h * * XR_MonitorEntry * XR_MonitorExit * XR_WaitCV * XR_Notify * XR_Broadcast * XR_Fork * XR_JoinCT */ /* * Exported thread creation interceptor * * XR_RegisterThreadStartProc */ /* * Exported signal/error stuff * * XR_RegisterHandler * * XR_CallHandler * XR_RestartHandlee * * XR_GetNextHandlee * XR_GetHandlerStackOf * XR_GetHandlerStack * XR_SetHandlerStack * * XR_CallDebugger * * XR_Exit */ /* * Exported property stuff * * XR_GetThreadProperty * XR_GetThreadInheritedProperty * XR_SetThreadProperty * XR_SetThreadInheritedProperty * * XR_GetPerThreadDataID * XR_GetPerThreadDataAddress */ /* * Exported to Process * * XR_InitializeMonitor * XR_InitializeCondition * * XR_MsecToTicks * XR_TicksToMsec * * XR_SetTimeout * XR_DisableTimeout * * XR_PauseAbortable * XR_AbortPending * XR_CancelAbort * * XR_DetachCT * XR_GetCurrent * XR_SetPriority * XR_GetPriority * XR_AbortCT * XR_DisableAborts * XR_EnableAborts * XR_Yield * XR_ValidateCT */ /* * Exported for use by the brave: * * XR_ExitWorld * XR_KillWorld */ /* * Exported for use by Michael Plass: * * XR_RegisterSwitchCallback */ /* * IMPORTANT NOTE: * * compiler and other runtime support assumes every data structure * can be initialized to zeroes! */ #define XR_Thread struct XR_ThreadRep * /* breaks recursion in dcls */ /* * 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_USECS_PER_TICK (1000000/XR_TICKS_PER_SECOND) #define XR_WAIT_FOREVER ((XR_Ticks) 0) #define XR_END_OF_TIME ((XR_Ticks)(0xffffffff)) extern XR_Ticks XR_ticksPerSecond; extern unsigned XR_msecsPerTick; extern unsigned XR_usecPerTick; extern XR_Ticks XR_waitForever; extern XR_Ticks XR_endOfTime; extern XR_Ticks XR_TicksSinceBoot (/* */); /* Return time in ticks since boot. Wraparound is ignored. */ extern XR_Ticks XR_MsecToTicks (/* msec */); /* unsigned msec; Convert milliseconds to ticks. Rounds up. Overflow if msec > LAST(unsigned)-1000. */ #if XR_MSEC_TO_TICKS # define XR_MsecToTicks(msec) \ ( ((msec)+(XR_MSECS_PER_TICK-1)) / XR_MSECS_PER_TICK ) #endif extern unsigned XR_TicksToMsec (/* ticks */); /* XR_Ticks ticks; Convert ticks to milliseconds. Undefined if it would overflow. */ #if XR_TICKS_TO_MSEC # define XR_TicksToMsec(ticks) ((ticks)*XR_MSECS_PER_TICK) #endif extern bool XR_TicksLater (/* a, b */); /* XR_Ticks a, b; Return TRUE iff a is strictly later than b. */ #if XR_TICKS_LATER # define XR_TicksLater(a,b) ( ((int)((a)-(b))) > 0 ) #endif /* * Spin Locks * * Spin locks come in two flavors: * * Primitive spin locks (PSL's) are acquired by vprocessors. * General spin locks (GSL's) are acquired by threads. */ typedef unsigned XR_LockBit; /* * PSL's */ typedef struct XR_PSLRep { XR_LockBit psl_locked; /* lock is held */ } * XR_PSL; /* * GSL's */ typedef struct XR_GSLRep { XR_LockBit gsl_locked; /* lock is held */ } * XR_GSL; #define XR_NULL_GSL_REP { ((XR_LockBit)(0)) } /* * Thread Queues * * Conceptually there's a thread queue for each . * Must hold metalock to manipulate these. */ typedef struct XR_TQRep { XR_Thread tq_tail; /* -> tail of circ list by t_next */ unsigned long tq_schedCtlInfo; /* scheduler control per pri */ } * XR_TQ; #define XR_NULL_TQ_REP { NIL, 0 } /* * Wait Queues * * Every wait queue is protected by a GSL. * This GSL is overloaded to protect ml, cv structures, so it is * acquired/released separately from wait queue operations. * Caller of wait queue operations must hold the GSL. */ typedef struct XR_WQRep { struct XR_GSLRep wq_gsl; XR_Thread wq_tail; /* -> tail of circular list using t_wNext */ } * XR_WQ; #define XR_NULL_WQ_REP { XR_NULL_GSL_REP, NIL } /* * Monitor Locks */ typedef struct XR_MLRep { struct XR_WQRep ml_wq; /* (:0) waiters queue */ XR_Thread ml_holder; /* holds mon_lock */ } *XR_ML; #define ml_gsl ml_wq.wq_gsl #define XR_NULL_ML_REP { XR_NULL_WQ_REP, NIL } /* for assembly language */ #if( defined(sparc) ) #else # undef XR_MONITOR_ENTRY # define XR_MONITOR_ENTRY 0 # undef XR_MONITOR_EXIT # define XR_MONITOR_EXIT 0 #endif extern void XR_InitializeMonitor (/* ml */); /* XR_ML ml; Initialize `ml'. Call only once, before handing out the object. */ extern void XR_MonitorEntry (/* XR_ML ml */); extern void XR_MonitorEntryOutOfLine (/* XR_ML ml */); /* Acquire `ml'. Defining XR_MONITOR_ENTRY replaces the C version of XR_MonitorEntry by an assembly language one, which may call XR_MonitorEntryOutOfLine. */ extern void XR_MonitorExit (/* XR_ML ml */); extern void XR_MonitorExitOutOfLine (/* XR_ML ml */); /* Release `ml', waking up next thread waiting on it. Defining XR_MONITOR_EXIT replaces the C version of XR_MonitorEntry by an assembly language one, which may call XR_MonitorExitOutOfLine. */ /* * Condition Variables (CV's) */ typedef struct XR_CVRep { struct XR_WQRep cv_wq; /* (:0) waiting threads */ XR_Ticks cv_timeout; /* timeout for waiting threads */ bool cv_abortable; /* aborts enabled? */ bool cv_wakeupWaiting; /* a wakeup is waiting */ } *XR_CV; #define cv_gsl cv_wq.wq_gsl #define XR_NULL_CV_REP { XR_NULL_WQ_REP, XR_WAIT_FOREVER, FALSE, FALSE } extern void XR_InitializeCondition (/* cv, timeout */); /* XR_CV cv; XR_Ticks timeout; Initialize `cv'. Call only once per variable. */ extern void XR_SetTimeout (/* cv, timeout */); /* XR_CV cv; XR_Ticks timeout; Set the timeout associated with `cv'. Has no effect on currently waiting threads. */ extern void XR_DisableTimeout (/* cv */); /* XR_CV cv; Disable timeouts for `cv'. Has no effect on currently waiting threads. */ #if XR_DISABLE_TIMEOUT # define XR_DisableTimeout(cv) (cv)->cv_timeout = XR_WAIT_FOREVER #endif extern XR_Ticks XR_GetTimeout (/* cv */); /* XR_CV cv; Get the timeout associated with `cv'. */ #if XR_GET_TIMEOUT # define XR_GetTimeout(cv) ((cv)->cv_timeout) #endif extern void XR_EnableAborts (/* cv */); /* XR_CV cv; Enable aborts on `cv'. No effect on threads currently waiting. */ #if XR_ENABLE_ABORTS # define XR_EnableAborts(cv) (cv)->cv_abortable = TRUE #endif extern void XR_DisableAborts (/* cv */); /* XR_CV cv; Disable aborts on `cv'. No effect on threads currently waiting. */ #if XR_DISABLE_ABORTS # define XR_DisableAborts(cv) (cv)->cv_abortable = FALSE #endif extern int XR_WaitCV (/* cv, ml */); /* 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 (/* cv */); /* XR_CV cv; Notify `cv'. */ extern void XR_Broadcast (/* cv */); /* XR_CV cv; Broadcast `cv'. */ extern void XR_NakedNotify (/* cv */); /* XR_CV cv; Naked notify of `cv'. This is intended to be used by an ioprocessor rather than a thread. */ /* * context save/restore * * The following stuff replaces Unix _setjmp/_longjmp. * It's faster, and XR_longjmp works for switching away from a stack * that you're subsequently going to switch back to. * The XR and Unix versions CANNOT BE USED INTERCHANGEABLY: * _setjmp/XR_longjmp or XR_setjmp/_longjmp pairs will blow up! * * Also here is some processor-dependent information about the format * of a procedure frame (arguably this belongs somewhere else). * * We assume a frame is described by a pair, and contains enough * information to get the caller's resume pc and frame. * * On some processors (e.g. sparc) we don't need the fp, and it disappears * from the macro-generated code. */ #if defined(sparc) # define JMPBUFSIZE 3 /* could be 2 ... */ # define XR_PC_FROM_JMP_BUF(b) (((XR_Pointer *)(b->jb_data))[0]) # define XR_FP_FROM_JMP_BUF(b) --> not used on sparc <-- # define XR_SP_FROM_JMP_BUF(b) (((XR_Pointer *)(b->jb_data))[2]) # define XR_SAVED_PC(t) ((XR_Pointer)(((XR_Thread)(t))->t_resume.jb_data[0])) # define XR_SAVED_FP(t) --> not used on sparc <-- # define XR_SAVED_SP(t) ((XR_Pointer)(((XR_Thread)(t))->t_resume.jb_data[2])) # define XR_GET_SAVED_FRAME(t,fp,sp) \ (sp) = XR_SAVED_SP(t) # define XR_OLD_PC_FROM_FRAME(fp,sp) ((XR_Pointer *)(sp))[15] # define XR_OLD_FP_FROM_FRAME(fp,sp) --> not used on sparc <-- # define XR_OLD_SP_FROM_FRAME(fp,sp) ((XR_Pointer *)(sp))[14] /* following must work for aliased fp=ofp and for aliased sp=osp */ # define XR_GET_OLD_FRAME_FROM_FRAME(fp,sp,ofp,osp) \ (osp) = ((XR_Pointer *)(sp))[14] # define XR_RSA_BYTES (16*4) /* size of register save area */ # define XR_CHECK_FRAME(fp,sp,t) XR_WITHIN_STACK(sp,t,XR_RSA_BYTES) #else --> fix me for this cputype <-- #endif typedef struct XR_JmpBufRep { unsigned jb_data[JMPBUFSIZE]; } *XR_JmpBuf; extern int XR_setjmp(/* jb */); /* XR_JmpBuf jb; Save context in *jb. On a sparc this is very cheap. */ #pragma unknown_control_flow(XR_setjmp) extern void XR_longjmp(/* jb, rv */); /* XR_jmpbuf jb; int rv; Return value rv to the context saved in *jb. */ /* * 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 starts with an empty stack. * 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 with each thread, and is inherited across * XR_Fork calls. * * It is okay to register NIL; a NIL handler just calls the debugger. */ /* Args to Unix signal handler -- see */ typedef struct XR_TrapArgsRep { int ta_sig; int ta_code; struct sigcontext *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 */); /* XR_HandlerData is private */ typedef struct XR_HandlerDataRep { XR_HandlerProc hd_proc; /* registered handler proc */ XR_Pointer hd_clientData; /* passed to proc when invoked */ XR_HandlerWhich hd_which; /* saved XR_HandlerProc `which' argument */ XR_Pointer hd_arg; /* saved XR_HandlerProc `arg' argument */ struct XR_JmpBufRep hd_resume; /* resume after trap or CallDebugger ... */ unsigned hd_result; /* ... by XR_longjmp(&hd_resume, hd_result) */ } * XR_HandlerData; extern void XR_InitHandlerData (/* XR_HandlerData handler, XR_Thread next */); extern void XR_RegisterHandler (/* XR_HandlerProc proc, XR_Pointer data */); /* Register a handler `proc' for this thread and its descendants. */ /* Debugger request/response messages */ 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). */ extern void XR_Exit(); /* Simulate return from top level procedure of the current thread. Do not release monitor locks, ... */ /* * Storage management -- imports */ extern XR_Pointer XR_ExtensionAlloc (/* nWords */); /* int nWords; Allocate a frame extension of given size (in words). */ XR_Pointer XR_ExtensionFree (/* x */); /* XR_Pointer x; Assuming x is the address of a frame extension allocated with XR_ExtensionAlloc, free it and return NIL. */ /* * Stack description */ typedef struct XR_StackRep { struct XR_SegRep stack_seg; /* shared memory segment containing stack */ XR_Pointer stack_handlerInitial; /* initial value for handler stack */ XR_Pointer stack_clientInitial; /* initial value for client stack */ XR_Pointer stack_warmLimit; /* warm stack limit -- checked by e.g. Switch */ } * XR_Stack; /* NOTE: the following work for machines on which the stack "grows" */ /* toward smaller addresses -- e.g. sparc, 68K, vax, ... */ #define stack_physInitial stack_handlerInitial #define stack_physLimit stack_seg.seg_addr #define XR_WITHIN_STACK(sp,t,bytes) \ ( (((sp)+(bytes)) <= (t)->t_stack.stack_physInitial) \ && ((sp) >= (t)->t_stack.stack_physLimit) ) #define XR_WITHIN_WARM_STACK(sp,t,bytes) \ ( (((sp)+(bytes)) <= (t)->t_stack.stack_physInitial) \ && ((sp) >= (t)->t_stack.stack_warmLimit) ) #define XR_WARM_STACK_EXCEEDED(sp,t) \ ( (sp) < (t)->t_stack.stack_warmLimit ) #ifdef sparc # define XR_STACK_ALIGNMENT_OK(sp) (((sp) & 0x7) == 0) # define XR_STACK_ALIGN(sp) ( ((XR_Pointer)(sp)) & ~0x7 ) #else --> fix me <-- #endif /* * Thread descriptors */ /* Scheduling State */ typedef unsigned XR_SStat; # define XR_SSTAT_NONE ((XR_SStat)(0)) # define XR_SSTAT_FREE ((XR_SStat)(1)) /* free, with stack */ # define XR_SSTAT_READY ((XR_SStat)(2)) /* ready */ # define XR_SSTAT_RUN ((XR_SStat)(3)) /* running */ # define XR_SSTAT_WAIT_ML ((XR_SStat)(4)) /* waiting ml */ # define XR_SSTAT_WAIT_CV ((XR_SStat)(5)) /* waiting cv */ # define XR_SSTAT_LAST ((XR_SStat)(5)) /* Priority */ 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 /* Switch State */ typedef unsigned XR_SwStat; # define XR_SWSTAT_NONE ((XR_SwStat)(0)) # define XR_SWSTAT_DONT_PREEMPT ((XR_SwStat)(1)) # define XR_SWSTAT_THREAD ((XR_SwStat)(2)) # define XR_SWSTAT_HANDLER ((XR_SwStat)(3)) # define XR_SWSTAT_HSTACK ((XR_SwStat)(4)) # define XR_SWSTAT_LAST 4 /* Join State */ typedef unsigned XR_JStat; # define XR_JSTAT_NONE ((XR_JStat)(0)) # define XR_JSTAT_EXITING ((XR_JStat)(1)) # define XR_JSTAT_JOINING ((XR_JStat)(2)) # define XR_JSTAT_JOINED ((XR_JStat)(3)) # define XR_JSTAT_DETACHED ((XR_JStat)(4)) # define XR_JSTAT_DONE ((XR_JStat)(5)) # define XR_JSTAT_LAST 5 /* Debugger request/response messages */ /* see XR_DBMsg above */ # define XR_NUM_PER_THREAD_DATA 8 /* Thread Data Structure */ typedef struct XR_ThreadRep { /* result of last UNIX system call */ /* ThreadsMachDep.s depends on these fields being at offset 0 and 4 */ int t_errno; /* result of last system call ... */ int t_errnoLock; /* ... that was invoked with lock false */ /* rescheduling hints for monitor entry/exit */ /* ThreadsMachDep.s depends on these fields being at offset 8 and 12 */ void * t_vpeToReschedOnMonitorExit; XR_ML t_mlNeeded; /* index values */ int t_index; /* index in thread table */ int t_timeoutIndex; /* >0 ==> waiting for timeout */ unsigned t_gen; /* generation number (won't repeat) */ /* scheduling state, thread queue -- must hold metaLock to change */ XR_SStat t_sStat; /* scheduling state */ XR_Pri t_pri; /* scheduling priority */ XR_Ticks t_when; /* ticks-since-boot when timeout wanted */ XR_Thread t_next; /* next in thread queue */ XR_TQ t_tq; /* queue containing this thread */ unsigned long t_schedCtlInfo; /* see ThreadsSchedCtl.h */ unsigned long t_disabled; /* see ThreadsSchedCtl.h */ /* wait queue */ XR_Thread t_wNext; /* next pointer in wait queue */ XR_WQ t_wq; /* wq containing this thread */ /* free queue */ XR_TQ t_fq; /* free queue for this thread */ /* slow timeout */ struct XR_CVRep t_timerCV; /* context */ struct XR_JmpBufRep t_resume; XR_SwStat t_swStat; /* handler data */ struct XR_HandlerDataRep t_handlerData; /* ??? */ /* memory map info */ struct XR_StackRep t_stack; /* thread stack description */ /* ABORT state */ bool t_abortable; /* significant when waiting on cv/icv */ bool t_abortRequest; /* abort requested but not yet acted on */ /* thread (re)starting */ XR_Pointer t_jumpSP; /* non-NIL ==> call XR_Jumpee with */ /* sp set to this */ void (*t_jumpProc)(/*arg*/); /* called with t_jumpArg by XR_Jumpee */ unsigned t_jumpArg; /* FORK/JOIN/Detach MONITORED RECORD */ struct XR_MLRep t_ml; /* lock on remaining fields */ XR_MesaProc t_startProc; /* start proc for this thread */ /* ??? */ XR_Pointer t_result; /* result data for joiner */ XR_JStat t_jStat; /* JOIN/Detach state */ struct XR_CVRep t_jCVc; /* for join-detach, child waits */ struct XR_CVRep t_jCVp; /* for join-detach, parent waits */ /* debugger */ XR_DBMsg t_dbMsg; /* for communication with debugger */ bool t_dbFreeze; /* freeze request from debugger */ bool t_dbFrozen; /* thread is frozen */ /* per-thread client data */ XR_Pointer t_dynEnv; /* dynamic environment */ XR_Pointer t_perThreadData[XR_NUM_PER_THREAD_DATA]; #undef XR_Thread } * XR_Thread; extern XR_Thread XR_currThread; /* current thread, PER PROCESSOR */ /* * Thread Priorities */ extern XR_Pri XR_GetPriority (); /* Return priority of current thread. */ #if XR_GET_PRIORITY # define XR_GetPriority() (XR_currThread->t_pri) #endif extern void XR_SetPriority (/* pri */); /* XR_Pri pri; Set priority of current thread. */ extern void XR_Yield (/* */); /* 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 (/* 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 */); extern int XR_TryFork (/* struct XR_CTRep *result, XR_MesaProc mp */); extern int XR_TryFork3 (/* struct XR_CTRep *result, XR_MesaProc mp, unsigned minStackBytes */); /* `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 (/* startProc */); /* 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. */ # if XR_REGISTER_THREAD_START_PROC # define XR_RegisterThreadStartProc(startProc) \ XR_currThread->t_startProc = (startProc) # endif extern XR_Pointer XR_JoinCT (/* ct */); /* XR_CT ct; JOIN with `ct' returning (pointer to) its results. The caller is presumed to know how many results to expect. If cp is an invalid thread, return ((XR_Pointer)(-1)), which is guaranteed not to be a valid pointer. */ 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 (/* ticks */); /* 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 (); /* Check whether an abort has been requested. This does not clear the p_abortRequest flag. */ #if XR_ABORT_PENDING # define XR_AbortPending() (XR_currThread->t_abortRequest) #endif extern int XR_CancelAbort (/* ct */); /* 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 (/* ct */); /* XR_CT ct; Detach `ct'. Return 0 if okay, or -1 if `ct' is invalid. */ extern int XR_AbortCT (/* ct */); /* XR_CT ct; Abort `ct'. Return 0 if okay, or -1 if `ct' is invalid. */ extern int XR_ValidateCT (/* ct */); /* XR_CT ct; Return 0 if okay, -1 if `ct' is invalid. */ /* * Per-Thread data */ extern int XR_GetPerThreadDataID(/* XR_Pointer key, bool create, bool inherit */); /* Return an id for per-thread data to be associated with the (non-NIL) value of key. : key == NIL => <-1, EINVAL> create == FALSE and no registration exists for key => <-1, EINVAL> create == TRUE and a registration already exists => <-1, EINVAL> no more slots => <-1, ENOMEM> okay => If the call is successful with create == TRUE, then the corresponding per-thread data is inherited across FORKs iff inherit == TRUE. */ extern XR_Pointer * XR_GetPerThreadDataAddress(/* int id */); /* Return address of per-thread data slot. */ #if XR_GET_PER_THREAD_DATA_ADDRESS # define XR_GetPerThreadDataAddress(id) ((XR_Pointer *) \ (((char *)(XR_currThread))+((int)(id))) ) #endif /* obsolete versions ... */ extern int XR_GetPerThreadDataOffset(/* XR_Pointer key, bool create */); /* Return a byte offset from XR_currThread to be used for per-thread client data associated with the (non-zero) value of key. The offset will be word-aligned but might be negative. : key == 0 => <-1, EINVAL> create == FALSE and no registration exists for key => <-1, EINVAL> create == TRUE and a registration already exists => <-1, EINVAL> no more slots => <-1, ENOMEM> okay => */ extern XR_Pointer * XR_GetPerThreadDataSlot(/* int byteOffset */); /* Return address of per-thread data slot at given offset. */ extern XR_Pointer XR_GetThreadProperty (/* */); /* Return property value of current thread. */ extern XR_Pointer XR_GetThreadInheritedProperty (/* */); /* Return inherited property value of current thread. */ extern void XR_SetThreadProperty (/* p */); /* XR_Pointer p; Set property value of current thread. */ extern void XR_SetThreadInheritedProperty (/* p */); /* XR_Pointer p; Set inherited 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, ...). */ extern void XR_KillWorld (/* */); /* Equivalent to XR_ExitWorld(-1). Obsolescent. */ /* * Thread switch recording (for performance monitoring) */ extern void XR_RegisterSwitchCallback(/* XR_MesaProc proc, XR_MesaProc *oldProcP */); /* Register a proc to be called whenever a thread is switched away from. The proc is called by (*(proc->mp_proc))( nextThread, (* dest thread for handoff scheduling *) nextState, (* state this thread is changing to *) swStat, (* from handler? (see XR_SWStat) *) proc ); Return old registration in *oldProcP. (This may be NIL, => don't return anything.) The proc may not acquire locks, or do anything else that might induce a switch (e.g. call XR_Yield() ... ). */ extern void XR_RegisterSetReadyCallback(/* XR_MesaProc proc, XR_MesaProc *oldProcP */); /* Register a proc to be called whenever a thread is made runnable. The proc is called by (*(proc->mp_proc))( runnableThread, (* thread to be made runnable *) proc ); Return old registration in *oldProcP. (This may be NIL, => don't return anything.) The proc may not acquire locks, or do anything else that might induce a switch (e.g. call XR_Yield() ... ). */ #endif _XR_THREADS_