/* ************************************************************************* * * * Copyright 2001 Compaq Computer Corporation * * * * COMPAQ Registered in U.S. Patent and Trademark Office. * * * * Confidential computer software. Valid license from Compaq or * * authorized sublicensor required for possession, use or copying. * * Consistent with FAR 12.211 and 12.212, Commercial Computer Software, * * Computer Software Documentation, and Technical Data for Commercial * * Items are licensed to the U.S. Government under vendor's standard * * commercial license. * * * * Compaq shall not be liable for technical or editorial errors or * * omissions contained herein. The information in this document is * * subject to change without notice. * * * ************************************************************************* */ /* * @(#)$RCSfile: pthread.h,v $ $Revision: 1.1.29.12 $ (DEC) $Date: 2000/09/01 18:37:14 $ */ /* * FACILITY: * * DECthreads POSIX 1003.1c * * ABSTRACT: * * External definitions for POSIX 1003.1c interfaces * * General notice: some of the types defined and used in this header are * not standard POSIX 1003.1c types. The DECthreads specific types are * generally used instead of "void *" and "long" where pointer size * #pragma declarations are necessary to support the OpenVMS Alpha 64-bit * programming environment. (And in a few other cases where it's * convenient.) These types should not present any obstacle to programs * coded using the standard types. The "addon" types are distinguished by * naming convention -- they begin with "__pthread" and the remainder * appears in mixed-case without punctuation. For example, * "__pthreadLongAddr_t" for "void *" and "__pthreadLongUint_t" for * "unsigned long". * * This header file contains extensive comments regarding the structures * and options. Please read them carefully before relying upon any * undocumented features -- they're undocumented for a reason! We want * you to be able to take advantage of them where appropriate, but you * must also understand the restrictions and risks. * * AUTHORS: * * Dave Butenhof * * CREATION DATE: * * January 1995 * * MODIFIED BY: * * Dave Butenhof * Paul Clark * Steve Johnson * Richard Love * Peter Portante * Webb Scales * Brian Silver * Mark Simons * Tom Dahl * * LAST MODIFICATION DATE: * * 21 October 1999 */ #ifndef _PTHREAD_HEADER # define _PTHREAD_HEADER /****************************************************************************** * * NOTICE: Temporary support for POSIX 1003.4a/D4 migration * -------------------------------------------------------- * * Support 1003.4a/D4 ("DCE threads") source migration mode by allowing * programmer to cause #include to define the old interfaces (with * modified names) if the _PTHREAD_USE_D4 macro is defined. This is equivalent * to #include -- the remainder of this header file is not * processed. * * In practice, the easiest way to do this is to continue to build threaded * code using the "-threads" switch, which will define _PTHREAD_USE_D4: * * cc -threads foo.c * * Or, you can invoke the source migration mode by the following sequence * within your .c or .h files: * * #define _PTHREAD_USE_D4 * #include * * Or, finally, by modifying your Makefile (or manual build sequence) to use * the -D compiler option. (Note: you must ALWAYS define _REENTRANT when * compiling threaded or thread-safe code on Tru64 UNIX. Using "cc -threads" * or "cc -pthread" does this automatically.) * * cc -D_PTHREAD_USE_D4 -D_REENTRANT foo.c * * On OpenVMS, use the #define solution, or the following DECC command (it is * not necessary to define _REENTRANT on OpenVMS): * * cc /define=_PTHREAD_USE_D4 foo.c * * The POSIX 1003.4a/D4 migration support may be retired (this clause will be * removed from pthread.h!) in the next major release of each operating system * (OpenVMS VAX, OpenVMS Alpha, and Tru64 UNIX) that occurs at least one year * after the initial release of the POSIX 1003.1c interfaces in Tru64 UNIX 4.0 * and OpenVMS 7.0. * *****************************************************************************/ #if defined (_PTHREAD_USE_D4) || defined (PTHREAD_USE_D4) # if defined (__unix__) || defined (__unix) || defined (unix) # include # else # include # endif #else /* * Define a symbol which client code can test to determine whether the * underlying threads package is DECthreads or not. This is especially * important to clients of the POSIX 1003.1c interface who may want to use * DECthreads extensions, such as the TEB, global lock and non-real-time * scheduling policies while maintaining portability to a "vanilla" * 1003.1c-1995 implementation. * * The DECthreads version is encoded in this number. The version is normally * in the form "Vvv.bb-lll" where "vv" represents the major version, "bb" * represents the baselevel (which increases continuously regardless of * version), and "lll" is a build level that increases in each DECthreads * project build within a baselevel. * * Higher numeric values are always more recent versions. So to check for * support of a feature that appeared in DECthreads V3.13-100, you could check * whether the symbol is > 212100L. */ #ifdef _DECTHREADS_VERSION # undef _DECTHREADS_VERSION #endif #define _DECTHREADS_VERSION 317018 #ifndef _DECTHREADS_ # define _DECTHREADS_ _DECTHREADS_VERSION #endif /****************************************************************************** * * NOTICE: inline function performance vs. binary compatibility * ------------------------------------------------------------ * * This version of pthread.h supports the capability of generating inlined * code on OpenVMS Alpha and Tru64 UNIX for improved performance on some * critical operations -- especially mutex synchronization and reading thread * specific data. * * There is a balance between performance and maintainability, however. Inline * code sequences cannot be transparently fixed by future versions of * DECthreads. Thus, if a bug is found in the inlined code and later fixed, * programs using the inlined sequences must be recompiled to acquire the fix. * Additionally changes may be made to inlined sequences to improve * reliability or performance in the future. Digital cannot guarantee that the * new sequences will be binary compatible with the old sequences, and * therefore any such changes may also require recompilation. * * By default, this version of pthread.h will generate calls to carefully * tuned assembly code functions within DECthreads that implement the same * algorithm as the inline asm() code sequences. This provides safety at the * expense of performance by adding the overhead of a call and some * unavoidable procedure prolog and epilog code. If you need the performance * advantage of avoiding those calls, AND ARE WILLING TO ACCEPT THE RISK THAT * YOU WILL NEED TO RECOMPILE LATER, define the preprocessor symbol * _PTHREAD_USE_INLINE before including this header file; either by compiling * with * * cc -D_PTHREAD_USE_INLINE * * or by using "#define" before including this header file: * * #define _PTHREAD_USE_INLINE * #include * * Although _PTHREAD_USE_INLINE is made available for experimentation and * where the need for performance is extreme, Digital STRONGLY RECOMMENDS that * use of this option be avoided. * *****************************************************************************/ /****************************************************************************** * * NOTICE: DECthreads metered sychronization and static mutex initialization * ------------------------------------------------------------------------- * * When a program using DECthreads is run with the environment variable * PTHREAD_CONFIG containing the option "METER=1", DECthreads will record all * synchronization operations. Normally, when a mutex is statically * initialized using PTHREAD_MUTEX_INITIALIZER that mutex is excluded from * metering until the first time a thread is required to block on the mutex * (when contention occurs). Although this may be fine, during debugging it's * often useful to know when "nonblocking" locks occur, as well. * * If the preprocessor symbol _PTHREAD_NOMETER_STATIC is not defined when this * header file is included, statically initialized mutexes will be set up such * that the first attempt to lock the mutex (regardless of whether the thread * must block) will involve a call into DECthreads. If metering is enabled the * operation (and all future operations on the mutex) will be metered. If * metering is not enabled, the mutex will be modified such that nonblocking * locks (and unlocks without waiters) will not require additional calls into * DECthreads. In other words, when metering is not enabled the extra cost of * the default mode (_PTHREAD_NOMETER_STATIC not defined) is a single call the * first time a thread uses each mutex. * *****************************************************************************/ /****************************************************************************** * * NOTICE: POSIX 1003.1c support * ----------------------------- * * The POSIX 1003.1c-1995 standard was formally approved at the June 1995 * meeting of the IEEE Standards Board. The correct configuration test macro * for strictly conforming POSIX 1003.1c-1995 applications is * * #define _POSIX_C_SOURCE 199506L * * The POSIX standard requires that, for portability, the application must * define _POSIX_C_SOURCE within each compilation unit, for example, by * compiling with -D_POSIX_C_SOURCE=199506L. The Tru64 UNIX will * default _POSIX_C_SOURCE to the latest POSIX 1003.1 revision supported by * the operating system (currently 1003.1c-1995) if no other confining * standard definitions are already defined. In other words, unless the * programmer specifies a specific restriction, the programmer will have * access to all standards that aren't inherently incompatible. * * Compiling with some other standards modes will disable POSIX 1003.1c-1995 * support, as the thread interfaces violate name space rules required by * those standards. For example, defining any of the symbols _POSIX_SOURCE * (1003.1-1990), _POSIX_C_SOURCE=199309L (1003.1b-1993), _XOPEN_SOURCE or * _XOPEN_SOURCE_EXTENDED (UNIX95 or earlier, which require 1003.1-1990), or * _ANSI_C_SOURCE (ANSI C) will disable thread support. A program built with * any of these options that includes will not compile properly, * as will fail to define types and symbols required by * pthread.h. * * Note that the Single UNIX Specification, Version 2 (UNIX98) from The Open * Group (X/Open) provides threads, and therefore defining _XOPEN_SOURCE=500 * (XSH5) does not conflict with use of POSIX threads. In fact XSH5 requires * that setting _XOPEN_SOURCE=500 overrides "inappropriate" settings of * _POSIX_C_SOURCE, _POSIX_SOURCE, or _ANSI_C_SOURCE. * * The header always defines _POSIX_VERSION to the latest POSIX.1 * revision supported by the system -- 199506L (1003.1c-1995) for Tru64 UNIX * 4.0. A portable program can use this symbol (or specific POSIX feature test * macros such as _POSIX_THREADS, also defined in ) to determine * whether the system supports POSIX 1003.1c-1995. (However, beware that * implementations of early drafts of 1003.1c, such as "DCE threads", which * supported 1003.4a/D4, may also define _POSIX_THREADS, but will not define * _POSIX_VERSION to 199506L.) * *****************************************************************************/ #if defined (__cplusplus) || defined (__DECCXX) # define _PTHREAD_ENV_CXX #elif defined (__DECC) || defined (__decc) # define _PTHREAD_ENV_DECC #elif defined (__EPCC__) # define _PTHREAD_ENV_EPCC #endif #if defined (VMS) || defined (__VMS) || defined (__vms) || defined (vms) # define _PTHREAD_ENV_VMS #elif defined (__unix__) || defined (__unix) || defined (unix) # define _PTHREAD_ENV_UNIX #endif #if defined (vax) || defined (VAX) || defined (__vax) || defined (__VAX) # define _PTHREAD_ENV_VAX #elif defined (__alpha) || defined (__ALPHA) # define _PTHREAD_ENV_ALPHA #elif defined (__ia64__) # define _PTHREAD_ENV_IA64 #elif defined (_M_IX86) # define _PTHREAD_ENV_X86 #endif #if !defined (_PTHREAD_ENV_DECC) && defined (_PTHREAD_ENV_VAX) # if defined (vaxc) || defined (VAXC) || defined (__vaxc) || defined (__VAXC) # define _PTHREAD_ENV_VAXC # endif #endif #ifdef _PTHREAD_ENV_CXX extern "C" { #endif #if defined (_PTHREAD_ENV_CXX) || defined (_PTHREAD_ENV_DECC) # define _PTHREAD_IMPORT_ extern #elif defined (_PTHREAD_ENV_VAXC) # define _PTHREAD_IMPORT_ globalref #else # define _PTHREAD_IMPORT_ extern #endif /* * Enable reentrant errno.h */ #ifdef _PTHREAD_ENV_UNIX # ifndef _REENTRANT # define _REENTRANT 1 # endif #endif #ifdef _PTHREAD_ENV_UNIX # include # include #endif #include #if defined (_PTHREAD_ENV_UNIX) && !defined (_PTHREAD_CORE_BUILD_) # define _PTHREAD_EXC_INCL_CLEAN #endif #include #ifdef _PTHREAD_EXC_INCL_CLEAN # undef _PTHREAD_EXC_INCL_CLEAN #endif #if defined (_PTHREAD_ENV_UNIX) # if defined (_OSF_SOURCE) && defined (_PTHREAD_ENV_ALPHA) # if defined (_PTHREAD_ENV_DECC) || defined (_PTHREAD_ENV_DECCXX) # include # define _PTHREAD_USE_ASM_ 1 # endif # endif # define _PTHREAD_USE_MANGLED_NAMES_ 1 # ifndef _PTHREAD_LEGACY_NP /* libpthreads wrappers */ # if defined (_PTHREAD_ENV_DECC) || defined (_PTHREAD_ENV_EPCC) # define _PTHREAD_USE_PTDNAM_ # endif # endif # define _PTDNAM(name) __##name # include # include # include # include #else # include # if defined (_PTHREAD_ENV_DECC) && (__DECC_VER >= 50260000) # include # else # ifndef _TIMESPEC_T_ # define _TIMESPEC_T_ typedef struct timespec { unsigned long tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ } timespec_t; # endif # endif # ifndef _SCHEDPARAM_T_ # define _SCHEDPARAM_T_ typedef struct sched_param { int sched_priority; } sched_param_t; # endif # ifndef sched_yield # define sched_yield pthread_yield_np # endif #endif #if defined (_PTHREAD_ENV_DECC) # define _PTHREAD_INLINE_ __inline #elif defined (_PTHREAD_ENV_DECCXX) # define _PTHREAD_INLINE_ inline #else # define _PTHREAD_INLINE_ #endif #ifndef _PTDNAM # define _PTDNAM(name) name #endif #if defined (_PTHREAD_ENV_VMS) && defined (_PTHREAD_ENV_ALPHA) # if defined (__DECC) && (__DECC_VER >= 50000000) # define _PTHREAD_USE_ASM_ 1 # if __DECC_VER < 50230004 # define _PTHREAD_SKIP_LOOPY_ASM_ 1 # endif # include # endif # define _PTHREAD_ALLOW_MIXED_PROTOS_ 1 #endif #if !defined (_PTHREAD_ENV_UNIX) /* * If we are not a UNIX system, then the field names for the POSIX standard * types don't have to be name space protected. */ # define _Pfield(_arg_) _arg_ #endif #ifdef _PTHREAD_ENV_VAXC /* * If compiling on OpenVMS VAX under VAX C, define missing POSIX 1003.1c error * symbols to the values used by DEC C so they'll match what DECthreads * returns. */ # ifdef ENOSYS # undef ENOSYS # endif # define ENOSYS 76 # ifdef ENOTSUP # undef ENOTSUP # endif # define ENOTSUP 81 # ifdef EDEADLK # undef EDEADLK # endif # define EDEADLK 82 #endif /****************************************************************************** * * NOTICE: Tru64 UNIX and "name mangling" * -------------------------------------- * * On Tru64 UNIX, maintaining binary compatibility for call_shared code using * the old 1003.4a/D4 interfaces (many of which have the same names as the * 1003.1c functions) requires that the compatibility interfaces retain their * names. Since the 1003.4a/D4 and 1003.1c functions must be able to coexist * within a process, this inevitably leads to the conclusion that we must give * the 1003.1c functions "mangled" names during the 1003.4a/D4 retirement * period. * * To that end, we map the 1003.1c standard names into "mangled" internal * names. When 1003.4a/D4 is retired these macros will be removed; the 1003.1c * functions will then be given their proper names. Binary compatibility for * images compiled during the retirement period will be retained by aliases * for the transition names. Note that we "mangle" only the names that are * identical to 1003.4a/D4 names. New functions (such as pthread_key_delete) * and functions with changed names (such as pthread_key_create, contrasted to * 1003.4a/D4's pthread_keycreate) are not mangled. * * The following names are "mangled": * * pthread_attr_getguardsize_np * pthread_attr_getinheritsched * pthread_attr_getstacksize * pthread_attr_setguardsize_np * pthread_attr_setinheritsched * pthread_attr_setstacksize * pthread_cancel * pthread_cond_broadcast * pthread_cond_destroy * pthread_cond_init * pthread_cond_sig_preempt_int_np * pthread_cond_signal * pthread_cond_signal_int_np * pthread_cond_timedwait * pthread_cond_wait * pthread_create * pthread_delay_np * pthread_detach * pthread_equal * pthread_exit * pthread_get_expiration_np * pthread_getspecific * pthread_join * pthread_lock_global_np * pthread_mutex_destroy * pthread_mutex_init * pthread_mutex_lock * pthread_mutex_trylock * pthread_mutex_unlock * pthread_once * pthread_self * pthread_setspecific * pthread_testcancel * pthread_unlock_global_np * * On OpenVMS this is irrelevant since name binding occurs at link time: when * images are activated they bind to a known offset within the image symbol * vector (Alpha) or transfer vector (VAX). The binary compatibility interface * names have been changed, but the arrangement of the transfer vector and * symbol vector remain the same. Thus old code linked against the old * shareable images will call the correct new routine. * *****************************************************************************/ /* * NOTICE: OpenVMS Alpha 64-bit pointer support * -------------------------------------------- * * On OpenVMS Alpha DECthreads generally supports both the 64 bit and 32 bit * programming environments. Some external data structures (such as the TEB * and attributes objects) cannot vary between interfaces, and are defined to * contain 64 bit values regardless of programming environment. Only one * 1003.1c routine varies between the interfaces: pthread_join, which writes a * "void *" to a caller-provided address. For pthread_join32 only the low 32 * bits of the thread return value is written. For pthread_join64 all 64 bits * are written (this will corrupt caller data if the allocated "void *" is 32 * bits wide). The default definition of "pthread_join" depends upon the * programming environment specified by compiler switches -- in other words, * the value of the _INITIAL_POINTER_SIZE macro. * * The following typedefs allow fields with required sizes to be declared * without needing a lot of #pragma __required_pointer_size statements * scattered through the header. On OpenVMS VAX and Tru64 UNIX these types * always correspond unambiguously to a single type. On OpenVMS Alpha the * types select the appropriate size to maintain datastructure layout * regardless of the default pointer size. * * Per the convention the 64-bit task force has established, a compilation on * OpenVMS Alpha that occurs without any /pointer_size switch should yield * only a 32-bit interface. But, if compilation on OpenVMS Alpha occurs with * an explicit /pointer_size switch, then (a) all prototypes should accept * long [64] bit pointers as arguments and (b) all functions which return * pointer values should return [32] bit pointers unless the function is a * variant with _64 in the name. * * The DECthreads team has no intention of supporting short pointer * compilation environments (cc -xtaso) on Tru64 UNIX. * * NOTE: _PTHREAD_ALLOW_MIXED_PROTOS_ should be defined only for the * OpenVMS Alpha platform. */ #ifdef _PTHREAD_ALLOW_MIXED_PROTOS_ # ifdef __INITIAL_POINTER_SIZE /* * This is a DECC compiler with 64-bit pointer support. */ # ifdef _PTHREAD_CORE_BUILD_ # define _PTHREAD_MIXED_PROTOS_ # else # if __INITIAL_POINTER_SIZE > 0 /* * The compilation has an explicit /pointer_size. */ # define _PTHREAD_MIXED_PROTOS_ # endif # endif # else /* * This is some compiler on AXP/VMS that does not have 64-bit pointer * support. */ # ifdef _PTHREAD_CORE_BUILD_ # error OpenVMS Alpha compiler without 64-bit pointer support # endif # endif #endif #ifdef _PTHREAD_ALLOW_MIXED_PROTOS_ /* * On OpenVMS Alpha, some of the fields in DECthreads structures (TEB, * pthread_mutex_t, pthread_cond_t) need to be 64-bit pointers regardless of * the default pointer size in use by the compiler. They need to be 64 bit * fields even on older versions of DEC C (prior to V5.0) which don't support * 64 bit pointers at all. * * If the compiler supports long pointers, we use the __required_pointer_size * pragma to force the proper interpretation of these pointers. On older * compilers, we use uint64 instead. */ typedef __int64 __pthreadLongInt_t; typedef unsigned __int64 __pthreadLongUint_t; # ifdef __INITIAL_POINTER_SIZE # pragma __required_pointer_size __save # pragma __required_pointer_size __long typedef void *__pthreadLongAddr_t; typedef const void *__pthreadLongConstAddr_t; typedef char *__pthreadLongString_t; typedef const char *__pthreadLongConstString_t; typedef __pthreadLongAddr_t *__pthreadLongAddr_p; # pragma __required_pointer_size __short typedef void *__pthreadShortAddr_t; typedef const void *__pthreadShortConstAddr_t; typedef char *__pthreadShortString_t; typedef const char *__pthreadShortConstString_t; typedef __pthreadLongAddr_t *__pthreadShortAddr_p; # pragma __required_pointer_size __restore # else /* OpenVMS Alpha with no long pointer support */ typedef unsigned __int64 __pthreadLongAddr_t; typedef unsigned __int64 __pthreadLongConstAddr_t; typedef unsigned __int64 __pthreadLongString_t; typedef unsigned __int64 __pthreadLongConstString_t; typedef unsigned __int64 __pthreadLongAddr_p; typedef const void *__pthreadShortConstAddr_t; typedef void *__pthreadShortAddr_t; typedef char *__pthreadShortString_t; typedef const char *__pthreadShortConstString_t; typedef __pthreadLongAddr_t *__pthreadShortAddr_p; # endif /* Long pointer support */ #else /* No mixed pointers */ typedef long __pthreadLongInt_t; typedef unsigned long __pthreadLongUint_t; typedef void *__pthreadLongAddr_t; typedef const void *__pthreadLongConstAddr_t; typedef char *__pthreadLongString_t; typedef const char *__pthreadLongConstString_t; typedef __pthreadLongAddr_t *__pthreadLongAddr_p; typedef void *__pthreadShortAddr_t; typedef char *__pthreadShortString_t; typedef const char *__pthreadShortConstString_t; typedef __pthreadLongAddr_t *__pthreadShortAddr_p; #endif typedef __pthreadLongAddr_p __pthreadTsd_t; #ifndef PTHREAD_KEYS_MAX # define PTHREAD_KEYS_MAX 255 #endif #ifndef _PTHREAD_ENV_UNIX # ifndef PTHREAD_DESTRUCTOR_ITERATIONS # define PTHREAD_DESTRUCTOR_ITERATIONS 4 # endif #endif #ifndef PTHREAD_STACK_MIN # ifdef _PTHREAD_ENV_VAX # define PTHREAD_STACK_MIN 4608 # else # define PTHREAD_STACK_MIN 8192 # endif #endif #define PTHREAD_CANCEL_DISABLE 0 #define PTHREAD_CANCEL_ENABLE 1 #define PTHREAD_CANCEL_DEFERRED 0 #define PTHREAD_CANCEL_ASYNCHRONOUS 1 #define PTHREAD_CANCELED (void *)-1 #define PTHREAD_SCOPE_PROCESS 0 #define PTHREAD_SCOPE_SYSTEM 1 #define PTHREAD_MUTEX_NORMAL 0 #define PTHREAD_MUTEX_RECURSIVE 1 #define PTHREAD_MUTEX_ERRORCHECK 2 #define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL #define PTHREAD_PROCESS_PRIVATE 0 #define PTHREAD_PROCESS_SHARED 1 #define PTHREAD_PRIO_NONE 0 #define PTHREAD_PRIO_PROTECT 1 #define PTHREAD_PRIO_INHERIT 2 /* * The following are internal, private flags used by the thread library * implementation. Any application or library code depending on the value or * meaning of these flags (except in the initialization of static objects * using the precise bit patterns constructed by the PTHREAD_*_INITIALIZER * family of macros) is unsupported and may break on future releases * (including patches). * * I.e., your code may not dynamically write these bits, nor can your code * read or interpret these bits from a thread synchronization object that may * have been used. (For example, the thread library may choose to replace the * initial bit patterns completely on the first use of a mutex.) */ #define _PTHREAD_MSTATE_CONFIG 0x00200000 /* Configure mutex */ #define _PTHREAD_MSTATE_TYPE 0x0f000000 /* Mutex type */ #define _PTHREAD_MTYPE_NORMAL 0x00000000 /* Normal (fast or metered) */ #define _PTHREAD_MTYPE_RECURS 0x01000000 /* Recursive */ #define _PTHREAD_MTYPE_ERRCHK 0x02000000 /* Detect usage errors */ #define _PTHREAD_CSTATE_SLOW 0x00200000 /* Slow signal/broadcast */ #define _PTHREAD_CVALID (0x06facbd1L) /* Condition variable */ #define _PTHREAD_MVALID (0x05bcafe1L) /* Mutex */ #define _PTHREAD_PVALID (0xdeadbeefL) /* Paddock */ #define _PTHREAD_RWVALID (0x02bacab1L) /* Read/Write lock */ #define _PTHREAD_CAVALID (0xaceface1L) /* Condition attributes */ #define _PTHREAD_MAVALID (0xecafeca1L) /* Mutex attributes */ #define _PTHREAD_TAVALID (0xbeefeed1L) /* Thread attributes */ #define _PTHREAD_RWVF_STA 0x08000000L #define _PTHREAD_RWVF_INT 0x10000000L #define _PTHREAD_RWVF_PRE 0x20000000L #define _PTHREAD_RWVF_INL 0x40000000L #define _PTHREAD_RWVF_NAM 0x80000000L #define _PTHREAD_MVF_STA 0x08000000L #define _PTHREAD_MVF_INT 0x10000000L #define _PTHREAD_MVF_PRE 0x20000000L #define _PTHREAD_MVF_INL 0x40000000L #define _PTHREAD_MVF_NAM 0x80000000L #define _PTHREAD_CVF_STA 0x08000000L #ifndef _PTHREAD_NOMETER_STATIC # define PTHREAD_MUTEX_INITIALIZER \ {_PTHREAD_MSTATE_CONFIG, _PTHREAD_MVALID | _PTHREAD_MVF_STA} # define PTHREAD_COND_INITIALIZER \ {_PTHREAD_CSTATE_SLOW, _PTHREAD_CVALID | _PTHREAD_CVF_STA} # define PTHREAD_MUTEX_INITWITHNAME_NP(_n_,_a_) \ {_PTHREAD_MSTATE_CONFIG, _PTHREAD_MVALID | _PTHREAD_MVF_STA, _n_, _a_} # define PTHREAD_COND_INITWITHNAME_NP(_n_,_a_) \ {_PTHREAD_CSTATE_SLOW, _PTHREAD_CVALID | _PTHREAD_CVF_STA, _n_, _a_} #else # define PTHREAD_MUTEX_INITIALIZER {0, _PTHREAD_MVALID | _PTHREAD_MVF_STA} # define PTHREAD_COND_INITIALIZER {0, _PTHREAD_CVALID | _PTHREAD_CVF_STA} # define PTHREAD_MUTEX_INITWITHNAME_NP(_n_,_a_) \ {0, _PTHREAD_MVALID | _PTHREAD_MVF_STA, _n_, _a_} # define PTHREAD_COND_INITWITHNAME_NP(_n_,_a_) \ {0, _PTHREAD_CVALID | _PTHREAD_CVF_STA, _n_, _a_} #endif #define PTHREAD_RWLOCK_INITIALIZER {_PTHREAD_RWVALID | _PTHREAD_RWVF_STA} #define PTHREAD_RWLOCK_INITWITHNAME_NP(_n_,_a_) \ {_PTHREAD_RWVALID | _PTHREAD_RWVF_STA, _n_, _a_} #define PTHREAD_MUTEX_INITFAST_NP {0, _PTHREAD_MVALID | _PTHREAD_MVF_STA} #define PTHREAD_MUTEX_INITFASTWITHNAME_NP(_n_,_a_) \ {0, _PTHREAD_MVALID | _PTHREAD_MVF_STA, _n_, _a_} #define PTHREAD_MUTEX_INITRECURSIVE_NP \ {_PTHREAD_MTYPE_RECURS | _PTHREAD_MSTATE_CONFIG, \ _PTHREAD_MVALID | _PTHREAD_MVF_STA} #define PTHREAD_MUTEX_INITRECURSIVEWITHNAME_NP(_n_,_a_) \ {_PTHREAD_MTYPE_RECURS | _PTHREAD_MSTATE_CONFIG, \ _PTHREAD_MVALID | _PTHREAD_MVF_STA, _n_, _a_} #define PTHREAD_MUTEX_INITERRCHK_NP \ {_PTHREAD_MTYPE_ERRCHK | _PTHREAD_MSTATE_CONFIG, \ _PTHREAD_MVALID | _PTHREAD_MVF_STA} #define PTHREAD_MUTEX_INITERRCHKWITHNAME_NP(_n_,_a_) \ {_PTHREAD_MTYPE_ERRCHK | _PTHREAD_MSTATE_CONFIG, \ _PTHREAD_MVALID | _PTHREAD_MVF_STA, _n_, _a_} /* * OBSOLETE: * * These macros are special variants of the PTHREAD_MUTEX_INITIALIZER macros. * * They represent an early attempt to support applications that needed to * preempt the C runtime malloc/free package of functions, and avoid problems * when the thread library needed to allocate or free memory. * * The extended documentation of the use of these macros has been removed, and * these functions will be retired in a future release. * * On Tru64 UNIX, use the tis_allocator_mutex_init() function, instead. * * On OpenVMS, use LIB$VM_MALLOC/LIB$VM_FREE for raw allocation and free. * These don't use mutexes for thread-safety, and they're fully reentrant. No * special support is required. */ #define _PTHREAD_MUTEX_INITPRE \ {_PTHREAD_MSTATE_CONFIG, _PTHREAD_MVALID|_PTHREAD_MVF_STA|_PTHREAD_MVF_PRE} #define _PTHREAD_MUTEX_INITPREWITHNAME(_n_,_a_) \ {_PTHREAD_MSTATE_CONFIG, \ _PTHREAD_MVALID|_PTHREAD_MVF_STA|_PTHREAD_MVF_PRE, \ _n_, _a_} #define _PTHREAD_MUTEX_INITPRERECUR \ {_PTHREAD_MTYPE_RECURS | _PTHREAD_MSTATE_CONFIG, \ _PTHREAD_MVALID | _PTHREAD_MVF_STA | _PTHREAD_MVF_PRE} #define _PTHREAD_MUTEX_INITPRERECURWITHNAME(_n_,_a_) \ {_PTHREAD_MTYPE_RECURS | _PTHREAD_MSTATE_CONFIG, \ _PTHREAD_MVALID | _PTHREAD_MVF_STA | _PTHREAD_MVF_PRE, _n_, _a_} #define _PTHREAD_MUTEX_INITPREERRCHK \ {_PTHREAD_MTYPE_ERRCHK | _PTHREAD_MSTATE_CONFIG, \ _PTHREAD_MVALID | _PTHREAD_MVF_STA | _PTHREAD_MVF_PRE} #define _PTHREAD_MUTEX_INITPREERRCHKWITHNAME(_n_,_a_) \ {_PTHREAD_MTYPE_ERRCHK | _PTHREAD_MSTATE_CONFIG, \ _PTHREAD_MVALID | _PTHREAD_MVF_STA | _PTHREAD_MVF_PRE, _n_, _a_} /* * NOTE: "Constructor keys" are currently supported only for limited use by * the dynamic loader to implement the C language "__declspec(__thread)" * allocation class. Use for any other purpose at all is completely * unsupported. (This may be changed in a future release.) */ /* * "Constructor keys" (keys created using pthread_key_create_new_np) must * be statically initialized using this macro prior to creation, e.g., * * pthread_key_t key = PTHREAD_KEY_INITIALIZER_NP; */ #define PTHREAD_KEY_INITIALIZER_NP 0 /* * Flags for pthread_key_construct_np */ #define PTHREAD_KEY_ALLTHREAD_NP 0x1 /* Constr/Destr in all threads */ #ifndef _PTHREAD_ENV_UNIX /* * All references to "individual attributes" fields within these attributes * object structures MUST be made through the defined function calls in this * header file. Not all fields in these structures mean what you might infer * from the field type. Not all of the fields are implemented at this time. * The name and order of fields may change without notice, although the size * of the structure will never change. */ typedef struct __pthread_attr_t { __pthreadLongUint_t _Pfield(valid); __pthreadLongString_t _Pfield(name); __pthreadLongUint_t _Pfield(arg); __pthreadLongUint_t _Pfield(reserved)[19]; } pthread_attr_t; #endif #ifndef _PTHREAD_ENV_UNIX /* * All references to "individual attributes" fields within these attributes * object structures MUST be made through the defined function calls in this * header file. Not all fields in these structures mean what you might infer * from the field type. Not all of the fields are implemented at this time. * The name and order of fields may change without notice, although the size * of the structure will never change. */ typedef struct __pthread_mutexattr_t { __pthreadLongUint_t _Pfield(valid); __pthreadLongUint_t _Pfield(reserved)[15]; } pthread_mutexattr_t; #endif #ifndef _PTHREAD_ENV_UNIX /* * All references to "individual attributes" fields within these attributes * object structures MUST be made through the defined function calls in this * header file. Not all fields in these structures mean what you might infer * from the field type. Not all of the fields are implemented at this time. * The name and order of fields may change without notice, although the size * of the structure will never change. */ typedef struct __pthread_condattr_t { __pthreadLongUint_t _Pfield(valid); __pthreadLongUint_t _Pfield(reserved)[13]; } pthread_condattr_t; #endif #ifndef _PTHREAD_ENV_UNIX /* * All references to "individual attributes" fields within these attributes * object structures MUST be made through the defined function calls in this * header file. Not all fields in these structures mean what you might infer * from the field type. Not all of the fields are implemented at this time. * The name and order of fields may change without notice, although the size * of the structure will never change. */ typedef struct __pthread_rwlockattr_t { __pthreadLongUint_t _Pfield(valid); /* Validation flag */ __pthreadLongUint_t _Pfield(reserved)[15]; } pthread_rwlockattr_t; #endif /* * All references to "individual attributes" fields within these attributes * object structures MUST be made through the defined function calls in this * header file. Not all fields in these structures mean what you might infer * from the field type. Not all of the fields are implemented at this time. * The name and order of fields may change without notice, although the size * of the structure will never change. */ typedef struct __pthread_paddockattr_t { __pthreadLongUint_t _Pfield(valid); /* Validation flag */ __pthreadLongUint_t _Pfield(reserved)[15]; } pthread_paddockattr_t; /* * All references to "individual paddock" fields within these object structures * MUST be made through the defined function calls in this header file. Not all * fields in these structures mean what you might infer from the field type. Not * all of the fields are implemented at this time. The name and order of fields * may change without notice, although the size of the structure will never * change. */ typedef struct __pthread_paddock_t { __pthreadLongUint_t _Pfield(valid); __pthreadLongString_t _Pfield(name); __pthreadLongUint_t _Pfield(arg); __pthreadLongUint_t _Pfield(reserved)[19]; } pthread_paddock_t; #ifndef _PTHREAD_ENV_UNIX /* * DECthreads maintains a substantial amount of internal information about * each thread in a "Thread Control Block" that is not directly accessible to * the programmer. However, some of this information is required by * application, library, or debug/profile code in performance critical code * paths. Thus, DECthreads provides an architected "Thread Environment Block" * that makes a subset of the TCB information available directly. On Alpha * hardware systems the address of the TEB is available by using the CALL_PAL * RDUNIQ instruction. DECthreads also provides both a macro and a callable * function to return the TEB address, for convenience and portability. */ # if defined (_PTHREAD_ALLOW_MIXED_PROTOS_) && defined (__INITIAL_POINTER_SIZE) # pragma __required_pointer_size __save # pragma __required_pointer_size __long # endif # if defined(_OSF_SOURCE) || !defined(_PTHREAD_ENV_UNIX) /* * Define the TEB's version. * * Version 0: Tru64 UNIX 4.0 and OpenVMS 7.0 * Version 1: Tru64 UNIX 4.0D and OpenVMS 7.2 */ # define PTHREAD_TEB_VERSION 1 /* Current version */ # define PTHREAD_TEB_SIZE \ ((size_t)((char *)&((pthread_t)0L)->_Pfield(thd_errno) \ - (char *)0L)) + sizeof (int) # define PTHREAD_TEB_EFLG_USER 0x01 /* User thread */ # define PTHREAD_TEB_EFLG_INITIAL 0x02 /* Process initial thread */ # define PTHREAD_TEB_CREATOR_PTHREAD 1 /* Created by 1003.1c API */ # define PTHREAD_TEB_CREATOR_CMA 2 /* Created by CMA API */ # define PTHREAD_TEB_CREATOR_D4 3 /* Created by Draft 4 API */ # define PTHREAD_TEB_CREATOR_D4EXC 4 /* Created by D4-Exception API */ # endif /* * Thread Environment Block (TEB). (On UNIX, this definition is duplicated in * the header file.) * * NOTE: Modification of any field in a thread's TEB structure will result in * undefined behavior. Fields that are commented as "RESERVED" are * undocumented and unsupported, and the contents or meaning may change at any * time. The "per_kt_area" field is reserved entirely for use by DECthreads * and the operating system kernel: it contains undefined, undocumented, * unsupported, and volatile data of unspecified type. * * Each public field is documented with a comment that begins with the TEB * version in which the field was created or documented. If the TEB "version" * has a value lower than version in which the field became accessible, do not * depend upon the value of that field. */ typedef struct __pthreadTeb_t { __pthreadLongAddr_p _Pfield(reserved1); /* Reserved to DECthreads */ __pthreadLongAddr_p _Pfield(reserved2); /* Reserved to DECthreads */ unsigned short _Pfield(size); /* V1: Size of TEB */ unsigned char _Pfield(version); /* TEB version */ unsigned char _Pfield(reserved3); /* Reserved to DECthreads */ unsigned char _Pfield(external); /* V1: PTHREAD_TEB_EFLG_ flgs */ unsigned char _Pfield(reserved4)[2]; /* RESERVED */ unsigned char _Pfield(creator); /* V1: PTHREAD_TEB_CREATOR_* */ __pthreadLongUint_t _Pfield(sequence); /* V0: Thread sequence */ __pthreadLongUint_t _Pfield(reserved5)[2]; /* Reserved to DECthreads */ __pthreadLongAddr_t _Pfield(per_kt_area); /* V0: Reserved */ __pthreadLongAddr_t _Pfield(stack_base); /* V0: Initial SP */ __pthreadLongAddr_t _Pfield(stack_reserve); /* V0: reserved stack */ __pthreadLongAddr_t _Pfield(stack_yellow); /* V0: yellow zone */ __pthreadLongAddr_t _Pfield(stack_guard); /* V0: guard (red) zone */ __pthreadLongUint_t _Pfield(stack_size); /* V0: total stack size */ __pthreadTsd_t _Pfield(tsd_values); /* V0: TSD array (void *) */ unsigned long _Pfield(tsd_count); /* V0: TSD array size */ unsigned int _Pfield(reserved6); /* Reserved to DECthreads */ unsigned int _Pfield(reserved7); /* Reserved to DECthreads */ unsigned int _Pfield(thread_flags); /* Reserved to DECthreads */ int _Pfield(thd_errno); /* V1: thread's errno */ __pthreadLongAddr_t _Pfield(stack_hiwater); /* V1: lowest known SP */ } pthreadTeb_t, *pthreadTeb_p; # if defined (_PTHREAD_ALLOW_MIXED_PROTOS_) && defined (__INITIAL_POINTER_SIZE) typedef pthreadTeb_p pthread_t; /* Long pointer if possible */ # pragma __required_pointer_size __restore # elif defined (_PTHREAD_ENV_ALPHA) && defined (_PTHREAD_ENV_VMS) typedef unsigned __int64 pthread_t; /* Force 64 bits anyway */ # else typedef pthreadTeb_p pthread_t; /* Pointers is pointers */ # endif #endif #ifndef _PTHREAD_ENV_UNIX typedef unsigned int pthread_key_t; #endif typedef void* __pthreadStartFunc_t (void *); typedef void __pthreadDestructorFunc_t (void*); typedef void* __pthreadConstructorFunc_t (pthread_key_t, pthread_t); typedef void __pthreadExtDestructorFunc_t (void*, pthread_t, pthread_key_t); typedef void __pthreadOnceFunc_t (void); typedef __pthreadStartFunc_t* __pthreadStart_t; typedef __pthreadDestructorFunc_t* __pthreadDestructor_t; typedef __pthreadConstructorFunc_t* __pthreadConstructor_t; typedef __pthreadExtDestructorFunc_t* __pthreadExtDestructor_t; typedef __pthreadOnceFunc_t* __pthreadOnce_t; /* * Macros to utilize the TEB directly for maximum efficiency. With hardware * and a compiler that supports it, this header uses inline instructions to * get access to the thread's TEB... otherwise this will result in a simple * call into DECthreads. * * It is perfectly reasonable for code to freely access any defined TEB field * on any DECthreads platform, as long as you meet all of the following rules * (read this section carefully!) * * You must not depend in any way upon the content or meaning of any * "reserved" fields (reserved1, reserved2, reserved3, etc.). These are for * DECthreads internal use only and are subject to change without notice. * * You may not write directly to any field of the TEB. Any modification may * result in undefined and possibly severe errors that may show up only much * later in the program. * * Don't make any assumptions about the nature of the sequence number returned * by pthread_getsequence_np or pthread_getselfseq_np, except that it is a * unique integer among all threads created within the current image. * Consecutively created threads may not necessarily have consecutive sequence * numbers, nor are all possible sequence numbers necessarily assigned by * DECthreads. A thread created "later" does not necessarily have a sequence * number higher than that of a thread created "earlier". * * A thread may read or write thread-specific data values directly to its own * tsd_values array. Writing a value to any array element of tsd_values that * does not correspond to the value of a thread-specific data key "owned" by * the calling subsystem (returned by a call to pthread_key_create or * pthread_key_create_new) is erroneous. If you choose to code inline access * to the TSD array, do so very cautiously! Write to another thread's * tsd_values array only if your code provides sufficient synchronization to * ensure that this is "safe" -- in general, this is not a good idea. * * Only DECthreads and the O/S may use the value of the "per_kt_area" pointer; * for other code this is unpredictable and undefined. */ #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_self __pthread_self # endif #endif extern pthread_t pthread_self (void); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif #if defined _PTHREAD_USE_ASM_ # ifdef pthread_self # undef pthread_self # endif # ifdef _PTHREAD_ENV_ALPHA # define pthread_self() ((pthread_t)asm ("call_pal 0x9e")) # endif #endif #ifdef _PTHREAD_ENV_UNIX # define pthread_unchecked_getspecific_np(_key_) \ (pthread_self ()->_Pfield(tsd_values)[_key_]) # define pthread_unchecked_setspecific_np(_key_,_value_) \ (pthread_self ()->_Pfield(tsd_values)[_key_] = (_value_)) #else # define pthreadTeb() ((pthreadTeb_p)pthread_self ()) # define pthread_unchecked_getspecific_np(_key_) \ (pthreadTeb ()->_Pfield(tsd_values)[_key_]) # define pthread_unchecked_setspecific_np(_key_,_value_) \ (pthreadTeb ()->_Pfield(tsd_values)[_key_] = (_value_)) #endif #ifndef _PTHREAD_ENV_UNIX /* * This is the primary structure controlling the identity and state of a * mutex. The "lock" field contains the primary mutex lock bit, a flag * indicating whether lock/unlock protocols are "fast" or "slow", the full * type of the mutex, and an internal reference count. The reference count * assures atomicity of unlock/wake sequences with respect to deletion. * * The "sequence" field gives each mutex a unique identifier, which is * primarily used for debugging. A new static mutex has a sequence number of * zero; DECthreads assigns a real sequence number when a thread first blocks * on the mutex. (A mutex created by calling pthread_mutex_init has a sequence * number assigned at creation.) * * Beware that the name and order of these fields are undocumented and * unsupported. Directly accessing any in your program may result in serious * difficulties in future releases of the operating system. */ typedef struct __pthread_mutex_t { unsigned int _Pfield(lock); /* LOCK, CONFIG, TYPE, REFCNT */ unsigned int _Pfield(valid); /* Validation info */ __pthreadLongString_t _Pfield(name); /* Name of mutex */ unsigned int _Pfield(arg); /* printf argument for name */ unsigned int _Pfield(depth); /* Recursive lock depth */ unsigned long _Pfield(sequence); /* Mutex sequence number */ unsigned long _Pfield(owner); /* Current owner (if known) */ __pthreadLongAddr_p _Pfield(block); /* Pointer to blocking struct */ } pthread_mutex_t; #endif #ifndef _PTHREAD_ENV_UNIX /* * Similar to pthread_mutex_t, but for a condition variable. */ typedef struct __pthread_cond_t { unsigned int _Pfield(state); /* EVENT, SLOW, REFCNT, etc. */ unsigned int _Pfield(valid); /* Validation info */ __pthreadLongString_t _Pfield(name); /* Name of condition variable */ unsigned int _Pfield(arg); /* printf argument for name */ unsigned long _Pfield(sequence); /* Condition variable seq # */ __pthreadLongAddr_p _Pfield(block); /* Pointer to blocking struct */ } pthread_cond_t; #endif /* * Ensure that an initialization routine is called exactly once. */ #define PTHREAD_ONCE_UNINIT 0 #define PTHREAD_ONCE_INITING 1 #define PTHREAD_ONCE_INITED 2 #define PTHREAD_ONCE_INIT {PTHREAD_ONCE_UNINIT} #ifndef _PTHREAD_ENV_UNIX typedef volatile struct __pthread_once_t { long _Pfield(state); long _Pfield(reserved)[10]; } pthread_once_t; #endif #ifndef _PTHREAD_ENV_UNIX /* * Readers-Writers Locks */ typedef struct __pthread_rwlock_t { unsigned int _Pfield(valid); /* Validation flag */ unsigned int _Pfield(flags); /* Internal flags */ __pthreadLongString_t _Pfield(name); /* Name of rwlock */ unsigned int _Pfield(arg); /* printf argument for name */ unsigned int _Pfield(readers); /* Number of readers */ unsigned int _Pfield(rwaits); /* Waiting readers */ unsigned int _Pfield(wwaits); /* Waiting writers */ __pthreadLongUint_t _Pfield(sequence); /* rwlock variable seq # */ unsigned long _Pfield(wrid); /* Current write owner */ __pthreadLongAddr_p _Pfield(block); /* Pointer to blocking struct */ __pthreadLongUint_t _Pfield(reserved1); /* Reserved to DECthreads */ } pthread_rwlock_t; #endif #define PTHREAD_INHERIT_SCHED 0 #define PTHREAD_EXPLICIT_SCHED 1 #define PTHREAD_CREATE_JOINABLE 0 #define PTHREAD_CREATE_DETACHED 1 #ifndef _PTHREAD_ENV_UNIX # define SCHED_FIFO 1 /* Tru64 UNIX sched.h defines */ # define SCHED_RR 2 /* these constants already */ # define SCHED_OTHER 3 # define SCHED_FG_NP SCHED_OTHER /* "Foreground" (Timeshare) */ # define SCHED_BG_NP (SCHED_OTHER+1) /* "Background" */ # define SCHED_LFI_NP (SCHED_OTHER+2) /* "Low FIFO" (background FIFO) */ # define SCHED_LRR_NP (SCHED_OTHER+3) /* "Low RR" (background RR) */ #endif #if (defined _PTHREAD_ENV_UNIX) && (defined _OSF_SOURCE) # define PRI_FIFO_MIN 14 # define PRI_FIFO_MAX SCHED_PRIO_RT_MAX # define PRI_RR_MIN 14 # define PRI_RR_MAX SCHED_PRIO_RT_MAX # define PRI_OTHER_MIN 14 # define PRI_OTHER_MAX SCHED_PRIO_RT_MAX # define PRI_FG_MIN_NP 14 # define PRI_FG_MAX_NP 63 # define PRI_BG_MIN_NP 0 # define PRI_BG_MAX_NP 13 # define PRI_LFI_MIN_NP 0 # define PRI_LFI_MAX_NP 13 # define PRI_LRR_MIN_NP 0 # define PRI_LRR_MAX_NP 13 #elif defined (_PTHREAD_ENV_VMS) # define PRI_FIFO_MIN 16 # define PRI_FIFO_MAX 31 # define PRI_RR_MIN 16 # define PRI_RR_MAX 31 # define PRI_OTHER_MIN PRI_FG_MIN_NP # define PRI_OTHER_MAX PRI_FG_MAX_NP # define PRI_FG_MIN_NP 8 # define PRI_FG_MAX_NP 15 # define PRI_BG_MIN_NP 0 # define PRI_BG_MAX_NP 7 # define PRI_LFI_MIN_NP 0 # define PRI_LFI_MAX_NP 7 # define PRI_LRR_MIN_NP 0 # define PRI_LRR_MAX_NP 7 # define sched_get_priority_max (_pol_) \ (_pol_ == SCHED_OTHER ? PRI_FG_MAX_NP : PRI_FIFO_MAX) # define sched_get_priority_min (_pol_) \ (_pol_ == SCHED_OTHER ? PRI_FG_MIN_NP : PRI_FIFO_MIN) #endif #ifdef _PTHREAD_ENV_UNIX # if !defined (_XOPEN_SOURCE) || (_XOPEN_SOURCE+0 < 400) extern int pthread_sigmask (int, const sigset_t*, sigset_t*); extern int pthread_kill (pthread_t, int); # endif #endif /* * DECthreads provides three distinct types of mutex. The default (normal or * "fast" mutex), which can lock and unlock with completely inline code on * Alpha processors, but does no consistency checking; the "recursive" mutex * which allows a given thread to lock a mutex it already owns without * deadlock (it remains locked until all nested locks are released); and the * "errorcheck" mutex, which behaves much like a normal mutex but checks for * self deadlock and for releasing a mutex that is either unowned or is owned * by another thread. The recursive and errorcheck mutexes require a call * into the DECthreads library for every lock and unlock. * * When synchronization metering is enabled, all mutex types monitor every * lock and unlock. A mutex statically initialized using * PTHREAD_MUTEX_INITIALIZER is "normal", but is set up so that the first use * of the mutex will result in a call into DECthreads (as if the mutex was * already locked). If synchronization metering is not enabled, DECthreads * will disable this extra state so that future references (in the absence of * normal mutex contention) will not cause unnecessary calls. Should you wish * to avoid this initial call, you can compile with _PTHREAD_NOMETER_STATIC; * normal mutexes statically initialized using this option are not metered. */ extern int pthread_mutexattr_init (pthread_mutexattr_t*); #ifdef _PTHREAD_ENV_UNIX extern int pthread_mutexattr_getprioceiling (const pthread_mutexattr_t*, int*); extern int pthread_mutexattr_setprioceiling (pthread_mutexattr_t*, int); #else # define pthread_mutexattr_getprioceiling pthread_mutexattr_getpriceiling extern int pthread_mutexattr_getpriceiling (const pthread_mutexattr_t*, int*); # define pthread_mutexattr_setprioceiling pthread_mutexattr_setpriceiling extern int pthread_mutexattr_setpriceiling (pthread_mutexattr_t*, int); #endif extern int pthread_mutexattr_getprotocol (const pthread_mutexattr_t*, int*); extern int pthread_mutexattr_setprotocol (pthread_mutexattr_t*, int); extern int pthread_mutexattr_getpshared (const pthread_mutexattr_t*, int*); extern int pthread_mutexattr_setpshared (pthread_mutexattr_t*, int); extern int pthread_mutexattr_gettype (const pthread_mutexattr_t*, int*); extern int pthread_mutexattr_settype (pthread_mutexattr_t*, int); extern int pthread_mutexattr_destroy (pthread_mutexattr_t*); #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_mutex_init __pthread_mutex_init # endif #endif extern int pthread_mutex_init (pthread_mutex_t*, const pthread_mutexattr_t*); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_mutex_destroy __pthread_mutex_destroy # endif #endif extern int pthread_mutex_destroy (pthread_mutex_t*); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_mutex_lock __pthread_mutex_lock # endif #endif extern int pthread_mutex_lock (pthread_mutex_t*); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif extern int pthread_mutex_getprioceiling (const pthread_mutex_t*, int*); extern int pthread_mutex_setprioceiling (pthread_mutex_t*, int, int*); #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_mutex_trylock __pthread_mutex_trylock # endif #endif extern int pthread_mutex_trylock (pthread_mutex_t*); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_mutex_unlock __pthread_mutex_unlock # endif #endif extern int pthread_mutex_unlock (pthread_mutex_t*); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif extern int pthread_condattr_init (pthread_condattr_t*); extern int pthread_condattr_destroy (pthread_condattr_t*); extern int pthread_condattr_setpshared (pthread_condattr_t*, int); extern int pthread_condattr_getpshared (const pthread_condattr_t*, int*); #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_cond_init __pthread_cond_init # endif #endif extern int pthread_cond_init ( pthread_cond_t*, const pthread_condattr_t*); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_cond_destroy __pthread_cond_destroy # endif #endif extern int pthread_cond_destroy (pthread_cond_t*); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_cond_signal __pthread_cond_signal # endif #endif extern int pthread_cond_signal (pthread_cond_t*); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_cond_broadcast __pthread_cond_broadcast # endif #endif extern int pthread_cond_broadcast (pthread_cond_t*); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_cond_wait __pthread_cond_wait # endif #endif extern int pthread_cond_wait (pthread_cond_t*, pthread_mutex_t*); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_cond_timedwait __pthread_cond_timedwait # endif #endif extern int pthread_cond_timedwait ( pthread_cond_t*, pthread_mutex_t*, const struct timespec*); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif extern int pthread_rwlockattr_init (pthread_rwlockattr_t*); extern int pthread_rwlockattr_destroy (pthread_rwlockattr_t*); extern int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t*, int*); extern int pthread_rwlockattr_setpshared (pthread_rwlockattr_t*, int); extern int pthread_rwlock_init (pthread_rwlock_t*, const pthread_rwlockattr_t*); extern int pthread_rwlock_destroy (pthread_rwlock_t*); extern int pthread_rwlock_rdlock (pthread_rwlock_t*); extern int pthread_rwlock_tryrdlock (pthread_rwlock_t*); extern int pthread_rwlock_wrlock (pthread_rwlock_t*); extern int pthread_rwlock_trywrlock (pthread_rwlock_t*); extern int pthread_rwlock_unlock (pthread_rwlock_t*); /* * Routines to get/set the contention scope for a thread that will be created * using the attributes object. */ extern int pthread_attr_getscope (const pthread_attr_t*, int*); extern int pthread_attr_setscope (pthread_attr_t*, int); /* * Routines to get/set the stack address for a thread that will be created * using the attributes object. Note that "stackaddr" must be the correct * initial stack BASE for the thread, which is highly machine-dependent. * (E.g., does the machine increment or decrement the stack, and does it do so * before or after storing a new value?) Use of these functions is inherently * NON-PORTABLE, and they should be used only with great caution. * Additionally, they do not provide any way for the implementation to know * the size of the stack, so it can neither prevent nor detect stack overflows * or the corruption that may be caused by this application error. (See the * DECthreads extension pthread_attr_setstackaddr_np.) */ extern int pthread_attr_setstackaddr (pthread_attr_t*, void*); extern int pthread_attr_getstackaddr (const pthread_attr_t*, void**); /* * Extended versions of set/get stackaddr routines that allow the caller to * specify the stack using a low address and size. The implementation will * compute the proper "stack base" using this information. E.g. you might mmap * space, add the size to the returned pointer, and then pass the result to * pthread_attr_setstackaddr on a machine with a pre-decremented stack * pointer; but on a machine with a post-incremented stack you would pass the * pointer returned by mmap. Using pthread_attr_setstackaddr_np instead, you * always pass the pointer returned by mmap and the requested size. */ extern int pthread_attr_setstackaddr_np (pthread_attr_t*, void*, size_t); extern int pthread_attr_getstackaddr_np ( const pthread_attr_t*, void**, size_t*); #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_attr_setinheritsched __pthread_attr_setinheritsched # endif #endif extern int pthread_attr_setinheritsched (pthread_attr_t*, int); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_attr_getinheritsched __pthread_attr_getinheritsched # endif #endif extern int pthread_attr_getinheritsched (const pthread_attr_t*, int*); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif extern int pthread_attr_setschedpolicy (pthread_attr_t*, int); extern int pthread_attr_getschedpolicy (const pthread_attr_t*, int*); extern int pthread_attr_setschedparam ( pthread_attr_t*, const struct sched_param*); extern int pthread_attr_getschedparam ( const pthread_attr_t*, struct sched_param*); extern int pthread_getschedparam (pthread_t, int*, struct sched_param*); extern int pthread_setschedparam (pthread_t, int, const struct sched_param*); extern int pthread_getconcurrency (void); extern int pthread_setconcurrency (int); extern int pthread_attr_init (pthread_attr_t*); extern int pthread_attr_destroy (pthread_attr_t*); #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_attr_setstacksize __pthread_attr_setstacksize # endif #endif extern int pthread_attr_setstacksize (pthread_attr_t*, size_t); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_attr_getstacksize __pthread_attr_getstacksize # endif #endif extern int pthread_attr_getstacksize ( const pthread_attr_t*, size_t*); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif extern int pthread_attr_setdetachstate (pthread_attr_t*, int); extern int pthread_attr_getdetachstate (const pthread_attr_t*, int*); #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_create __pthread_create # endif #endif extern int pthread_create ( pthread_t*, const pthread_attr_t*, void* (*)(void *), void*); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif #ifdef _PTHREAD_MIXED_PROTOS_ extern int pthread_join64 (pthread_t, __pthreadLongAddr_t*); extern int pthread_join32 (pthread_t, __pthreadShortAddr_t*); # ifdef pthread_join # undef pthread_join # endif # if __INITIAL_POINTER_SIZE == 64 # define pthread_join pthread_join64 # else # define pthread_join pthread_join32 # endif #else # ifdef _PTHREAD_ALLOW_MIXED_PROTOS_ # ifdef pthread_join # undef pthread_join # endif # define pthread_join pthread_join32 # else # ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_join __pthread_join # endif # endif # endif extern int pthread_join (pthread_t, void**); # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" # endif #endif #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_detach __pthread_detach # endif #endif extern int pthread_detach (pthread_t); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_exit __pthread_exit # endif #endif extern void pthread_exit (void*); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_equal __pthread_equal # endif #endif extern int pthread_equal (pthread_t, pthread_t); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif /* * See the note near the top of this header for the risks and benefits of * using inlined operations! They are NOT compiled into your program by * default, and if you choose to enable them you will be required to * recompile should DECthreads ever need to change the inline instruction * sequences! (While we will not do this arbitrarily, we will not hesitate * should it become necessary to substantially improve code performance or * reliability, or to fix a bug!) */ #ifdef _PTHREAD_USE_INLINE # ifdef pthread_equal # undef pthread_equal # endif # define pthread_equal(t1,t2) (t1==t2) #endif #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_once __pthread_once # endif #endif extern int pthread_once (pthread_once_t*, __pthreadOnce_t); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif extern int pthread_key_create (pthread_key_t*, __pthreadDestructor_t); extern int pthread_key_delete (pthread_key_t); extern int pthread_key_create_new_np ( pthread_key_t*, __pthreadConstructor_t, __pthreadExtDestructor_t, int); /* * See the note near the top of this header for the risks and benefits of * using inlined operations! They are NOT compiled into your program by * default, and if you choose to enable them you will be required to * recompile should DECthreads ever need to change the inline instruction * sequences! (While we will not do this arbitrarily, we will not hesitate * should it become necessary to substantially improve code performance or * reliability, or to fix a bug!) * * Additional note: * * pthread_getspecific can't be implemented as a macro in ANSI C, since it * involves two invocations of pthread_self(), which the compiler can't be * depended upon to combine. The next best alternative is a static inlined * routine; even if the #pragma inline isn't recognized by your compiler it's * no worse than the real call (and may be better because the compiler can use * optimized local call sequences); and the routine is small. Consider this an * experiment -- it can be used for a lot more if it works well. */ #if defined (_PTHREAD_USE_ASM_) && defined (_PTHREAD_USE_INLINE) _PTHREAD_INLINE_ static void * pthread_getspecific (pthread_key_t __key) { # ifdef _PTHREAD_ENV_UNIX pthread_t __self = pthread_self (); # else pthreadTeb_p __self = pthreadTeb (); # endif return (void *)(__key >= __self->_Pfield(tsd_count) ? NULL : __self->_Pfield(tsd_values)[__key]); } #else # ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_getspecific __pthread_getspecific # endif # endif extern void* pthread_getspecific (pthread_key_t); # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" # endif #endif #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_setspecific __pthread_setspecific # endif #endif extern int pthread_setspecific (pthread_key_t, const void*); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif #if defined (_PTHREAD_EXC_USE_NATIVE) # define pthread_cleanup_push(_routine_,_arg_) \ { \ void (*_XXX_proc) (void *) = (void (*)(void *))(_routine_); \ void *_XXX_arg = (void *)(_arg_); \ int _XXX_completed = 0; \ _PTHREAD_NATIVE_TRY { # define pthread_cleanup_pop(_execute_) \ _XXX_completed = 1;} \ _PTHREAD_NATIVE_FINALLY { \ if ((! _XXX_completed) || (_execute_)) _XXX_proc (_XXX_arg);} \ } #else # define pthread_cleanup_push(_routine_,_arg_) \ { \ void (*_XXX_proc) (void *) = (void (*)(void *))(_routine_); \ void *_XXX_arg = (void *)(_arg_); \ int _XXX_completed = 0; \ PTHREAD_TRY_NP { # define pthread_cleanup_pop(_execute_) \ _XXX_completed = 1;} \ PTHREAD_FINALLY_NP { \ if ((! _XXX_completed) || (_execute_)) _XXX_proc (_XXX_arg);} \ PTHREAD_ENDTRY_NP} #endif #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_cancel __pthread_cancel # endif #endif extern int pthread_cancel (pthread_t); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif extern int pthread_setcancelstate (int, int*); extern int pthread_setcanceltype (int, int*); #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_testcancel __pthread_testcancel # endif #endif extern void pthread_testcancel (void); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif /* * DECthreads non-portable extensions to POSIX 1003.1c-1995. */ /* * Get or set a name to be associated with threads created using the * attributes object. Note that only the thread attributes object includes a * name -- for other objects, it is sufficient to set the name immediately * after initializing the object (whereas a thread may run between the call to * pthread_create and the call to pthread_setname_np, without a name). * * Note that the "void*" value to which "mbz" points MAY be written by the * thread library. On Alpha hardware (Tru64 UNIX and OpenVMS) and on IA-64, * the value to which "mbz" points must be a 64-bit pointer. If you are * compiling with short pointers, you must take extra steps to ensure that you * have allocated a 64-bit value to receive the result. */ extern int pthread_attr_getname_np ( const pthread_attr_t*, char*, size_t, void**); extern int pthread_attr_setname_np (pthread_attr_t*, const char*, void*); /* * Get or set a name on a condition variable. */ extern int pthread_cond_getname_np (pthread_cond_t*, char*, size_t); extern int pthread_cond_setname_np (pthread_cond_t*, const char*, void*); /* * Get or set a name on a thread-specific data key */ extern int pthread_key_getname_np (pthread_key_t, char*, size_t); extern int pthread_key_setname_np (pthread_key_t, const char*, void*); /* * Get or set a name on a mutex */ extern int pthread_mutex_getname_np (pthread_mutex_t*, char*, size_t); extern int pthread_mutex_setname_np (pthread_mutex_t*, const char*, void*); /* * Get or set a name on a rwlock */ extern int pthread_rwlock_getname_np (pthread_rwlock_t*, char*, size_t); extern int pthread_rwlock_setname_np (pthread_rwlock_t*, const char*, void*); /* * Get or set a name on a thread */ extern int pthread_getname_np (pthread_t, char*, size_t); extern int pthread_setname_np (pthread_t, const char*, void*); #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_cond_sig_preempt_int_np __pthread_cond_sig_preempt_int_np # endif #endif extern int pthread_cond_sig_preempt_int_np (pthread_cond_t*); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_cond_signal_int_np __pthread_cond_signal_int_np # endif #endif extern int pthread_cond_signal_int_np (pthread_cond_t*); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_get_expiration_np __pthread_get_expiration_np # endif #endif extern int pthread_get_expiration_np (const struct timespec*, struct timespec*); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_delay_np __pthread_delay_np # endif #endif extern int pthread_delay_np (const struct timespec*); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_lock_global_np __pthread_lock_global_np # endif #endif extern int pthread_lock_global_np (void); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_unlock_global_np __pthread_unlock_global_np # endif #endif extern int pthread_unlock_global_np (void); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif extern int pthread_attr_setguardsize (pthread_attr_t*, size_t); extern int pthread_attr_getguardsize (const pthread_attr_t*, size_t*); extern unsigned long pthread_getsequence_np (pthread_t); extern unsigned long pthread_getselfseq_np (void); /* * By default (unless #undef-ed) use an inlined macro version of * pthread_getsequence_np, since it's trivial. */ #ifdef _PTHREAD_ENV_UNIX # define pthread_getsequence_np(_t_) (((pthread_t)(_t_))->_Pfield(sequence)) # define pthread_getselfseq_np() (pthread_self ()->_Pfield(sequence)) #else # define pthread_getsequence_np(_t_) (((pthreadTeb_p)(_t_))->_Pfield(sequence)) # define pthread_getselfseq_np() (pthreadTeb ()->_Pfield(sequence)) #endif /* * The POSIX 1003.1c pthread_getspecific() function doesn't report any * errors. If the key value is illegal, or if the thread has no value for the * key, it returns NULL without any error indication. Normally that's not a * problem. However if you really want to know whether a key is valid, you * can use this function. It will return EINVAL if the key is invalid, ENOENT * if the key exists but the thread has no value for the key (or value is * NULL), and 0 if the key is valid and the thread has a value. */ extern int pthread_key_validate_np (pthread_key_t); extern int pthread_yield_np (void); /* * OBSOLETE functions will be moved here before destruction. */ /* * The "DCE thread" heritage _np mutex type attribute operations have been * superceded by the Single UNIX Specification, Version 2 operations. (Same * name but without the _np suffix.) The _np variations will be removed in a * future release. */ #define PTHREAD_MUTEX_NORMAL_NP PTHREAD_MUTEX_NORMAL #define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE #define PTHREAD_MUTEX_ERRORCHECK_NP PTHREAD_MUTEX_ERRORCHECK extern int pthread_mutexattr_gettype_np (const pthread_mutexattr_t*, int*); extern int pthread_mutexattr_settype_np (pthread_mutexattr_t*, int); /* * The "DCE thread" heritage _np guardsize attribute operations have been * superceded by the Single UNIX Specification, Version 2 operations. (Same * name but without the _np suffix.) The _np variations will be removed in a * future release. */ #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_attr_getguardsize_np __pthread_attr_getguardsize_np # endif #endif extern int pthread_attr_getguardsize_np (const pthread_attr_t*, size_t*); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif #ifdef _PTHREAD_USE_MANGLED_NAMES_ # ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "__" # else # define pthread_attr_setguardsize_np __pthread_attr_setguardsize_np # endif #endif extern int pthread_attr_setguardsize_np ( pthread_attr_t*, size_t); #ifdef _PTHREAD_USE_PTDNAM_ # pragma extern_prefix "" #endif /* * OBSOLETE: The function pthread_debug() is no longer implemented. The entry * point remains for source/binary compatibility for now, but will be removed * in a future release. */ extern void pthread_debug (void); /* * OBSOLETE: This type is no longer used. The definition remains for * source/binary compatibility for now, but will be removed in a future * release. */ typedef enum pthreadDbgStatus_t { PTHREAD_DBG_SUCCESS = 0, PTHREAD_DBG_QUIT = 1, PTHREAD_DBG_NONESEL = 2, PTHREAD_DBG_SUCCESSPEND = 3, PTHREAD_DBG_NOPRIV = -1, PTHREAD_DBG_INVPARAM = -2, PTHREAD_DBG_INVSEQ = -3, PTHREAD_DBG_INCONSTATE = -4, PTHREAD_DBG_CORRUPT = -5, PTHREAD_DBG_INVOPTION = -6, PTHREAD_DBG_NOARG = -7, PTHREAD_DBG_INVADDR = -8, PTHREAD_DBG_INVCMD = -9, PTHREAD_DBG_NULLCMD = -10, PTHREAD_DBG_CONFLICT = -11, PTHREAD_DBG_UNIMPL = -12 } pthreadDbgStatus_t; /* * OBSOLETE: The function pthread_debug_cmd() is no longer implemented. The * entry point remains for source/binary compatibility for now, but will be * removed in a future major release. */ extern pthreadDbgStatus_t pthread_debug_cmd (char *); #ifdef _PTHREAD_ENV_CXX } /* End of extern "C" { */ #endif #endif /* _PTHREAD_USE_D4 */ #endif /* ************************************************************************* * * * Copyright 2000 Compaq Computer Corporation * * * * COMPAQ Registered in U.S. Patent and Trademark Office. * * * * Confidential computer software. Valid license from Compaq or * * authorized sublicensor required for possession, use or copying. * * Consistent with FAR 12.211 and 12.212, Commercial Computer Software, * * Computer Software Documentation, and Technical Data for Commercial * * Items are licensed to the U.S. Government under vendor's standard * * commercial license. * * * * Compaq shall not be liable for technical or editorial errors or * * omissions contained herein. The information in this document is * * subject to change without notice. * * * ************************************************************************* */ /* * @(#)$RCSfile: pthread_d4.h,v $ $Revision: 1.1.22.1 $ (DEC) $Date: 2000/10/19 03:24:22 $ */ /* * FACILITY: * * DECthreads core * * ABSTRACT: * * External definitions for DECthreads POSIX 1003.4a/D4 services * * AUTHORS: * * Dave Butenhof * * CREATION DATE: * * 20 February 1990 * * MODIFIED BY: * * J.L. Berg * Dave Butenhof * Paul Clark * Paul Curtin * Steve Johnson * Brian Keane * Peter Portante * Webb Scales * * LAST MODIFIED: * * 16 September 1998 */ #ifndef _PTHREAD_D4_ # define _PTHREAD_D4_ #ifdef __cplusplus extern "C" { #endif #if defined(vms) || defined(__vms) || defined(VMS) || defined(__VMS) # include # ifndef _TIMESPEC_T_ # define _TIMESPEC_T_ typedef struct timespec { unsigned long tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ } timespec_t; # endif #else # include # include #endif /* * We define the following macro to change the actual name of the routine to * have the _d4 appended to it. It is only used on routines which have a name * conflict with the new POSIX 1003.1c standard. */ #if _CMA_OS_ == _CMA__VMS # if _CMA_COMPILER_ == _CMA__VAXC # define _Draft4(_arg_) _arg_/**/_d4 # else # define _Draft4(_arg_) _arg_##_d4 # endif #else # define _Draft4(_arg_) _arg_ #endif /* * The implementation makes these basic decisions */ #ifndef _POSIX_THREADS # define _POSIX_THREADS 1 #endif #ifndef _POSIX_THREAD_ATTR_STACKSIZE # define _POSIX_THREAD_ATTR_STACKSIZE 1 #endif #if _CMA_POSIX_SCHED_ # define _POSIX_THREADS_REALTIME_SCHEDULING 1 #elif defined(_POSIX_THREADS_REALTIME_SCHEDULING) # undef _POSIX_THREADS_REALTIME_SCHEDULING #endif #ifndef _POSIX_THREADS_PER_PROCESS_SIGNALS_1 # define _POSIX_THREADS_PER_PROCESS_SIGNALS_1 1 #endif #if ((_CMA_COMPILER_ != _CMA__DECCPLUS) && (_CMS_OS_ == _CMA__UNIX)) /* * Implement push and pop for cancellation handlers, using the compiler's * native try/finally constructs. */ # define pthread_cleanup_push(_routine_,_arg_) \ { \ pthread_cleanup_t _XXX_proc = (pthread_cleanup_t)(_routine_); \ pthread_addr_t _XXX_arg = (pthread_addr_t)(_arg_); \ int _XXX_completed = 0; \ try { # define pthread_cleanup_pop(_execute_) \ _XXX_completed = 1;} \ finally { \ if ((! _XXX_completed) || (_execute_)) _XXX_proc (_XXX_arg);} \ } #else /* * Implement push and pop for cancellation handlers, using TRY and ENDTRY */ # define pthread_cleanup_push(_routine_,_arg_) \ { \ pthread_cleanup_t _XXX_proc = (pthread_cleanup_t)(_routine_); \ pthread_addr_t _XXX_arg = (pthread_addr_t)(_arg_); \ int _XXX_completed = 0; \ TRY { # define pthread_cleanup_pop(_execute_) \ _XXX_completed = 1;} \ FINALLY { \ if ((! _XXX_completed) || (_execute_)) _XXX_proc (_XXX_arg);} \ ENDTRY} #endif #define pthread_equal_np(__t1,__t2) pthread_equal(__t1,__t2) /* * Sample decisions for the environment types */ typedef cma_t_key pthread_key_t; typedef cma_t_address pthread_addr_t; typedef pthread_addr_t any_t; typedef cma_t_handle pthread_handle_t; typedef void (*pthread_cleanup_t) (pthread_addr_t arg); /* * Sample decision for a one-time initialization control block and its * initialization macro. * * Declare a one time initialization control block as: * * static pthread_once_t block = pthread_once_init; */ typedef cma_t_once pthread_once_t; #define pthread_once_init cma_once_init #define CANCEL_ON 1 #define CANCEL_OFF 0 /* * The following are the portable pthread definitions */ /* * Operations on attributes objects */ typedef cma_t_attr pthread_attr_t; /* * An attributes object is created to specify the attributes of other CMA * objects that will be created. */ int _CMA_CALL_ pthread_attr_create ( pthread_attr_t *attr); /* * An attributes object can be deleted when it is no longer needed. */ int _CMA_CALL_ pthread_attr_delete ( pthread_attr_t *attr); /* * Operations on threads */ typedef cma_t_start_routine pthread_startroutine_t; typedef cma_t_thread pthread_t; typedef pthread_startroutine_t pthread_func_t; #define PTHREAD_INHERIT_SCHED (int)cma_c_sched_inherit #define PTHREAD_DEFAULT_SCHED (int)cma_c_sched_use_default #define PTHREAD_CREATE_JOINABLE (int)cma_c_create_joinable #define PTHREAD_CREATE_DETACHED (int)cma_c_create_detached #if !_CMA_RT4_KTHREAD_ # define SCHED_FIFO cma_c_sched_fifo # define SCHED_RR cma_c_sched_rr # define SCHED_OTHER cma_c_sched_throughput # define SCHED_FG_NP cma_c_sched_throughput # define SCHED_BG_NP cma_c_sched_background #endif #define PRI_FIFO_MIN cma_c_prio_fifo_min #define PRI_FIFO_MAX cma_c_prio_fifo_max #define PRI_RR_MIN cma_c_prio_rr_min #define PRI_RR_MAX cma_c_prio_rr_max #define PRI_FG_MIN_NP cma_c_prio_through_min #define PRI_FG_MAX_NP cma_c_prio_through_max #define PRI_BG_MIN_NP cma_c_prio_back_min #define PRI_BG_MAX_NP cma_c_prio_back_max #define PRI_OTHER_MIN cma_c_prio_through_min #define PRI_OTHER_MAX cma_c_prio_through_max int _CMA_CALL_ _Draft4(pthread_equal) ( /* Compare two handles */ pthread_t handle1, pthread_t handle2); /* * This must come after the routine prototype declaration so that the * right name mangling can happen for the prototype on VMS platforms. */ #ifdef pthread_equal # undef pthread_equal #endif #define pthread_equal(_t1_,_t2_) \ (((_t1_).field1 == (_t2_).field1) \ && ((_t1_).field2 == (_t2_).field2)) /* * Operations to define thread creation attributes */ /* * Set or obtain the default thread priority. */ int _CMA_CALL_ pthread_attr_setprio ( pthread_attr_t *attr, int priority); int _CMA_CALL_ pthread_attr_getprio ( pthread_attr_t attr); /* * Set or obtain the default scheduling algorithm */ int _CMA_CALL_ pthread_attr_setsched ( pthread_attr_t *attr, int scheduler); int _CMA_CALL_ pthread_attr_getsched ( pthread_attr_t attr); /* * Set or obtain whether a thread will use the default scheduling attributes, * or inherit them from the creating thread. */ int _CMA_CALL_ _Draft4(pthread_attr_setinheritsched) ( pthread_attr_t *attr, int inherit); int _CMA_CALL_ _Draft4(pthread_attr_getinheritsched) ( pthread_attr_t attr); /* * Set or obtain the default stack size */ int _CMA_CALL_ _Draft4(pthread_attr_setstacksize) ( pthread_attr_t *attr, long stacksize); unsigned long _CMA_CALL_ _Draft4(pthread_attr_getstacksize) ( pthread_attr_t attr); /* * Set or obtain the default guard size */ int _CMA_CALL_ _Draft4(pthread_attr_setguardsize_np) ( pthread_attr_t *attr, long guardsize); unsigned long _CMA_CALL_ _Draft4(pthread_attr_getguardsize_np) ( pthread_attr_t attr); /* * Set or obtain the detach state */ int _CMA_CALL_ pthread_attr_setdetach_np ( pthread_attr_t *attr, int detachstate); int _CMA_CALL_ pthread_attr_getdetach_np ( pthread_attr_t attr); /* * The following procedures can be used to control thread creation, * termination and deletion. */ /* * To create a thread object and runnable thread, a routine must be specified * as the new thread's start routine. An argument may be passed to this * routine, as an untyped address; an untyped address may also be returned as * the routine's value. An attributes object may be used to specify details * about the kind of thread being created. */ int _CMA_CALL_ _Draft4(pthread_create) ( pthread_t *thread, pthread_attr_t attr, pthread_startroutine_t start_routine, pthread_addr_t arg); /* * A thread object may be "detached" to specify that the return value and * completion status will not be requested. */ int _CMA_CALL_ _Draft4(pthread_detach) ( pthread_t *thread); /* * A thread may terminate it's own execution. */ void _CMA_CALL_ _Draft4(pthread_exit) ( pthread_addr_t status); /* * A thread can await termination of another thread and retrieve the return * value of the thread. */ int _CMA_CALL_ _Draft4(pthread_join) ( pthread_t thread, pthread_addr_t *status); /* * Thread Scheduling Operations */ /* * The current user_assigned priority of a thread can be changed. */ int _CMA_CALL_ pthread_setprio ( pthread_t thread, int priority); /* * The current user_assigned scheduler algorithm of a thread can be changed. */ int _CMA_CALL_ pthread_setscheduler ( pthread_t thread, int scheduler, int priority); /* * A thread may tell the scheduler that its processor can be made available. */ void _CMA_CALL_ pthread_yield (void); /* * Bind a thread to a particular CPU on a multiprocessor system. */ int _CMA_CALL_ pthread_bind_to_cpu_np ( pthread_t thread, long cpu_mask); /* * Thread Information Operations */ /* * A thread may obtain a copy of its own thread handle. */ pthread_t _CMA_CALL_ _Draft4(pthread_self) (void); /* * Obtain a thread's sequence number. This will usually be a unique integer * across all threads within a process (until a large number of threads has * been created). */ long _CMA_CALL_ pthread_getunique_np ( pthread_t *thread); /* * The current user_assigned priority of a thread can be read. */ int _CMA_CALL_ pthread_getprio ( pthread_t thread); /* * The current user_assigned scheduler algorithm of a thread can be read. */ int _CMA_CALL_ pthread_getscheduler ( pthread_t thread); /* * Operations on Mutexes */ #define MUTEX_FAST_NP (int)cma_c_mutex_fast #define MUTEX_RECURSIVE_NP (int)cma_c_mutex_recursive #define MUTEX_NONRECURSIVE_NP (int)cma_c_mutex_nonrecursive typedef cma_t_attr pthread_mutexattr_t; typedef cma_t_mutex pthread_mutex_t; int _CMA_CALL_ pthread_mutexattr_create ( pthread_mutexattr_t *attr); int _CMA_CALL_ pthread_mutexattr_delete ( pthread_mutexattr_t *attr); int _CMA_CALL_ pthread_mutexattr_setkind_np ( pthread_mutexattr_t *attr, int kind); int _CMA_CALL_ pthread_mutexattr_getkind_np ( pthread_mutexattr_t attr); int _CMA_CALL_ pthread_mutexattr_setmetered_np ( pthread_mutexattr_t *attr, int meter); int _CMA_CALL_ pthread_mutexattr_getmetered_np ( pthread_mutexattr_t attr); /* * The following routines create, delete, lock and unlock mutexes. */ int _CMA_CALL_ _Draft4(pthread_mutex_init) ( pthread_mutex_t *mutex, pthread_mutexattr_t attr); int _CMA_CALL_ _Draft4(pthread_mutex_destroy) ( pthread_mutex_t *mutex); int _CMA_CALL_ _Draft4(pthread_mutex_lock) ( pthread_mutex_t *mutex); int _CMA_CALL_ _Draft4(pthread_mutex_trylock) ( pthread_mutex_t *mutex); int _CMA_CALL_ _Draft4(pthread_mutex_unlock) ( pthread_mutex_t *mutex); /* * Operations on condition variables */ typedef cma_t_attr pthread_condattr_t; typedef cma_t_cond pthread_cond_t; int _CMA_CALL_ pthread_condattr_create ( pthread_condattr_t *attr); int _CMA_CALL_ pthread_condattr_delete ( pthread_condattr_t *attr); /* * A thread can create and delete condition variables. */ int _CMA_CALL_ _Draft4(pthread_cond_init) ( pthread_cond_t *cond, pthread_condattr_t attr); int _CMA_CALL_ _Draft4(pthread_cond_destroy) ( pthread_cond_t *cond); /* * A thread can signal to and broadcast on a condition variable. */ int _CMA_CALL_ _Draft4(pthread_cond_broadcast) ( pthread_cond_t *cond); int _CMA_CALL_ _Draft4(pthread_cond_signal) ( pthread_cond_t *cond); int _CMA_CALL_ _Draft4(pthread_cond_signal_int_np) ( pthread_cond_t *cond); #if _CMA_OS_ == _CMA__UNIX int _CMA_CALL_ pthread_cond_sig_preempt_int_np ( pthread_cond_t *condition, pthread_addr_t scp); #else # if _CMA_OS_ == _CMA__VMS int _CMA_CALL_ pthread_cond_sigprmpt_int_np_d4 ( pthread_cond_t *condition); # else int _CMA_CALL_ pthread_cond_sig_preempt_int_np ( pthread_cond_t *condition); # endif #endif /* * A thread can wait for a condition variable to be signalled or broadcast. */ int _CMA_CALL_ _Draft4(pthread_cond_wait) ( pthread_cond_t *cond, pthread_mutex_t *mutex); /* * Operations for timed waiting */ /* * A thread can perform a timed wait on a condition variable. */ int _CMA_CALL_ _Draft4(pthread_cond_timedwait) ( pthread_cond_t *cond, pthread_mutex_t *mutex, struct timespec *abstime); /* * Operations for client initialization. */ typedef void (*pthread_initroutine_t) (void); int _CMA_CALL_ _Draft4(pthread_once) ( pthread_once_t *once_block, pthread_initroutine_t init_routine); /* * Operations for per-thread context */ typedef cma_t_destructor pthread_destructor_t; /* * A unique per-thread context key can be obtained for the process */ int _CMA_CALL_ pthread_keycreate ( pthread_key_t *key, pthread_destructor_t destructor); /* * A thread can set a per-thread context value identified by a key. */ int _CMA_CALL_ _Draft4(pthread_setspecific) ( pthread_key_t key, pthread_addr_t value); /* * A thread can retrieve a per-thread context value identified by a key. */ int _CMA_CALL_ _Draft4(pthread_getspecific) ( pthread_key_t key, pthread_addr_t *value); /* * Operations for alerts. */ /* * The current thread can request that a thread terminate it's execution. */ int _CMA_CALL_ _Draft4(pthread_cancel) ( pthread_t thread); /* * The current thread can poll for alert delivery. */ void _CMA_CALL_ _Draft4(pthread_testcancel) (void); /* * The current thread can enable or disable alert delivery (PTHREAD * "cancels"); it can control "general cancelability" (CMA "defer") or * just "asynchronous cancelability" (CMA "asynch disable"). */ int _CMA_CALL_ pthread_setasynccancel ( int state); int _CMA_CALL_ pthread_setcancel ( int state); #ifndef _CMA_SUPPRESS_EXTERNALS_ _CMA_IMPORT_ pthread_attr_t pthread_attr_default; _CMA_IMPORT_ pthread_mutexattr_t pthread_mutexattr_default; _CMA_IMPORT_ pthread_condattr_t pthread_condattr_default; #endif /* * Define nonportable extensions */ extern int _CMA_CALL_ _Draft4(pthread_get_expiration_np) ( struct timespec *delta, struct timespec *abstime); extern int _CMA_CALL_ _Draft4(pthread_delay_np) ( struct timespec *interval); extern int _CMA_CALL_ _Draft4(pthread_lock_global_np) (void); extern int _CMA_CALL_ _Draft4(pthread_unlock_global_np) (void); #if _CMA_OS_ != _CMA__VMS extern int _CMA_CALL_ pthread_sig_to_can_thread_np ( sigset_t *sigset, pthread_t *target, pthread_t *thread); extern int _CMA_CALL_ pthread_signal_to_cancel_np ( sigset_t *sigset, pthread_t *target); #endif /* * Now, since we are providing source migration capability, we need to make * sure old code, which was built against the POSIX 1003.4a interface, * references the new routine names which have _d4 on the end. */ #if _CMA_OS_ == _CMA__VMS # define pthread_attr_getguardsize_np(__attr) \ pthread_attr_getguardsize_np_d4 (__attr) # define pthread_attr_getinheritsched(__attr) \ pthread_attr_getinheritsched_d4 (__attr) # define pthread_attr_getstacksize(__attr) \ pthread_attr_getstacksize_d4 (__attr) # define pthread_attr_setguardsize_np(__attr,__guardsize) \ pthread_attr_setguardsize_np_d4 (__attr,__guardsize) # define pthread_attr_setinheritsched(__attr,__inherit) \ pthread_attr_setinheritsched_d4 (__attr,__inherit) # define pthread_attr_setstacksize(__attr,__stacksize) \ pthread_attr_setstacksize_d4 (__attr,__stacksize) # define pthread_cancel(__thread) \ pthread_cancel_d4 (__thread) # define pthread_cond_broadcast(__cond) \ pthread_cond_broadcast_d4 (__cond) # define pthread_cond_destroy(__cond) \ pthread_cond_destroy_d4 (__cond) # define pthread_cond_init(__cond,__attr) \ pthread_cond_init_d4 (__cond,__attr) # define pthread_cond_sig_preempt_int_np(__cond) \ pthread_cond_sigprmpt_int_np_d4 (__cond) # define pthread_cond_signal(__cond) \ pthread_cond_signal_d4 (__cond) # define pthread_cond_signal_int_np(__cond) \ pthread_cond_signal_int_np_d4 (__cond) # define pthread_cond_timedwait(__cond,__mutex,__abstime) \ pthread_cond_timedwait_d4 (__cond,__mutex,__abstime) # define pthread_cond_wait(__cond,__mutex) \ pthread_cond_wait_d4 (__cond,__mutex) # define pthread_create(__thread,__attr,__start_routine,__arg) \ pthread_create_d4 (__thread,__attr,__start_routine,__arg) # define pthread_delay_np(__interval) \ pthread_delay_np_d4 (__interval) # define pthread_detach(__thread) \ pthread_detach_d4 (__thread) # define pthread_exit(__status) \ pthread_exit_d4 (__status) # define pthread_get_expiration_np(__delta,__abstime) \ pthread_get_expiration_np_d4 (__delta,__abstime) # define pthread_getspecific(__key,__value) \ pthread_getspecific_d4 (__key,__value) # define pthread_join(__thread,__status) \ pthread_join_d4 (__thread,__status) # define pthread_lock_global_np() \ pthread_lock_global_np_d4 () # define pthread_mutex_destroy(__mutex) \ pthread_mutex_destroy_d4 (__mutex) # define pthread_mutex_init(__mutex,__attr) \ pthread_mutex_init_d4 (__mutex,__attr) # define pthread_mutex_lock(__mutex) \ pthread_mutex_lock_d4 (__mutex) # define pthread_mutex_trylock(__mutex) \ pthread_mutex_trylock_d4 (__mutex) # define pthread_mutex_unlock(__mutex) \ pthread_mutex_unlock_d4 (__mutex) # define pthread_once(__once_block,__init_routine) \ pthread_once_d4 (__once_block,__init_routine) # define pthread_self() \ pthread_self_d4 () # define pthread_setspecific(__key,__value) \ pthread_setspecific_d4 (__key,__value) # define pthread_testcancel() \ pthread_testcancel_d4 () # define pthread_unlock_global_np() \ pthread_unlock_global_np_d4 () #endif #ifdef __cplusplus } #endif #endif /* ************************************************************************* * * * Copyright 2000 Compaq Computer Corporation * * * * COMPAQ Registered in U.S. Patent and Trademark Office. * * * * Confidential computer software. Valid license from Compaq or * * authorized sublicensor required for possession, use or copying. * * Consistent with FAR 12.211 and 12.212, Commercial Computer Software, * * Computer Software Documentation, and Technical Data for Commercial * * Items are licensed to the U.S. Government under vendor's standard * * commercial license. * * * * Compaq shall not be liable for technical or editorial errors or * * omissions contained herein. The information in this document is * * subject to change without notice. * * * ************************************************************************* */ /* * @(#)$RCSfile: pthread_debug.h,v $ $Revision: 1.1.26.2 $ (DEC) $Date: 2000/02/21 20:20:40 $ */ /* * FACILITY: * * DECthreads POSIX 1003.1c * * ABSTRACT: * * External definitions for the DECthreads "debug assistant" library * (libpthreaddebug.so on Digital UNIX, or PTHREAD$DBGSHR.EXE on * OpenVMS) * * IMPORTANT: * ---------- * * The interfaces defined in this header file are intended for use only * by debuggers or libraries that need to support generalized debugger * access with assistance from DECthreads, such as Ada or C++ tasking * packages. * * AUTHORS: * * Dave Butenhof * Peter Portante * * CREATION DATE: * * 16 October 1995 * * MODIFIED BY: * * Dave Butenhof * Richard Love * Peter Portante * Tim Rice * Brian Silver * Mark Simons * Mary Sullivan * Tom Dahl * */ #ifndef _PTHREAD_DEBUG_H_ # define _PTHREAD_DEBUG_H_ #ifdef __cplusplus extern "C" { #endif #include #include #include #ifndef _DECTHREADS_ # error " depends upon DECthreads internals" #endif #define PTHREAD_DEBUG_VERSION 3 /* Current interface version */ /* * GENERAL NOTES ON USING THIS HEADER * * The header describes the functional interface and data * structures used to communicate with the DECthreads debug assistant (we'll * generally refer to it as "the assistant"). * * To use the debug assistant, a debugger will compile (one or more modules) * with this header file, and link with the assistant library. The facilities * in this debugging system are designed to work with a mechanism such as the * Digital UNIX "proc" filesystem, or analysis of a saved core file, where the * multithreaded process being debugged (the "debuggee", or "target") lives in * a separate address space, not directly accessible by the assistant. Thus, * all memory references are made through "callbacks" supplied by the "client" * debugger (or any analysis tool utilizing this library). * * *** DECthreads "core" symbol table hook: * * In order to navigate within the address space of the multithreaded process, * the assistant relies on a special "symbol table" linked into the DECthreads * library (that is, libpthread.so on Digital UNIX, or PTHREAD$RTL.EXE on * OpenVMS). This symbol table, identified by the symbolic name * __pthread_dbg_symtable, tells the assistant how to find the various "root" * data structures necessary to identify threads, synchronization objects, and * other data. The assistant has no direct access to the symbol table of the * process being debugged, so it relies on the debugger to supply the address * of __pthread_dbg_symtable. The address is one of the arguments to the * pthreadDebugContextInit entry point, which must be called before using any * other debug assistant functions. * * It may also be noted that the debugger may look for __pthread_dbg_symtable * symbol to determine whether the target process may be multithreaded, before * attempting to initialize a debug assistant context for that process. At the * very least, be aware that the assistant currently cannot initialize * (pthreadDebugContextInit will fail) for any process that does not have a * visible __pthread_dbg_symtable symbol. In the future, we will try to work * with the kernel and debuggers to devise a better way to "hook" into the * target process, and we'd like to remove the need for * __pthread_dbg_symtable. * * *** Object caching and SUSPEND/RESUME callbacks: * * For efficiency, the assistant caches "objects" that it references in the * target process. However, because the target process is asynchronous, and * may be running simultaneously in many cases, the assistant cannot count on * the data remaining static. Therefore, it generally uses the cache to * efficiently LOCATE the remote object, and reads the actual target process * memory to "validate" the object. This validation can be avoided if and only * if the assistant can know that the process has been unable to run since the * object was last validated. It knows this, for example, while the debugger * traverses the list of threads, because pthreadDebugThdSeqInit suspends the * target process, which is resumed only when pthreadDebugThdSeqDestroy is * called. There are several important consequences to this assumption: * * * Operation in contexts where the assistant has not itself suspended the * process do not assume that the debugger has suspended the target * process. If the debugger wishes to take full advantage of caching in all * contexts, the debugger should always use the pthreadDebugSuspend and * pthreadDebugResume functions -- even though all they do is invoke the * debugger callback. The functions allow the assistant to know when the * debugger has suspended process execution. * * * If you supply a SUSPEND callback, it must actually ensure that the * process is suspended before it returns. If it cannot suspend the * process, it must return an error status. If the SUSPEND callback * returns with success status (0), while the process is not actually * suspended, the debug assistant's cache may become inconsistent. This * will result in confusion of the debug client and the users. (You may, * for example, see objects that no longer exist.) * * *** A few words about kernel threads and user threads * * In general, the debugger should endeavor to ignore kernel threads. It may, * however, sometimes be useful to have a mode that works with kernel threads * and ignores user threads. You should rarely attempt to deal with both user * and kernel threads simultaneously. For example, don't try to hold all other * kernel threads while single stepping a user thread -- instead, hold all * other user threads. * * Beware that procfs may sometimes show a large number of kernel threads. * Generally, a DECthreads process will have one kernel thread for each * physical processor available to the process, plus one for the internal * "manager thread". Threads created in "system contention scope" (SCS) will * each have a private kernel thread. There may also be a number of kernel * threads that were previously used, and later destroyed. These are cached by * the kernel against future need. The kernel cache will be trimmed * approximately every 20 seconds by a routine that runs in the context of the * DECthreads "manager thread". (Note: the manager thread is used both by the * DECthreads library, in user mode context, and by the kernel, in kernel * context.) * * *** Identification of user thread ID from kernel thread: * * When a debugger takes a trap, it must usually determine the current thread * ID. When using the proc filesystem, the debugger can acquire a struct * prstatus structure for the current kernel thread, read the pr_teb member, * fetch from that address in the target process a block of memory of size * "sizeof(struct pthreadTeb_t)", and read the sequence member from the * resulting structure. However, there are special cases during process * initialization when this method will not work, because the TEB pointer is * only set when execution reaches the libc initialization (and is then * changed to a "true TEB" when DECthreads is initialized). (Note that in this * case, the correct thread ID is always "1".) Instead, you might want to * consider using pthreadDebugKidToId, which converts a kernel thread ID to a * user thread ID, and let the assistant do all the "grunt work" (even though * most of the work is done via the KTHDINFO and GETMEM callbacks). (You could * also supply the SPECKTHD callback and use pthreadDebugGetSpecialThread.) * * *** The SPECKTHD callback: * * For the most part, SPECKTHD is required only if the debugger plans to * utilize the pthreadDebugGetSpecialThread function. However, the assistant * will also use SPECKTHD (if available) to enhance the output of the "thread" * command (pthreadDebugCmd parser). Specifically, it will display ">" for the * current thread and "*" for the trap thread in the "thread -1" columnar * output format. It may be used in additional places (if available) for * various reasons, but we do not currently expect to require implementation * of the SPECKTHD callback. * * *** Interactions with proc filesystem: * * When you PRRUN, or PRSTEP, a process, after changing the HOLD state of user * mode threads, (especially after HOLDing them), you should always use the * additional flag PRRESCHED. This causes the kernel to generate a special * upcall for each kernel thread allowing the DECthreads scheduler to preempt * the HELD user thread before it can continue executing user instructions. * Without PRRESCHED, some HELD threads may continue to run. Also, beware that * HOLDing user threads does not work reliably prior to Digital UNIX 4.0D * patch kit 3 (released January, 1999). * * *** Something approximating release notes: * * *** V0 interface * * The V0 interface was the originally released Debug Assistant, part of * DECthreads version 3.13, and shipped with Digital UNIX 4.0 and OpenVMS * 7.0. There was no public header for this interface, though the private * header was usually known (and distributed) as . * * The V0 PTHREAD_DEBUG_VERSION value was 0x0313c001, rather than 0. This * scheme was scrapped for V1, setting PTHREAD_DEBUG_VERSION to 1. * * Many V0 interfaces had substantially different names than the V1 and * later. * * *** V1 interface * * Released with DECthreads version 3.14, on Digital UNIX 4.0D, OpenVMS * 7.2. The header is shipped with the O/S kit. (But * read the warnings carefully before using it!) * * Many function names were changed for greater consistency, putting all * the "object" designations towards the front. All of the old entry * points remain for binary compatibility. * * New callbacks were added: KTHDINFO and SPECKTHD. (Actually, V0 had * defined the KTHDINFO, but hadn't defined the information structure * associated with it.) * * Most of the informational structures were changed substantially, * and register info was changed from arrays to structures. * * When V0 clients attach to the debug assistant, all input and output * structures are translated to/from V1 internal form. * * Porting from V0 to V1 may be a substantial amount of effort, but will * gain significant new information. * * *** Digital UNIX 4.0D, patch kit 3 (DECthreads 3.14-131) * * Substantial changes to repair HOLD and UNHOLD, particularly of threads * that may be concurrently executing on another processor. (Though some * race conditions were observed even on a uniprocessor.) As a result, * the behavior of, in particular, the pthreadDebugThdHold function was * substantially changed in many cases. The ESRCH error was introduced to * indicate a TERMINATED thread, which cannot be held. (The ESRCH error * was arguably a bad idea, since it could retroactively change the * behavior of existing V0 and V1 clients. A later release will remedy * this by silently ignoring the TERMINATED thread and returning 0 for * V0 and V1 clients.) * * *** Digital UNIX 4.0D, patch kit 3, and OpenVMS 7.2 * * The SUSPEND and RESUME callbacks, and the WRITE callback, are now * optional, regardless of client interface version. These may be * omitted, for example, when the source of data is a core file, where * those functions have no meaning. (OpenVMS SDA always omits them, * because it supports only an asynchronous read-only connection.) But * beware that some results are unreliable if SUSPEND and RESUME are not * made available for a "live" process, since many operations cannot be * completed "atomically". If you supply SUSPEND or RESUME, you must * supply both. * * You need not supply MALLOC or FREE callbacks; malloc and free will be * used directly. If you supply either, you must supply both. * * *** V2 interface * * Part of DECthreads version 3.15. Released with Digital UNIX 4.0D, * patch kit 4, Compaq Tru64 UNIX 4.0F, and Tru64 UNIX 5.0. * * When you connect to a session with pthreadDebugContextInit, you may * set some flags in the high end of the "version" member in the * pthreadDebugCallbacks_t structure. These flags are defined in the * pthreadDebugInitFlag_t enum, and are documented at the top of this * header file. * * New fields were added to the TSD (key address), RWL (writer ID, and * reader count), and THREAD (creator interface) structures. Also, the * THREAD info structure was substantially rearranged to give better * and less ambiguous information about a thread's blocking state. All * blocking state is now segregated into a "block" union containing * appropriate information for each type of blocking state. Note that * the blocking information is now filled in for READY and RUNNING * threads as well as BLOCK threads. When a thread is readied, its prior * blocking state remains until it begins to run, and that information * can sometimes be useful in debugging. (E.g., the ready thread was * previously blocked on condition variable 3.) In some cases when a * thread is interrupted (e.g., by a ^C under ladebug), the blocking * state also remains intact while the thread processes the signal; you * can now see that the current thread was previously blocked, and why. * Also, the kernel blocking state for UNIX, in addition to the habitat * and syscall numbers (which are hard to translate without access to * the OS source code), is now represented as strings. (Note that the * habitat string will be empty if the habitat is 0, the "normal" * habitat; others are named.) The syscall names don't always directly * correspond to the user-visible libc stub names, but most are close * enough to determine what's going on. Also note that the "process * shared" synchronization object blocking functions are reported as * kernel blocking states, but do not have habitat and syscall numbers. * * Sequence traversal routines were added for TSD keys. (These routines * can be used by version 0 and version 1 clients, but the entry points * didn't exist on earlier versions of the Debug Assistant and aren't * declared in earlier versions of the header file.) * * There are some rudimentary and preliminary routines to process and * format a DECthreads trace stream. Some are currently nonfunctional * (and will fail with ENOSYS). The others are not intended to be * self-evident, and are not well documented. (Even by the loose * standards of this header file.) * * There is a new event, TOOLREPORT, which will be used by the Visual * Threads tool to invoke a debugger breakpoint if a debugger is attached * that cares. The first argument is a string to be printed for the user. * The second is a command string. The syntax of the command string is * "undefined", but probably would be based on the ladebug command syntax * and likely ignored by any other debugger. (Note that this event can be * used by version 0 or version 1 clients, but the event will be accepted * only when running with a version 2 Debug Assistant. Some unreleased * version 1 Debug Assistants, such as the one in "Digital UNIX X5.0 * EFT1", also recognize this event.) * * Correct 4.0D-3's regression in adding ESRCH errors for version 0 * clients that attempt to HOLD/UNHOLD terminated threads. Version 0 (and * 1) clients will receive the status 0. Version 2 clients will receive * EINVAL. * * Version 0 and version 1 interfaces silently ignore HOLD/UNHOLD * requests for internal DECthreads threads. (Those with "negative" * sequence numbers.) Version 2 clients will receive EPERM errors. * * *** V3 interface * * Part of DECthreads version 3.16. Released with Tru64 UNIX 5.0A, * and 4.0G (?). The code is also available with the "bl13" patch kits * for 4.0D, 4.0E, and 4.0F. * * The use of time structures has been changed for consistency and to * reduce ambiguity across various time_t models. (Tru64 UNIX now * supports both a 32-bit time_t and a 64-bit time_t.) The new type is * pthreadDebugTimespec_t. * * The pthreadDebugMutInfo_t structure contains a new "depth" field to * record the "recursion depth" of a recursive lock. The existing flag * PTHREAD_DEBUG_MUT_PSHARED is now set when appropriate, though full * support for pshared synchronization objects will be in a later * version. A new flag, PTHREAD_DEBUG_MUT_TRACED, tells whether the * mutex is marked for tracing. The flags will be set for clients of * old versions, as well. * * A new flag, PTHREAD_DEBUG_THD_DETACH, records that the target thread * of a pthreadDebugThdGetInfo call is detached. The layout of the * structure has not changed, and the new flag will be set for clients * connected using older versions. * * The _PSHARED flags are also set now for condition variable and * read-write lock info. Again, full support for pshared synchronization * requires additional client and operating system support and will be * in a future version. */ /* * MACROS */ /* * The following error numbers (as defined by ) may be returned as * the value of any debug assistant interface to indicate status. Client * callback routines are also expected to report the outcome by returning * error numbers. The following are the error numbers used by the assistant, * and their usual meaning. Callbacks should follow these guidelines if * possible. * * ESUCCESS (0) Successful completion * ENOENT End of traversal sequence (no more) * ENOTSUP Function not supported (usually callback error) * EINVAL Invalid parameter (sometimes, "thread in wrong state") * ESRCH ID does not represent a thread * ENOMEM Insufficient memory * EPERM Unable to perform operation (priv, ownership) * EAGAIN Operation cannot be performed right now (try again) * ENOSYS Not supported * EBUSY Operation cannot be performed: object is busy * ECHILD Broken association between parts of sync. object * EFAULT Internal addressing error * EVERSION Incompatible trace file version * ESHUTDOWN pthreadDebugCmd("exit") * * Note that, in most cases, errors returned by a callback routine cause the * debug assistant to immediately abort the current operation and return the * callback's error status to the client. There are some cases where the debug * assistant may be able to continue operation, or attempt an alternative. We * recognize that simply passing through the callback status is not * necessarily useful or informative to the client, and may cause confusion. * This situation, though, is unlikely to change at this late date. */ /* * These flags can be logically OR-ed into PTHREAD_DEBUG_VERSION (when * connecting with the v1 interface or higher) to affect how the connection is * made. * * PTHREAD_DEBUG_FLAG_PASSIVE: * * Normally, when a debugger connects, pthreadDebugContextInit writes * into the debuggee process to register the connection. (Tracing tools * can ask about the connection.) Only one debugger (we think) can * usefully attach to a given process: for example, they would need to * coordinate interpretation of the event breakpoints, and any * modifications to the process state. * * PTHREAD_DEBUG_FLAG_PASSIVE allows a tool (e.g., VT) to attach without * registering the connection. * * PTHREAD_DEBUG_FLAG_NOUPDATE: * * Normally, when certain queries are made, the debug assistant may * update information in the target process. For example, one of the * thread information fields is a stack highwater mark; this data, part * of the thread control block, is updated by the assistant so that * repeated queries will return more useful information. Setting the * PTHREAD_DEBUG_FLAG_NOUPDATE on connection will prevent these updates. * * Note that setting both PASSIVE and NOUPDATE is not the same as making * a connection "read-only" by omitting the WRITE callback. The flags * just prevent the debug assistant from writing data on its own; the * client is still allowed to make calls that request modifications. * * Note also that the debug assistant will continue to rely on the * SUSPEND and RESUME callbacks, which allow "atomic" access to data in * the threaded process. The "passivity" of such a connection can be * debated, but, if the client desires truly a truly passive connection, * and is prepared to deal with the data inconsistencies, it's possible * to omit the SUSPEND and RESUME callbacks. (As OpenVMS SDA does.) * * PTHREAD_DEBUG_FLAG_UPCALLS: * * Digital UNIX two-level scheduling involves a special communication * path from the kernel out into the user-mode scheduler, called an * upcall. Although similar in some ways to signal delivery, an upcall is * something different. While the standard exc_remote_virtual_unwind * routine in libc can be used to "walk" a stack containing upcalls, any * debugger that doesn't use this routine, or have similar private logic, * will be unable to find the user program state "underneath" an upcall * frame. Because most existing debuggers do not use the standard * routine, nor have similar logic, programmers may be unable to * determine what a thread is actually doing (the stack traceback will * appear to end at the upcall). * * In order to avoid this confusion, the debug assistant, by default (and * unconditionally for debuggers using the original "v0" interface) will * "hide" upcall frames when returning (or setting) registers. Because * the debugger won't see the upcall frames, the programmer won't be * confused. There are complications involved, however, and a debugger * that can support upcall frames may wish to avoid the extra * indirection. (Also, thread library developers are extremely limited by * upcall hiding, because the debugger cannot "see" a large chunk of * thread library code.) * * An "upcall-saavy" debugger that won't be confused by upcall frames may * set PTHREAD_DEBUG_FLAG_UPCALLS to prevent the assistant from hiding * upcalls. */ typedef enum pthreadDebugInitFlag_tag { PTHREAD_DEBUG_FLAG_PASSIVE = 0x01000000, /* Limited modification */ PTHREAD_DEBUG_FLAG_NOUPDATE = 0x02000000, /* Read-only */ PTHREAD_DEBUG_FLAG_UPCALLS = 0x04000000 /* Debugger Knows Upcalls */ } pthreadDebugInitFlag_t; /* * TYPEDEFS */ /* * On OpenVMS Alpha, we specify long pointer sizes for all pointers. To make * things simple, we just compile the entire header inside an explicit long * pointer region. Since this is a private (or at least semi-private) header, * it's reasonable to require that it be compiled using a recent version of * DEC C. */ #if defined (_PTHREAD_ENV_ALPHA) && defined (_PTHREAD_ENV_VMS) # ifndef __INITIAL_POINTER_SIZE # ifdef __cplusplus # error " requires pointer size support and cannot be used under DEC C++" # else # error " requires DEC C version 5.0 or later, with pointer size support" # endif # endif # pragma __required_pointer_size __save # pragma __required_pointer_size __long #endif /* * User thread IDs, mutex IDs and condition variable IDs are all sequence * numbers assigned by the DECthreads library. Each object can be accessed by * this number. The IDs for each object are maintained on a per-object basis. * So no two objects of the same type will share an ID, but objects of * different types may. */ typedef long pthreadDebugId_t; /* * We have this type here to distinguish between IDs which describe user * threads and IDs which describe kernel threads. */ typedef void *pthreadDebugKId_t; /* * This type designates an untyped pointer (void*) that will be interpreted as * an address in the multithreaded process ("target") that is being debugged, * not within the debugger (and debug assistant) address space. * * Note, these are always 64 bit pointers on OpenVMS Alpha, and the latter is * a 64-bit pointer to a 64-bit pointer. */ typedef void *pthreadDebugTargetAddr_t, **pthreadDebugTargetAddr_p; typedef const void *pthreadDebugTargetConstAddr_t; /* * Type defining floating point and general registers. */ #if defined (_PTHREAD_ENV_ALPHA) typedef struct pthreadDebugRegs_tag { __pthreadLongUint_t r0; /* return value (v0) */ __pthreadLongUint_t r1; /* callee saved 0 (t0) */ __pthreadLongUint_t r2; /* callee saved 1 (t1) */ __pthreadLongUint_t r3; /* callee saved 2 (t2) */ __pthreadLongUint_t r4; /* callee saved 3 (t3) */ __pthreadLongUint_t r5; /* callee saved 4 (t4) */ __pthreadLongUint_t r6; /* callee saved 5 (t5) */ __pthreadLongUint_t r7; /* callee saved 6 (t6) */ __pthreadLongUint_t r8; /* callee saved 7 (t7) */ __pthreadLongUint_t r9; /* caller saved 0 (s0) */ __pthreadLongUint_t r10; /* caller saved 1 (s1) */ __pthreadLongUint_t r11; /* caller saved 2 (s2) */ __pthreadLongUint_t r12; /* caller saved 3 (s3) */ __pthreadLongUint_t r13; /* caller saved 4 (s4) */ __pthreadLongUint_t r14; /* caller saved 5 (s5) */ __pthreadLongUint_t r15; /* caller saved 6 (fp) */ __pthreadLongUint_t r16; /* argument register 0 (a0) */ __pthreadLongUint_t r17; /* argument register 1 (a1) */ __pthreadLongUint_t r18; /* argument register 2 (a2) */ __pthreadLongUint_t r19; /* argument register 3 (a3) */ __pthreadLongUint_t r20; /* argument register 4 (a4) */ __pthreadLongUint_t r21; /* argument register 5 (a5) */ __pthreadLongUint_t r22; /* callee saved 8 (t8) */ __pthreadLongUint_t r23; /* callee saved 9 (t9) */ __pthreadLongUint_t r24; /* callee saved 10 (t10) */ __pthreadLongUint_t r25; /* callee saved 11 (t11) */ __pthreadLongUint_t r26; /* return address (ra) */ __pthreadLongUint_t r27; /* callee saved 12 (t12) */ __pthreadLongUint_t r28; /* assembler temp (at) */ __pthreadLongUint_t r29; /* global pointer (gp) */ __pthreadLongUint_t r30; /* stack pointer (sp) */ __pthreadLongUint_t pc; /* user-mode PC */ __pthreadLongUint_t ps; /* processor status */ } pthreadDebugRegs_t, *pthreadDebugRegs_p; typedef __pthreadLongUint_t pthreadDebugRegsArray_t[33]; /* Array version */ typedef struct pthreadDebugFregs_tag { __pthreadLongUint_t f0; /* f0 return value */ __pthreadLongUint_t f1; /* f1 return value (complex) */ __pthreadLongUint_t f2; /* callee saved 1 */ __pthreadLongUint_t f3; /* callee saved 2 */ __pthreadLongUint_t f4; /* callee saved 3 */ __pthreadLongUint_t f5; /* callee saved 4 */ __pthreadLongUint_t f6; /* callee saved 5 */ __pthreadLongUint_t f7; /* callee saved 6 */ __pthreadLongUint_t f8; /* callee saved 7 */ __pthreadLongUint_t f9; /* caller saved 8 */ __pthreadLongUint_t f10; /* caller saved 0 */ __pthreadLongUint_t f11; /* caller saved 1 */ __pthreadLongUint_t f12; /* caller saved 2 */ __pthreadLongUint_t f13; /* caller saved 3 */ __pthreadLongUint_t f14; /* caller saved 4 */ __pthreadLongUint_t f15; /* caller saved 5 */ __pthreadLongUint_t f16; /* argument register 0 */ __pthreadLongUint_t f17; /* argument register 1 */ __pthreadLongUint_t f18; /* argument register 2 */ __pthreadLongUint_t f19; /* argument register 3 */ __pthreadLongUint_t f20; /* argument register 4 */ __pthreadLongUint_t f21; /* argument register 5 */ __pthreadLongUint_t f22; /* caller saved 6 */ __pthreadLongUint_t f23; /* caller saved 7 */ __pthreadLongUint_t f24; /* caller saved 8 */ __pthreadLongUint_t f25; /* caller saved 9 */ __pthreadLongUint_t f26; /* caller saved 10 */ __pthreadLongUint_t f27; /* caller saved 11 */ __pthreadLongUint_t f28; /* caller saved 12 */ __pthreadLongUint_t f29; /* caller saved 13 */ __pthreadLongUint_t f30; /* caller saved 14 */ __pthreadLongUint_t fpcr; /* FP status register */ __pthreadLongUint_t fp_control; /* IEEE fp control state */ } pthreadDebugFregs_t, *pthreadDebugFregs_p; typedef __pthreadLongUint_t pthreadDebugFregsArray_t[33]; /* Array version */ #elif defined (_PTHREAD_ENV_IA64) # include #elif defined (_PTHREAD_ENV_VAX) typedef struct pthreadDebugRegs_tag { int r0; /* R0 */ int r1; /* R1 */ int r2; /* R2 */ int r3; /* R3 */ int r4; /* R4 */ int r5; /* R5 */ int r6; /* R6 */ int r7; /* R7 */ int r8; /* R8 */ int r9; /* R9 */ int r10; /* R10 */ int r11; /* R11 */ int r12; /* R12 (AP) */ int r13; /* R13 (FP) */ int r14; /* R14 (SP) */ int pc; /* R15 (PC) */ int psw; /* processor status */ } pthreadDebugRegs_t, *pthreadDebugRegs_p; typedef pthreadDebugRegs_t pthreadDebugFregs_t, *pthreadDebugFregs_p; typedef int pthreadDebugRegsArray_t[17]; /* Array version */ #elif defined (_PTHREAD_ENV_X86) typedef struct pthreadDebugRegs_tag { DWORD EAX; /* DS(default) - 32bit - data register */ DWORD EBX; /* DS(default) - 32bit - data register */ DWORD ECX; /* DS(default) - 32bit - data register */ DWORD EDX; /* DS(default) - 32bit - data register */ DWORD EBP; /* SS(default) - 32bit - stack frame base */ DWORD ESI; /* DS(default) - 32bit - data register */ DWORD EDI; /* ES(default) - 32bit - data register */ DWORD ESP; /* SS(default) - 32bit - stack frame pointer */ DWORD CS; /* 16bit - code segment selector */ DWORD SS; /* 16bit - stack segment selector */ DWORD DS; /* 16bit - main data segment selector */ DWORD ES; /* 16bit - string/data segment selector */ DWORD FS; /* 16bit - optional data segment selector */ DWORD GS; /* 16bit - optional data segment selector */ DWORD EFLAGS; /* 32bit - condition/mode flags register */ DWORD EIP; /* CS - 32bit - instruction pointer */ } pthreadDebugRegs_t, *pthreadDebugRegs_p; typedef pthreadDebugRegs_t pthreadDebugFregs_t, *pthreadDebugFregs_p; typedef DWORD pthreadDebugRegsArray_t[16]; /* Array version */ typedef DWORD pthreadDebugFregsArray_t[16]; /* Array version */ #else # error " cannot be used in this environment" #endif /* * Debug assistant context type. This opaque value is returned by the * pthreadDebugContextInit() routine. */ typedef void* pthreadDebugContext_t; typedef void** pthreadDebugContext_p; /* * Debug assistant time type. This structure is actually the same size * as a struct timespec but it has 64 bits for the seconds when the * timespec structure has only 32 under Tru64 Unix Alpha. For OpenVMS, both * fields remain as two 32 bit entities. */ typedef struct pthreadDebugTimespec_tag { long tv_sec; unsigned long tv_nsec; } pthreadDebugTimespec_t, *pthreadDebugTimespec_p; /* * "Caller context" argument. A value of this type is specified when creating * a new debug context with pthreadDebugContextInit, and is passed by the * assistant to each client callback routine. */ typedef void* pthreadDebugClient_t; /* * Type defining "special thread" codes (SPECKTHD callback) * * CURRENT The thread being observed. (Debuggers usually have * commands to switch between threads, for example, to * see the stack and registers of various threads.) * TRAP The thread that caused the most recent debugging * event -- breakpoint, hardware fault, etc. */ typedef enum pthreadDebugSpecialType_tag { PTHREAD_DEBUG_SPECIAL_TYPE_CURRENT = 1, /* Thread being observed */ PTHREAD_DEBUG_SPECIAL_TYPE_TRAP = 2 /* Thread that trapped */ } pthreadDebugSpecialType_t; /* * Type defining thread state. * * UNKNOWN The state can't be determined. (This should never * happen.) * RUNNING Thread is currently executing on some processor. * READY Thread is not currently running, but is eligible to * run when a processor becomes available. * BLOCKED Thread is waiting for some event (beyond its control) * to occur before it can run. The SUBSTATE provides * details about why it is waiting. * NEW A transitional state -- a newly created thread that * hasn't yet been made READY. * SORTING Another transitional -- the thread has been removed * from a ready queue briefly for some internal * bookkeeping operation, and will shortly be made READY * again. * TERMINATED The thread is no longer running, but has not yet * been DETACHED. * ZOMBIE A transitional state -- the thread has terminated, and * been detached, but all resources haven't yet been * disposed. */ typedef enum pthreadDebugState_tag { PTHREAD_DEBUG_STATE_UNKNOWN = 0, /* Unknown (bad) state */ PTHREAD_DEBUG_STATE_RUNNING = 1, /* Running on kernel thread */ PTHREAD_DEBUG_STATE_READY = 2, /* Ready to run */ PTHREAD_DEBUG_STATE_BLOCKED = 3, /* Blocked on some object */ PTHREAD_DEBUG_STATE_NEW = 4, /* Just created not readied */ PTHREAD_DEBUG_STATE_SORTING = 5, /* Sort scheduler database */ PTHREAD_DEBUG_STATE_TERMINATED = 6, /* Not eligible to run */ PTHREAD_DEBUG_STATE_ZOMBIE = 7 /* Waiting to be reclaimed */ } pthreadDebugState_t; /* * Type defining thread substate. For example, if the state is blocked, * substate gives additional information about current state or recent * transition. */ typedef enum pthreadDebugSubstate_tag { PTHREAD_DEBUG_SUBSTATE_UNKNOWN = 0, /* Unknown (bad) substate */ PTHREAD_DEBUG_SUBSTATE_NORMAL = 1, /* No additional information */ PTHREAD_DEBUG_SUBSTATE_UNBLOCK_PEND = 2, /* Kernel unblock pending */ PTHREAD_DEBUG_SUBSTATE_KERNEL = 3, /* Blocked in the kernel */ PTHREAD_DEBUG_SUBSTATE_MUTEX = 4, /* Blocked on a mutex */ PTHREAD_DEBUG_SUBSTATE_CV = 5, /* Blocked on a cv */ PTHREAD_DEBUG_SUBSTATE_TIMED_CV = 6, /* Blocked on a timed cv */ PTHREAD_DEBUG_SUBSTATE_TERM_CANCEL = 7, /* Terminating from a cancel */ PTHREAD_DEBUG_SUBSTATE_TERM_EXIT = 8, /* Terminating normally */ PTHREAD_DEBUG_SUBSTATE_DELAY = 9, /* Blocked for a delay */ PTHREAD_DEBUG_SUBSTATE_JOIN = 10, /* Blocked for a join */ PTHREAD_DEBUG_SUBSTATE_START = 11, /* Thread just started */ PTHREAD_DEBUG_SUBSTATE_SYNCSUSP = 12, /* Waiting for suspend */ PTHREAD_DEBUG_SUBSTATE_READLOCK = 13, /* Thread is wating on rdlock */ PTHREAD_DEBUG_SUBSTATE_WRITELOCK = 14 /* Thread is wating on wrlock */ } pthreadDebugSubstate_t; /* * Type defining thread "kinds". All threads created by a program through * DECthreads interfaces are of kind NORMAL. A debugger should usually show * threads of other kinds only when a special switch or mode is used (e.g., * pthread_debug's "thread -a".) */ typedef enum pthreadDebugThreadKind_tag { PTHREAD_DEBUG_THD_KIND_INITIAL = 1, /* Initial thread */ PTHREAD_DEBUG_THD_KIND_NORMAL = 2, /* Normal thread */ PTHREAD_DEBUG_THD_KIND_NULL = 3, /* DECthreads null thread */ PTHREAD_DEBUG_THD_KIND_MGR = 4, /* DECthreads manager thread */ PTHREAD_DEBUG_THD_KIND_FOREIGN = 5, /* A non-DECthreads NT thread */ PTHREAD_DEBUG_THD_KIND_EXITHAND = 6 /* The exit handler thread */ } pthreadDebugThreadKind_t; /* * Type defining the possible thread creators. You can use this information to * determine whether the thread was created using the POSIX interface, one of * the (retired) DCE thread interfaces, or the (obsolete) CMA interface. */ typedef enum pthreadDebugThreadCreator_tag { PTHREAD_DEBUG_THD_CREATOR_POSIX = 1, PTHREAD_DEBUG_THD_CREATOR_CMA = 2, PTHREAD_DEBUG_THD_CREATOR_DCE = 3, PTHREAD_DEBUG_THD_CREATOR_DCEEXC = 4, PTHREAD_DEBUG_THD_CREATOR_TIS = 5 } pthreadDebugThreadCreator_t; /* * Definitions for user mode and kernel mode blocking information. */ typedef enum pthreadDebugThdBlkType_tag { PTHREAD_DEBUG_THDBLK_BADVALUE = 0, /* Unknown, N/A */ PTHREAD_DEBUG_THDBLK_NONE = 1, /* No blocking state */ PTHREAD_DEBUG_THDBLK_MUTEX = 2, /* Mutex blocks */ PTHREAD_DEBUG_THDBLK_COND = 3, /* Condition variable blocks */ PTHREAD_DEBUG_THDBLK_DELAY = 4, /* pthread_delay_np */ PTHREAD_DEBUG_THDBLK_RWL = 5, /* Readers/Writer lock blocks */ PTHREAD_DEBUG_THDBLK_JOIN = 6, /* Join waits */ PTHREAD_DEBUG_THDBLK_SUSPSYNC = 7, /* Suspend waits */ PTHREAD_DEBUG_THDBLK_KERNEL = 8 /* Kernel block */ } pthreadDebugThdBlkType_t; #ifdef _PTHREAD_ENV_UNIX # define PTHREAD_DEBUG_KRNBFLG_FAULT 0x00000001 /* Pagefault */ # define PTHREAD_DEBUG_KRNBFLG_SYSCALL 0x00000002 /* Syscall */ typedef struct pthreadDebugThdKrnBlk_tag { pthreadDebugThdBlkType_t type; /* Union descriminator */ long flags; /* Blocking flags */ long habitat; /* Habitat (if SYSCALL) */ long syscall; /* Syscall (if SYSCALL) */ pthreadDebugTargetAddr_t va; /* Pagefault VA (if FAULT) */ char habitat_nm[8]; /* Habitat name (not hab 0) */ char syscall_nm[24]; /* Syscall name (if SYSCALL) */ } pthreadDebugThdKrnBlk_t, *pthreadDebugThdKrnBlk_p; #elif defined (_PTHREAD_ENV_VMS) # define PTHREAD_DEBUG_KRNBFLG_WFLAND 0x00000001 /* SYS$WFLAND */ # define PTHREAD_DEBUG_KRNBFLG_COLLIDED 0x00000002 /* PFW collided */ typedef enum pthreadDebugKrnBlkType_tag { PTHREAD_DEBUG_KRNBLKTYPE_UNKNOWN = 0, /* Undefined */ PTHREAD_DEBUG_KRNBLKTYPE_NONE = 1, /* No blocking state */ PTHREAD_DEBUG_KRNBLKTYPE_SYNC = 2, /* $SYNC */ PTHREAD_DEBUG_KRNBLKTYPE_WFL = 3, /* Event flag wait */ PTHREAD_DEBUG_KRNBLKTYPE_HIBER = 4, /* $HIBER */ PTHREAD_DEBUG_KRNBLKTYPE_IMS = 5, /* Inner-mode semaphore */ PTHREAD_DEBUG_KRNBLKTYPE_PFW = 6 /* Pagefault wait */ } pthreadDebugKrnBlkType_t; typedef struct pthreadDebugThdKrnBlk_tag { pthreadDebugThdBlkType_t type; /* Union descriminator */ long flags; /* Flags */ pthreadDebugKrnBlkType_t ktype; /* Type of kernel block */ union { struct { unsigned short *iosb; /* IOSB (SYNC only) */ int efn; /* Event flag (SYNC only) */ } sync; unsigned int mask[2]; /* Wait mask (WFL only) */ unsigned long seq; /* Sequence # (IMS only) */ __pthreadLongUint_t va; /* Address (PFW only) */ } detail; } pthreadDebugThdKrnBlk_t, *pthreadDebugThdKrnBlk_p; #else typedef struct pthreadDebugThdKrnBlk_tag { pthreadDebugThdBlkType_t type; /* Union descriminator */ long flags; /* Blocking flags */ } pthreadDebugThdKrnBlk_t, *pthreadDebugThdKrnBlk_p; #endif /* * Information about the blocking state of a thread. */ typedef union pthreadDebugThdBlkInfo_tag { pthreadDebugThdBlkType_t type; /* Union descriminator */ struct { pthreadDebugThdBlkType_t type; /* Union descriminator */ pthreadDebugId_t mutex; /* Mutex */ } mutex; struct { pthreadDebugThdBlkType_t type; /* Union descriminator */ pthreadDebugId_t cond; /* Condition variable */ pthreadDebugId_t mutex; /* Associated mutex */ pthreadDebugTimespec_t timeout;/* Timeout */ } cond; struct { pthreadDebugThdBlkType_t type; /* Union descriminator */ pthreadDebugTimespec_t timeout;/* Timeout */ } delay; struct { pthreadDebugThdBlkType_t type; /* Union descriminator */ pthreadDebugId_t rwlock; /* read-write lock */ } rwlock; struct { pthreadDebugThdBlkType_t type; /* Union descriminator */ pthreadDebugId_t thread; /* Join thread */ } join; struct { pthreadDebugThdBlkType_t type; /* Union descriminator */ pthreadDebugId_t thread; /* suspending thread */ } suspsync; pthreadDebugThdKrnBlk_t kernel; /* O/S-specific kernel blocking info */ } pthreadDebugThdBlkInfo_t, *pthreadDebugThdBlkInfo_p; /* * Type defining information returned about a thread. * * NOTES: * * 1) The "sequence" field is traditionally reported as a signed number when * the PTHREAD_DEBUG_THD_INTERNAL flag is set, even though the sequence * number is unsigned. * 2) Even when the state is "RUNNING", the thread may have a substate of * "MUTEX", "CV", "TIMED_CV", etc. In such case, the "condition" and/or * "mutex" fields (Id of the synchronization object on which the thread is * waiting) MAY or MAY NOT be non-zero. This situation means that the * thread is "about to wait" or "in the process of waking". * 3) The "locks" field can count only the non-default mutex types held by the * thread -- recursive or errorcheck mutexes, pshared mutexes, and priority * inheritance or priority ceiling mutexes. The thread may additionally * hold any number of default (NORMAL) mutexes. * 4) If the stack was created with a user specified stack ("stackaddr" * attribute), the PTHREAD_DEBUG_THD_STACKADDR flag will be set. In this * case, all of the thread's stack information fields, except stack_base * and stack_hiwater, are guesses, and probably inaccurate. You shouldn't, * for example, compare stack_hiwater against stack_reserve to check for * stack overflows. If the stacksize attribute has also been modified in * the attributes object, DECthreads will guess that the creator intended * that as the size of the user stack. Because the standard does not * specify any such relationship, this is still an unreliable guess. * (There's no specific indication that both stackaddr and stacksize were * set. However, if DECthreads must guess, we guess PTHREAD_STACK_MIN. So * it's reasonable for you to guess that, if the stacksize of a user stack * isn't PTHREAD_STACK_MIN, the user also specified a stacksize.) * * However, if the flag PTHREAD_DEBUG_THD_ESTACKADDR is also set, then the * "extended stackaddr" interface, pthread_setstackaddr_np, was used, which * allows the caller to specify the size and base address. In this case, * all stack information may be considered valid. */ #define PTHREAD_DEBUG_THD_CANCEL 0x00000001 /* Cancel pending */ #define PTHREAD_DEBUG_THD_CAN_ENABLED 0x00000002 /* Cancel enabled */ #define PTHREAD_DEBUG_THD_CAN_ASYNC 0x00000004 /* Async cancel enabled */ #define PTHREAD_DEBUG_THD_CAN_SYSTEM 0x00000008 /* System cancel enabled */ #define PTHREAD_DEBUG_THD_NAME 0x00000010 /* Name != "" */ #define PTHREAD_DEBUG_THD_SYS_SCOPE 0x00000020 /* System contention scope */ #define PTHREAD_DEBUG_THD_INTERNAL 0x00000040 /* DECthreads internal */ #define PTHREAD_DEBUG_THD_HOLD 0x00000080 /* Thread is HELD */ #define PTHREAD_DEBUG_THD_SUSPEND 0x00000100 /* Thread is SUSPENDED */ #define PTHREAD_DEBUG_THD_JOINER 0x00000200 /* A thread is joining */ #define PTHREAD_DEBUG_THD_STACKADDR 0x00000400 /* User stack */ #define PTHREAD_DEBUG_THD_ESTACKADDR 0x00000800 /* User stack with size */ #define PTHREAD_DEBUG_THD_DETACH 0x00001000 /* Thread is detached */ typedef struct pthreadDebugThreadInfo_tag { unsigned long flags; /* PTHREAD_DEBUG_THD_ flags */ pthreadDebugState_t state; /* Current scheduler state */ pthreadDebugSubstate_t substate; /* Current scheduler substate */ pthreadDebugThreadKind_t kind; /* Kind of thread */ pthreadDebugThreadCreator_t creator;/* The creating interface */ int sched_policy; /* Thread's scheduling policy */ int base_priority; /* Thread's (base) priority */ int cur_priority; /* Thread's (current) priority */ pthreadDebugId_t sequence; /* Sequence number */ pthread_t teb; /* Pointer to thread's TEB */ pthread_t *handle; /* "Handle" (where pthread_create stored the TEB pointer) */ pthreadDebugTargetAddr_t stack_base;/* Base of thread's stack */ pthreadDebugTargetAddr_t stack_reserve;/* First byte of reserved zone */ pthreadDebugTargetAddr_t stack_yellow;/* First byte of yellow zone */ pthreadDebugTargetAddr_t stack_guard;/* First byte of guard zone */ pthreadDebugTargetAddr_t stack_hiwater;/* Stack's "highwater mark" */ unsigned long stack_size; /* Total size of stack */ pthreadDebugThdBlkInfo_t block; /* Detailed blocking info */ void *(*start)(void*); /* Thread start rtn */ pthreadDebugTargetAddr_t start_arg; /* Thread start arg */ pthreadDebugTargetAddr_t result; /* TERMINATED: Thread result */ pthreadDebugTimespec_t cpu_time; /* Accumulated CPU time (nyi) */ unsigned long sig_block; /* Blocked signal mask (UNIX only) */ unsigned long sig_pend; /* Pending signal mask (UNIX only) */ int locks; /* Number of owned locks (if known) */ int thd_errno; /* Last known errno */ char name[32]; /* Thread's name */ } pthreadDebugThreadInfo_t, *pthreadDebugThreadInfo_p; /* * Type defining information returned about a kernel thread. The flags * are set by the callback to specify which fields are valid, in case some * information is unavailable (e.g., from a core file). Note that STATE and * TEB are always required. */ #define PTHREAD_DEBUG_KTD_POLICY 0x00000001 /* sched_policy valid */ #define PTHREAD_DEBUG_KTD_BPRIO 0x00000002 /* base_priority valid */ #define PTHREAD_DEBUG_KTD_CPRIO 0x00000004 /* cur_priority valid */ #define PTHREAD_DEBUG_KTD_SUSPCNT 0x00000008 /* suspend_count valid */ #define PTHREAD_DEBUG_KTD_SIGBLK 0x00000010 /* sig_block valid */ #define PTHREAD_DEBUG_KTD_SIGPND 0x00000020 /* sig_pend valid */ #define PTHREAD_DEBUG_KTD_SLEEP 0x00000040 /* sleep_time valid */ #define PTHREAD_DEBUG_KTD_WAIT 0x00000080 /* wait_event valid */ #define PTHREAD_DEBUG_KTD_USER 0x00000100 /* user_time valid */ #define PTHREAD_DEBUG_KTD_SYSTEM 0x00000200 /* system_time valid */ #define PTHREAD_DEBUG_KTD_SCHCLS 0x00000400 /* sched_class valid */ #ifdef _PTHREAD_ENV_UNIX typedef enum pthreadDebugKState_tag { PTHREAD_DEBUG_KSTATE_UNKNOWN = 0, /* Unknown (bad) state */ PTHREAD_DEBUG_KSTATE_RUNNING = 1, /* Running */ PTHREAD_DEBUG_KSTATE_STOPPED = 2, /* Stopped */ PTHREAD_DEBUG_KSTATE_WAITING = 3, /* Waiting normally */ PTHREAD_DEBUG_KSTATE_UINT_WAITING = 4, /* Uninterruptible wait */ PTHREAD_DEBUG_KSTATE_HALTED = 5 /* Halted cleanly */ } pthreadDebugKState_t; typedef struct pthreadDebugKThreadInfo_tag { unsigned long flags; /* Miscellaneous flags */ pthreadDebugKState_t state; /* Current scheduler state */ pthread_t teb; /* Current user thread TEB */ int sched_policy; /* Thread scheduling policy */ int base_priority; /* Thread base priority */ int cur_priority; /* Thread current priority */ int suspend_count; /* Mach suspend count */ sigset_t sig_block; /* Current blocked signals */ sigset_t sig_pend; /* Current pending signals */ long sleep_time; /* Second thread has been sleeping */ long wait_event; /* Event on which thread is waiting */ pthreadDebugTimespec_t user_time; /* Accumulated user CPU time */ pthreadDebugTimespec_t system_time; /* Accumulated system CPU time */ char sched_class[8]; /* Scheduling class name */ long reserved[10]; /* Expansion space */ } pthreadDebugKThreadInfo_t, *pthreadDebugKThreadInfo_p; #else /* * FIX-ME: Don't take this too literally yet. */ typedef enum pthreadDebugKState_tag { PTHREAD_DEBUG_KSTATE_RUNNING = 1, /* Running */ PTHREAD_DEBUG_KSTATE_STOPPED = 2, /* Stopped */ PTHREAD_DEBUG_KSTATE_WAITING = 3 /* Waiting normally */ } pthreadDebugKState_t; typedef struct pthreadDebugKThreadInfo_tag { unsigned long flags; /* Miscellaneous flags */ pthreadDebugKState_t state; /* Current scheduler state */ int sched_policy; /* Thread scheduling policy */ int base_priority; /* Thread base priority */ int cur_priority; /* Thread current priority */ long wait_event; /* Event on which thread is waiting */ pthread_t teb; /* Current user thread TEB */ pthreadDebugTimespec_t user_time; /* Accumulated user CPU time */ pthreadDebugTimespec_t system_time; /* Accumulated system CPU time */ char sched_class[8]; /* Scheduling class name */ long reserved[10]; /* Expansion space */ char name[32]; /* Thread's name */ } pthreadDebugKThreadInfo_t, *pthreadDebugKThreadInfo_p; #endif typedef enum pthreadDebugMutexType_tag { PTHREAD_DEBUG_MUT_TYPE_NORMAL = 1, /* Normal mutex */ PTHREAD_DEBUG_MUT_TYPE_RECURSIVE = 2, /* Recursive mutex */ PTHREAD_DEBUG_MUT_TYPE_ERRORCHECK = 3 /* Error-check mutex */ } pthreadDebugMutexType_t; typedef enum pthreadDebugMutexProtocol_tag { PTHREAD_DEBUG_MUT_PROTO_NONE = 1, /* Normal */ PTHREAD_DEBUG_MUT_PROTO_PROTECT = 2, /* Priority ceiling */ PTHREAD_DEBUG_MUT_PROTO_INHERIT = 3 /* Priority inheritance */ } pthreadDebugMutexProtocol_t; /* * Type defining information returned about a mutex. * * NOTES: * * 1) When a mutex is STATICALLY initialized using PTHREAD_MUTEX_INITIALIZER * (or equivalent) and has not yet been used to BLOCK a thread, the mutex * does not have a sequence number. It is not visible in a * pthreadDebugMutSeq* traversal, or to pthreadDebugMutGetInfo, and its * name cannot be set using pthreadDebugMutSetName. In this case, the * "sequence" member of the pthreadDebugMutexInfo_t structure will have the * value 0. The value 0 is never a valid sequence number, so there is no * ambiguity. You can only examine the state of these mutexes using * pthreadDebugMutGetInfoAddr. */ #define PTHREAD_DEBUG_MUT_NAME 0x00000001 /* Name != "" */ #define PTHREAD_DEBUG_MUT_LOCKED 0x00000002 /* Currently locked */ #define PTHREAD_DEBUG_MUT_WAITERS 0x00000004 /* There are waiters */ #define PTHREAD_DEBUG_MUT_METERED 0x00000008 /* Mutex has meter info */ #define PTHREAD_DEBUG_MUT_INTERNAL 0x00000010 /* DECthreads internal */ #define PTHREAD_DEBUG_MUT_PSHARED 0x00000020 /* "Process shared" */ #define PTHREAD_DEBUG_MUT_TRACED 0x00000040 /* Mutex is traced */ typedef struct pthreadDebugMutexInfo_tag { unsigned long flags; /* Miscellaneous flags */ pthreadDebugMutexType_t type; /* Mutex type */ pthreadDebugId_t owner; /* Current owner (if known) */ pthreadDebugId_t sequence; /* Sequence number */ pthread_mutex_t *address; /* Mutex address */ unsigned int depth; /* Recursive lock depth */ pthreadDebugMutexProtocol_t protocol; /* Mutex protocol (nyi) */ int prioceiling; /* Priority ceiling (nyi) */ int priority; /* Current priority (nyi) */ char name[32]; /* Mutex name */ } pthreadDebugMutexInfo_t, *pthreadDebugMutexInfo_p; /* * Type defining information returned about a rwlock. * * NOTES: * * 1) When a rwlock is STATICALLY initialized using PTHREAD_RWLOCK_INITIALIZER * (or equivalent) and has not yet been used to BLOCK a thread, the rwlock * does not have a sequence number. It is not visible in a * pthreadDebugRwSeq* traversal, or to pthreadDebugRwGetInfo, and its * name cannot be set using pthreadDebugRwSetName. In this case, the * "sequence" member of the pthreadDebugRwlockInfo_t structure will have the * value 0. The value 0 is never a valid sequence number, so there is no * ambiguity. You can only examine the state of these rwlockes using * pthreadDebugRwGetInfoAddr. */ #define PTHREAD_DEBUG_RW_NAME 0x00000001 /* Name != "" */ #define PTHREAD_DEBUG_RW_RDLOCKED 0x00000002 /* Currently rdlocked */ #define PTHREAD_DEBUG_RW_WRLOCKED 0x00000004 /* Currently wrlocked */ #define PTHREAD_DEBUG_RW_RWAITERS 0x00000008 /* Waiting readers */ #define PTHREAD_DEBUG_RW_WWAITERS 0x00000010 /* Waiting writers */ #define PTHREAD_DEBUG_RW_INTERNAL 0x00000020 /* DECthreads internal */ #define PTHREAD_DEBUG_RW_PSHARED 0x00000040 /* "Process shared" */ typedef struct pthreadDebugRwlockInfo_tag { unsigned long flags; /* Miscellaneous flags */ pthreadDebugId_t sequence; /* Sequence number */ pthread_rwlock_t *address; /* Rwlock address */ pthreadDebugId_t wrid; /* Write owner (if any) */ unsigned long rcount; /* Reader count */ char name[32]; /* Rwlock name */ } pthreadDebugRwlockInfo_t, *pthreadDebugRwlockInfo_p; /* * Type defining information returned about a condition variable. * * NOTES: * * 1) When a condition variable is STATICALLY initialized using * PTHREAD_COND_INITIALIZER (or equivalent) and has not yet been used to * BLOCK a thread, the condition variable does not have a sequence * number. It is not visible in a pthreadDebugCondSeq* traversal, or to * pthreadDebugCondGetInfo, and its name cannot be set using * pthreadDebugCondSetName. In this case, the "sequence" member of the * pthreadDebugCondInfo_t structure will have the value 0. The value 0 is * never a valid sequence number, so there is no ambiguity. You can only * examine the state of these mutexes using pthreadDebugCondGetInfoAddr. */ #define PTHREAD_DEBUG_COND_NAME 0x00000001 /* Name != "" */ #define PTHREAD_DEBUG_COND_PEND 0x00000002 /* Pending wake (sig_int) */ #define PTHREAD_DEBUG_COND_WAITERS 0x00000004 /* There are waiters */ #define PTHREAD_DEBUG_COND_METERED 0x00000008 /* CV has meter info */ #define PTHREAD_DEBUG_COND_INTERNAL 0x00000010 /* DECthreads internal */ #define PTHREAD_DEBUG_COND_PSHARED 0x00000020 /* "Process shared" */ #define PTHREAD_DEBUG_COND_TRACED 0x00000040 /* CV is traced */ typedef struct pthreadDebugCondInfo_tag { unsigned long flags; /* Miscellaneous flags */ pthreadDebugId_t sequence; /* Sequence number */ pthread_cond_t *address; /* Condition address */ pthreadDebugId_t mutex; /* Associated mutex (if waiters) */ long reserved[10]; /* Expansion space */ char name[32]; /* Condition name */ } pthreadDebugCondInfo_t, *pthreadDebugCondInfo_p; /* * Type defining information returned about a thread specific data key. * * NOTES: * * 1) EXTENDED tsd keys have additional semantics. In particular, they may * have a constructor routine (called at thread startup) as well as a * destructor routine (called at thread termination). * 2) EXTENDED tsd key destructor routines are called with additional * arguments: as well as the current value of the tsd key in that thread, * they receive the thread ID (pthread_t) and the tsd key itself. * 3) EXTENDED tsd keys can be created with the PTHREAD_KEY_ALLTHREAD_NP * flag. The constructor (if any) will immediately be run for each thread * that currently exists. Similarly, when the key is destroyed the * destructor will immediately be run for each thread. Note that the * constructor and destructor are, in these cases, run in the context of * the thread creating or destroying the key, NOT in the context of the * various threads -- thus the constructor and destructor must be carefully * constructed (which is why the behavior is an option). * * NOTE: Currently, EXTENDED tsd keys are reserved for use by the Digital UNIX * loader, in implementing THREAD LOCAL STORAGE. (cc's __declspec(thread).) */ #define PTHREAD_DEBUG_TSD_NAME 0x00000001 /* Name != "" */ #define PTHREAD_DEBUG_TSD_RESERVED 0x00000002 /* DECthreads reserved */ #define PTHREAD_DEBUG_TSD_ALLTHREAD 0x00000004 /* Const/Dest in all thds */ #define PTHREAD_DEBUG_TSD_EXTENDED 0x00000008 /* Extended (TLS) key */ typedef struct pthreadDebugTsdInfo_tag { unsigned long flags; /* Miscellaneous flags */ pthread_key_t key; /* Key value */ pthread_key_t *address; /* Where the key was stored */ __pthreadConstructor_t constructor; /* Constructor routine */ union { /* Destructor routine */ __pthreadDestructor_t standard; __pthreadExtDestructor_t extended; } destructor; char name[32]; /* key's name */ } pthreadDebugTsdInfo_t, *pthreadDebugTsdInfo_p; /* * CALLBACK PROTOTYPES * * Typedefs for "callback routines" that the debug client must provide to the * debug assistant library. The set of callbacks is provided to * pthreadDebugContextInit via the pthreadDebugCallbacks_t structure. */ /* * GETMEM: Typedef for routine to read a block of memory from target process. * * Arguments: * * caller_context The caller's context argument * address Address of target memory * buffer Local address to write memory * size Size of buffer * * Return value: * * 0 succeeded * EINVAL invalid address */ typedef int (*pthreadDebugGetMemRtn_t) ( pthreadDebugClient_t, pthreadDebugTargetAddr_t, __pthreadLongAddr_t, size_t); /* * SETMEM: Typedef for routine to write a block of memory to target process * * Arguments: * * caller_context The caller's context argument * address Address of target memory * buffer Local address to read memory * size Size of buffer * * Return value: * * 0 success * EINVAL invalid address * ENOSYS Not supported. */ typedef int (*pthreadDebugSetMemRtn_t) ( pthreadDebugClient_t, pthreadDebugTargetAddr_t, __pthreadLongConstAddr_t, size_t); /* * SUSPEND: Typedef for routine to suspend all threads in the target process. * * Suspension should be "counted" -- that is, when multiple calls to suspend * are made, the process should not be resumed until an equal number of calls * to resume have been made. If the underlying suspend/resume mechanism does * not have this property, the callback should implement a count and employ * the underlying mechanism only when the first suspend or last matching * resume request is made. * * Arguments: * * caller_context The caller's context argument * * Return value: * * 0 success * ENOSYS Not supported. */ typedef int (*pthreadDebugSuspendRtn_t) (pthreadDebugClient_t); /* * RESUME: Typedef for routine to resume all threads in the target process. * * Suspension should be "counted" -- that is, when multiple calls to suspend * are made, the process should not be resumed until an equal number of calls * to resume have been made. If the underlying suspend/resume mechanism does * not have this property, the callback should implement a count and employ * the underlying mechanism only when the first suspend or last matching * resume request is made. * * Arguments: * * caller_context The caller's context argument * * Return value: * * 0 Success * ENOSYS Not supported. */ typedef int (*pthreadDebugResumeRtn_t) (pthreadDebugClient_t); /* * KTHDINFO: Typedef for routine to get state information on a kernel thread. * * Arguments: * * caller_context The caller's context argument * thread_id Kernel thread (port) ID * thread_info Kernel thread info struct * * Return value: * * 0 Success * ESRCH ID is invalid * ENOSYS Not supported. */ typedef int (*pthreadDebugKthdInfoRtn_t) ( pthreadDebugClient_t, pthreadDebugKId_t, pthreadDebugKThreadInfo_p); /* * HOLD: Typedef for routine to prevent the kernel thread from running until * further notice. * * Arguments: * * caller_context The caller's context argument * thread_id Kernel thread ID * * Return value: * * 0 Success * ESRCH ID is invalid * ENOSYS Not supported. */ typedef int (*pthreadDebugHoldRtn_t) ( pthreadDebugClient_t, pthreadDebugKId_t); /* * UNHOLD: Typedef for routine to release a kernel thread that is held * * Arguments: * * caller_context The caller's context argument * thread_id kernel thread ID * * Return value: * * 0 success * ESRCH invalid thread_id * ENOSYS Not supported. */ typedef int (*pthreadDebugUnholdRtn_t) ( pthreadDebugClient_t, pthreadDebugKId_t); /* * GETFREG: Typedef for routine to get floating point register contents * * Arguments: * * caller_context The caller's context argument * fp_registers register value structure * thread_id kernel thread ID * * Return value: * * 0 success * ESRCH invalid thread_id * ENOSYS Not supported. */ typedef int (*pthreadDebugGetFregRtn_t) ( pthreadDebugClient_t, pthreadDebugFregs_p, pthreadDebugKId_t); /* * SETFREG: Typedef for routine to set floating point register contents * * Arguments: * * caller_context The caller's context argument * fp_registers register value structure * thread_id kernel thread ID * * Return value: * * 0 success * ESRCH invalid thread_id * ENOSYS Not supported. */ typedef int (*pthreadDebugSetFregRtn_t) ( pthreadDebugClient_t, const pthreadDebugFregs_t *, pthreadDebugKId_t); /* * GETREG: Typedef for routine to get general register contents * * Arguments: * * caller_context The caller's context argument * registers register value structure * thread_id kernel thread ID * * Return value: * * 0 success * ESRCH invalid thread_id */ typedef int (*pthreadDebugGetRegRtn_t) ( pthreadDebugClient_t, pthreadDebugRegs_p, pthreadDebugKId_t); /* * SETREG: Typedef for routine to set general register contents * * Arguments: * * caller_context The caller's context argument * registers register value structure * thread_id kernel thread ID * * Return value: * * 0 success * ESRCH invalid thread_id * ENOSYS Not supported. */ typedef int (*pthreadDebugSetRegRtn_t) ( pthreadDebugClient_t, const pthreadDebugRegs_t *, pthreadDebugKId_t); /* * OUTPUT: Typedef for routine to write a line of output * * Arguments: * * caller_context The caller's context argument * line A line of output (no newline) * * Return value: * * 0 Success * ENOSYS Not supported. */ typedef int (*pthreadDebugOutputRtn_t) ( pthreadDebugClient_t, __pthreadLongConstString_t); /* * ERROR: Typedef for routine to write a line of error output * * Arguments: * * caller_context The caller's context argument * line A line of output (no newline) * * Return value: * * 0 Success * ENOSYS Not supported. */ typedef int (*pthreadDebugErrorRtn_t) ( pthreadDebugClient_t, __pthreadLongConstString_t); /* * MALLOC: Typedef for routine to allocate memory * * Arguments: * * caller_context The caller's context argument * size size of allocation * * Return value: * * pointer to memory * NULL for error */ typedef __pthreadLongAddr_t (*pthreadDebugMallocRtn_t) ( pthreadDebugClient_t, size_t); /* * FREE: Typedef for routine to deallocate memory * * Arguments: * * caller_context The caller's context argument * address address of allocated space * * Return value: * * none */ typedef void (*pthreadDebugFreeRtn_t) ( pthreadDebugClient_t, __pthreadLongAddr_t); /* * SPECIAL: Typedef for routine to determine the kernel thread ID of a * "special" thread in the debug target process. "Special" threads include the * current thread (which may be changed by a debugger command, for example, * ladebug's "thread" command), and the trap thread (the thread that generated * a trap (breakpoint, etc.) currently being processed. * * Arguments: * * caller_context The caller's context argument * type Which special thread to return. * thread_id Pointer to return current kernel thread ID * * Return value: * * 0 success * ENOSYS Not supported. * ESRCH no current thread */ typedef int (*pthreadDebugSpecKthdRtn_t) ( pthreadDebugClient_t, pthreadDebugSpecialType_t, pthreadDebugKId_t *); /* * The callback definition structure must be initialized by setting the * version field to the value PTHREAD_DEBUG_VERSION, and setting the address * of each callback routine, before calling pthreadDebugContextInit. Note that * DECthreads supports limited upwards compatibility for clients of this * interface specifying older versions (for example, clients compiled using * the original version will work with version 1). * * Callbacks that are not supported by the client must be set to NULL. The * client should clear the callback structure (e.g., with bzero or memset) and * then set the callbacks it understands and supports, to ensure that all * other callbacks are set to NULL. * * pthreadDebugContextInit will fail (with EINVAL) if the READ or GETREG * callbacks are not specified. It will also fail with EINVAL if you specify * either MALLOC or FREE (or SUSPEND and RESUME) without specifying both. * Other callbacks are optional, but may be required for some functions. * You'll get an error (ENOSYS or ENOTSUP) if you call a function that * requires an unimplemented callback. We may also want to call various * callbacks for other reasons (e.g., we use WRITE, if available, to update * some thread information when it's shown, for clients connected with V1 or * higher interface, but we'll ignore that feature if the callback isn't * present (or returns ENOSYS or ENOTSUP). * * Note in particular, however, that debug information is NOT RELIABLE if you * do not specify the SUSPEND and RESUME callbacks. Access to some information * is not atomic, and the consequences of accessing a running process may * range from bad data to (debugger) SEGV/ACCVIO errors. (This is OK if the * debugger knows that the target process is always suspended, but beware that * our access to remote process data will be substantially more efficient if * we know when the process is suspended, and we can know that only when we've * used SUSPEND/RESUME.) */ typedef struct pthreadDebugCallbacks_tag { unsigned long version; pthreadDebugGetMemRtn_t read_callback; /* REQUIRED */ pthreadDebugSetMemRtn_t write_callback; pthreadDebugSuspendRtn_t suspend_callback; pthreadDebugResumeRtn_t resume_callback; pthreadDebugKthdInfoRtn_t kthdinfo_callback; pthreadDebugHoldRtn_t hold_callback; pthreadDebugUnholdRtn_t unhold_callback; pthreadDebugGetFregRtn_t getfreg_callback; pthreadDebugSetFregRtn_t setfreg_callback; pthreadDebugGetRegRtn_t getreg_callback; /* REQUIRED */ pthreadDebugSetRegRtn_t setreg_callback; pthreadDebugOutputRtn_t output_callback; pthreadDebugOutputRtn_t error_callback; pthreadDebugMallocRtn_t malloc_callback; pthreadDebugFreeRtn_t free_callback; pthreadDebugSpecKthdRtn_t speckthd_callback; } pthreadDebugCallbacks_t, *pthreadDebugCallbacks_p; /* * ROUTINES */ /* * pthreadDebugContextInit * * Initialize the DECthreads debug interface and stores the context in * the given debug context structure. This allows the caller to setup the * process to be debugged and register all the callbacks once so that the * other routines only need to take one parameter, this debug context * structure. If the debugger wishes, it can register different callbacks * based on procfs, ptrace core file, remote debugging, etc. * * Arguments: * * caller_context Uninterpreted value, passed to each callback. * callbacks Array of client callbacks, plus API version * symbol_handle Address of __pthread_dbg_symtable in target * debug_context Returns a handle to debug context. * * Callbacks: * * GETMEM, SETMEM, MALLOC, FREE * * Return value: * * 0 Successful completion * EINVAL Unsupported debug client (debug library cannot * support debugger API version) * ENOTSUP Unsupported target (no DECthreads, or * incompatible DECthreads version) * ENOMEM Unable to allocate internal context structure */ extern int pthreadDebugContextInit ( pthreadDebugClient_t, pthreadDebugCallbacks_p, pthreadDebugTargetAddr_t, pthreadDebugContext_p); /* * pthreadDebugContextDestroy * * Destroy the given debug context and free any associated resources. * * Arguments: * * debug_context The debug context to destroy * * Callbacks: * * FREE, GETMEM, SETMEM * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid */ extern int pthreadDebugContextDestroy (pthreadDebugContext_t); /* * pthreadDebugCondGetInfo * * Get the DECthreads state of a given condition variable. * * The process must be suspended for proper operation. * * Arguments: * * debug_context The debug context to use * cond_id condition variable id * info pointer to info structure * * Callbacks: * * GETMEM, MALLOC, FREE * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ESRCH condition variable not found * ECHILD condition variable has lost "child" part */ extern int pthreadDebugCondGetInfo ( pthreadDebugContext_t, pthreadDebugId_t, pthreadDebugCondInfo_p); /* * pthreadDebugCondGetInfoAddr * * Get information about a condition variable from its address * * Arguments: * * debug_context debug context to use * cond_addr Address of cond var in target process * cond_info Address of info buffer * * Callbacks: * * GETMEM, MALLOC, FREE * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid, or not a cond var. * ECHILD condition variable has lost "child" part */ extern int pthreadDebugCondGetInfoAddr ( pthreadDebugContext_t, pthread_cond_t *, pthreadDebugCondInfo_t *); /* * pthreadDebugCondSeqInit * * Return the first condition variable in the current list of user * condition variables. If the call succeeds, then * pthreadDebugCvSeqNext() can be called to retrieve subsequent condition * variables. * * Note, this call will suspend the process. The corresponding destroy * will resume the process. * * Arguments: * * debug_context The debug context to use * cond Pointer to return first condition variable * * Callbacks: * * GETMEM, MALLOC, SUSPEND, FREE * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ENOENT no condition variables * EBUSY debug context's thread traversal is active * ENOMEM unable to allocate traversal context */ extern int pthreadDebugCondSeqInit ( pthreadDebugContext_t, pthreadDebugId_t *); /* * pthreadDebugCondSeqNext * * Return the next condition variable in the current list of user * condition variables. * * Arguments: * * debug_context The debug context to use * cond Pointer to return next condition variable * * Callbacks: * * GETMEM, MALLOC, FREE * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ESRCH the previously returned condition variable * context no longer exists (process not * suspended?) * ENOENT no more condition variables */ extern int pthreadDebugCondSeqNext ( pthreadDebugContext_t, pthreadDebugId_t *); /* * pthreadDebugCondSeqDestroy * * Terminates the iterative condition variable queries started with * pthreadDebugCvSeqInit(). * * Note, this call will resume the process suspended with the * corresponding init operation. * * Arguments: * * debug_context The debug context to use * * Callbacks: * * FREE, RESUME * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid, or no traversal * EBUSY Active traversal of wrong type */ extern int pthreadDebugCondSeqDestroy (pthreadDebugContext_t); /* * pthreadDebugCondSetName * * Set the name of a condition variable for the debug session. (Setting * to "" removes any existing name.) * * Note that this name applies only within the Debug Assistant session * specified by debug_context. It cannot be seen within the target * process (e.g., by tracing, or pthread_cond_getname_np), or by other * Debug Assistant sessions. It will be forgotten when the debug context * is destroyed. * * Arguments: * * debug_context debug context to use * id condition variable ID * name Pointer to name (up to 31 characters) * * Callbacks: * * MALLOC, FREE * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid, or not a cond var. * ENOMEM insufficient memory to create name */ extern int pthreadDebugCondSetName ( pthreadDebugContext_t, pthreadDebugId_t, __pthreadLongConstString_t); /* * pthreadDebugCblkSeqInit * * Return the first thread in the current list of threads blocked on a * condition variable. If the call succeeds, then * pthreadDebugCblkSeqNext() can be called to retrieve subsequent * threads. * * Note, this call will suspend the process. The corresponding destroy * will resume the process. * * Arguments: * * debug_context The debug context to use * cond The condition variable to examine * thread Pointer to return the first blocked thread * * Callbacks: * * GETMEM, MALLOC, SUSPEND, FREE * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ESRCH Condition variable not found * ENOENT no threads blocked on a condition variable * EBUSY debug context's thread traversal is active * ENOMEM unable to allocate traversal context */ extern int pthreadDebugCblkSeqInit ( pthreadDebugContext_t, pthreadDebugId_t, pthreadDebugId_t *); /* * pthreadDebugCblkSeqNext * * Return the next thread in the current list of threads blocked on a * condition variable. * * Arguments: * * debug_context The debug context to use * cond The condition variable to examine * thread Pointer to return the next blocked thread * * Callbacks: * * GETMEM, MALLOC, FREE * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ENOENT no more threads */ extern int pthreadDebugCblkSeqNext ( pthreadDebugContext_t, pthreadDebugId_t *); /* * pthreadDebugCblkSeqDestroy * * Terminates the iterative blocked thread queries started with * pthreadDebugCblkSeqInit(). * * Note, this call will resume the process suspended with the * corresponding init operation. * * Arguments: * * debug_context The debug context to use * * Callbacks: * * FREE, RESUME * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid, or no traversal * EBUSY Active traversal of wrong type */ extern int pthreadDebugCblkSeqDestroy (pthreadDebugContext_t); /* * pthreadDebugMutGetInfo * * Get the DECthreads state of a given mutex. * * Note, the process must be suspended for proper operation. * * Arguments: * * debug_context The debug context to use * mutex_id mutex id * info pointer to info structure * * Callbacks: * * GETMEM, MALLOC, FREE * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ESRCH mutex not found * ECHILD mutex has lost "child" part */ extern int pthreadDebugMutGetInfo ( pthreadDebugContext_t, pthreadDebugId_t, pthreadDebugMutexInfo_p); /* * pthreadDebugMutGetInfoAddr * * Get information about a mutex from its address * * Arguments: * * debug_context debug context to use * mutex_addr Address of mutex in target process * mutex_info Address of info buffer * * Callbacks: * * GETMEM, MALLOC, FREE * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid, or not a mutex * ECHILD mutex has lost "child" part */ extern int pthreadDebugMutGetInfoAddr ( pthreadDebugContext_t, pthread_mutex_t *, pthreadDebugMutexInfo_t *); /* * pthreadDebugMutSeqInit * * Return the first mutex in the current list of user mutexes. If the * call succeeds, then pthreadDebugMutSeqNext() can be called to retrieve * subsequent mutexes. * * Note, this call will suspend the process. The corresponding destroy * will resume the process. * * Arguments: * * debug_context The debug context to use * mutex Pointer to return first mutex ID * * Callbacks: * * GETMEM, MALLOC, SUSPEND, FREE * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ENOENT no mutexes * EBUSY debug context's thread traversal is active * ENOMEM unable to allocate traversal context */ extern int pthreadDebugMutSeqInit ( pthreadDebugContext_t, pthreadDebugId_t *); /* * pthreadDebugMutSeqNext * * Return the next mutex in the current list of user mutexes. * * Arguments: * * debug_context The debug context to use * mutex Pointer to return next mutex ID * * Callbacks: * * GETMEM, MALLOC, FREE * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ENOENT no more mutexes */ extern int pthreadDebugMutSeqNext ( pthreadDebugContext_t, pthreadDebugId_t *); /* * pthreadDebugMutSeqDestroy * * Terminates the iterative mutex queries started with * pthreadDebugMutSeqInit(). * * Note, this call will resume the process suspended with the * corresponding init operation. * * Arguments: * * debug_context The debug context to use * * Callbacks: * * FREE, RESUME * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid, or no traversal * EBUSY Active traversal of wrong type */ extern int pthreadDebugMutSeqDestroy (pthreadDebugContext_t); /* * pthreadDebugMutSetName * * Set the name of a mutex for the debug session. * * Note that this name applies only within the Debug Assistant session * specified by debug_context. It cannot be seen within the target * process (e.g., by tracing, or pthread_mutex_getname_np), or by other * Debug Assistant sessions. It will be forgotten when the debug context * is destroyed. * * Arguments: * * debug_context debug context to use * id mutex ID * name Pointer to name (up to 31 characters) * * Callbacks: * * MALLOC, FREE * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid, or not a cond var. * ENOMEM insufficient memory to create name */ extern int pthreadDebugMutSetName ( pthreadDebugContext_t, pthreadDebugId_t, __pthreadLongConstString_t); /* * pthreadDebugMblkSeqInit * * Return the first thread in the current list of threads blocked on a * mutex. If the call succeeds, then pthreadDebugMblkSeqNext() can be * called to retrieve subsequent threads. * * Note, this call will suspend the process. The corresponding destroy * will resume the process. * * Arguments: * * debug_context The debug context to use * mutex The mutex to examine * thread Pointer to return the first blocked thread * * Callbacks: * * GETMEM, MALLOC, SUSPEND, FREE, RESUME * * Return value: * * 0 Successful completion * ESRCH Mutex not found * EINVAL debug context isn't valid * ENOENT no threads blocked on mutex * EBUSY debug context's thread traversal is active * ENOMEM unable to allocate traversal context */ extern int pthreadDebugMblkSeqInit ( pthreadDebugContext_t, pthreadDebugId_t, pthreadDebugId_t *); /* * pthreadDebugMblkSeqNext * * Return the next thread in the current list of threads blocked on a * mutex. * * Arguments: * * debug_context The debug context to use * mutex The mutex to examine * thread Pointer to return the next blocked thread * * Callbacks: * * GETMEM, MALLOC, FREE * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ENOENT no more threads */ extern int pthreadDebugMblkSeqNext ( pthreadDebugContext_t, pthreadDebugId_t *); /* * pthreadDebugMblkSeqDestroy * * Terminates the iterative blocked thread queries started with * pthreadDebugMblkSeqInit(). * * Note, this call will resume the process suspended with the * corresponding init operation. * * Arguments: * * debug_context The debug context to use * * Callbacks: * * FREE, RESUME * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid, or no traversal * EBUSY Active traversal of wrong type */ extern int pthreadDebugMblkSeqDestroy (pthreadDebugContext_t); /* * pthreadDebugRwGetInfoAddr * * Retrieve the state of a rwlock by address * * Arguments: * * debug_context DECthreads debug context * rwlock_addr Rwlock address (pthread_rwlock_t) * info Return rwlock info * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * EINVAL Not a rwlock * ECHILD Rwlock has lost "child" part */ int pthreadDebugRwGetInfoAddr ( pthreadDebugContext_t, pthread_rwlock_t *, pthreadDebugRwlockInfo_p); /* * pthreadDebugRwGetInfo * * Retrieve the state of a rwlock * * Arguments: * * debug_context DECthreads debug context * rwlock_id Rwlock sequence number * info Return rwlock info * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ESRCH rwlock not found * ECHILD Rwlock has lost "child" part */ int pthreadDebugRwGetInfo ( pthreadDebugContext_t, pthreadDebugId_t, pthreadDebugRwlockInfo_p); /* * pthreadDebugRwblkRdSeqDestroy * * Destroy the active blocked thread traversal context for the list of * threads waiting on a rwlock for a read lock * * Arguments: * * debug_context DECthreads debug context * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid, or no traversal * EBUSY Active traversal of wrong type */ int pthreadDebugRwblkRdSeqDestroy (pthreadDebugContext_t); /* * pthreadDebugRwblkRdSeqInit * * Initialize a blocked thread traversal context. * * Arguments: * * debug_context DECthreads debug context * rwl_id Read-write lock to search * thread_id Returns first thread * * Return value: * * 0 Successful completion * ESRCH Read-write lock not found * EINVAL debug context isn't valid * EBUSY debug context's blocked traversal is active * ENOMEM unable to allocate traversal context * ENOENT no threads */ int pthreadDebugRwblkRdSeqInit ( pthreadDebugContext_t, pthreadDebugId_t, pthreadDebugId_t *); /* * pthreadDebugRwblkRdSeqNext * * Return the next entry in a thread traversal context. * * Arguments: * * debug_context DECthreads debug context * thread_id Returns first thread * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ENOENT no more threads * EBUSY traversal in use by different object type */ int pthreadDebugRwblkRdSeqNext ( pthreadDebugContext_t, pthreadDebugId_t *); /* * pthreadDebugRwblkWrSeqDestroy * * Destroy the active blocked thread traversal context for the list of * threads waiting on a rwlock for a write lock * * Arguments: * * debug_context DECthreads debug context * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid, or no traversal * EBUSY Active traversal of wrong type */ int pthreadDebugRwblkWrSeqDestroy (pthreadDebugContext_t); /* * pthreadDebugRwblkWrSeqInit * * Initialize a blocked thread traversal context. * * Arguments: * * debug_context DECthreads debug context * rwl_id Read-write lock to search * thread_id Returns first thread * * Return value: * * 0 Successful completion * ESRCH Read-write lock not found * EINVAL debug context isn't valid * EBUSY debug context's blocked traversal is active * ENOMEM unable to allocate traversal context * ENOENT no threads */ int pthreadDebugRwblkWrSeqInit ( pthreadDebugContext_t, pthreadDebugId_t, pthreadDebugId_t *); /* * pthreadDebugRwblkWrSeqNext * * Return the next entry in a thread traversal context. * * Arguments: * * debug_context DECthreads debug context * thread_id Returns first thread * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ENOENT no more threads * EBUSY traversal in use by different object type */ int pthreadDebugRwblkWrSeqNext ( pthreadDebugContext_t, pthreadDebugId_t *); /* * pthreadDebugRwSeqDestroy * * Destroy the active rwlock traversal context. * * Arguments: * * debug_context DECthreads debug context * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid, or no traversal * EBUSY Active traversal of wrong type */ int pthreadDebugRwSeqDestroy (pthreadDebugContext_t); /* * pthreadDebugRwSeqInit * * Initialize a rwlock traversal context. * * Arguments: * * debug_context DECthreads debug context * rwlock_id Returns first rwlock * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * EBUSY debug context's traversal is active * ENOMEM unable to allocate traversal context * ENOENT no rwlockes */ int pthreadDebugRwSeqInit ( pthreadDebugContext_t, pthreadDebugId_t *); /* * pthreadDebugRwSeqNext * * Return the next entry in a rwlock traversal context. * * Arguments: * * debug_context DECthreads debug context * rwlock_id Returns next rwlock * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ENOENT no more rwlockes * EBUSY traversal in use by different object type */ int pthreadDebugRwSeqNext ( pthreadDebugContext_t, pthreadDebugId_t *); /* * pthreadDebugRwSetName * * Set the name of a read-write lock for the debug session. (Setting to * "" removes any existing name.) * * Note that this name applies only within the Debug Assistant session * specified by debug_context. It cannot be seen within the target * process (e.g., by tracing, or pthread_cond_getname_np), or by other * Debug Assistant sessions. It will be forgotten when the debug context * is destroyed. * * Arguments: * * debug_context DECthreads debug context * id ID * name pointer to name string * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid or name is NULL * ENOMEM can't store new name */ int pthreadDebugRwSetName ( pthreadDebugContext_t, pthreadDebugId_t, __pthreadLongConstString_t); /* * pthreadDebugThdGetInfo * * Get the DECthreads state of a given thread. * * Note, the process must be suspended for proper operation. * * Arguments: * * debug_context The debug context to use * thread_id thread id * info pointer to info structure * * Callbacks: * * GETMEM, MALLOC, [SETMEM, FREE] * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ESRCH thread not found */ extern int pthreadDebugThdGetInfo ( pthreadDebugContext_t, pthreadDebugId_t, pthreadDebugThreadInfo_p); /* * pthreadDebugThdGetInfoAddr * * Get information about a thread from its address (pthread_t) * * Arguments: * * debug_context debug context to use * thd_addr Address of thread in target process * thd_info Address of info buffer * * Callbacks: * * GETMEM, MALLOC, [SETMEM, FREE] * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid, or not a thread */ extern int pthreadDebugThdGetInfoAddr ( pthreadDebugContext_t, pthread_t, pthreadDebugThreadInfo_t *); /* * pthreadDebugThdSeqInit * * Return the first thread in the current list of user threads. If the * call succeeds, then pthreadDebugThdSeqNext() can be called to retrieve * subsequent threads. * * Note, this call will suspend the process. The corresponding destroy * will resume the process. * * Arguments: * * debug_context The debug context to use * thread Pointer to return first thread ID * * Callbacks: * * GETMEM, MALLOC, SUSPEND, FREE * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ENOENT no threads * EBUSY debug context's thread traversal is active * ENOMEM unable to allocate traversal context */ extern int pthreadDebugThdSeqInit ( pthreadDebugContext_t, pthreadDebugId_t *); /* * pthreadDebugThdSeqNext * * Return the next thread in the current list of user threads. * * Arguments: * * debug_context The debug context to use * thread Pointer to return next thread ID * * Callbacks: * * GETMEM, MALLOC, FREE * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ESRCH the previously returned thread (context) no * longer exists [process not suspended?] * ENOENT no more threads */ extern int pthreadDebugThdSeqNext ( pthreadDebugContext_t, pthreadDebugId_t *); /* * pthreadDebugThdSeqDestroy * * Terminates the iterative thread queries started with * pthreadDebugThdSeqInit(). * * Note, this call will resume the process suspended with the * corresponding init operation. * * Arguments: * * debug_context The debug context to use * * Callbacks: * * FREE, RESUME, [ERROR, OUTPUT] * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid, or no traversal * EBUSY Active traversal of wrong type */ extern int pthreadDebugThdSeqDestroy (pthreadDebugContext_t); /* * pthreadDebugThdSetName * * Set the name of a thread for the debug session. (Setting to "" removes * any existing name.) * * Note that this name applies only within the Debug Assistant session * specified by debug_context. It cannot be seen within the target * process (e.g., by tracing, or pthread_getname_np), or by other Debug * Assistant sessions. It will be forgotten when the debug context is * destroyed. * * Arguments: * * debug_context debug context to use * id thread ID * name Pointer to name (up to 31 characters) * * Callbacks: * * MALLOC, FREE * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid, or not a cond var. * ENOMEM insufficient memory to create name */ extern int pthreadDebugThdSetName ( pthreadDebugContext_t, pthreadDebugId_t, __pthreadLongConstString_t); /* * pthreadDebugTsdCreate * * Create a new TSD key in the target process. * * (Note that this is pointless unless the client is also adding code to * the target process that will use the new key.) * * This call has a potentially dangerous race condition if code in the * target process may also be creating a TSD key. This race cannot be * resolved from the Debug Assistant, so, if the condition is detected, * this function will return EAGAIN. The client should allow the process * to run and try again later. (This will never occur if the debugger * creates a new TSD key before starting the process, and that's the * best time to use it anyway.) * * Arguments: * * debug_context The debug context to use * key Pointer (return the TSD key) * destructor Address (in target process) of routine * * Callbacks: * * MALLOC, SUSPEND, RESUME, GETMEM, SETMEM, FREE * * Return value: * * 0 Successful completion * EINVAL debug context or key isn't valid * ENOMEM can't create key * EAGAIN Synchronization conflict: try again later */ extern int pthreadDebugTsdCreate ( pthreadDebugContext_t, pthread_key_t *, __pthreadDestructor_t); /* * pthreadDebugTsdGetInfo * * Get information on a Thread Specific Data (TSD) Key. * * Arguments: * * debug_context The debug context to use * key The TSD key * info pointer to info structure * * Callbacks: * * MALLOC, GETMEM, FREE * * Return value: * * 0 Successful completion * EINVAL debug context or key isn't valid */ extern int pthreadDebugTsdGetInfo ( pthreadDebugContext_t, pthread_key_t, pthreadDebugTsdInfo_p); /* * pthreadDebugTsdGetSpecific * * Return the value of a thread-specific data (TSD) key for a specific * thread. * * NOTE: There is no interface to return a 32-bit value for a TSD key. * The pointer "value" must point to a 64-bit "void*" on an Alpha * (Digital UNIX or OpenVMS). * * Arguments: * * debug_context The debug context to use * thread_id The thread's ID * key The TSD key * value Pointer where TSD value is returned * * Callbacks: * * MALLOC, GETMEM, FREE * * Return value: * * 0 Successful completion * EINVAL debug context or key isn't valid * ESRCH thread not found */ extern int pthreadDebugTsdGetSpecific ( pthreadDebugContext_t, pthreadDebugId_t, pthread_key_t, pthreadDebugTargetAddr_p); /* * pthreadDebugTsdSetSpecific * * Set the value of a thread-specific data (TSD) key for a specific * thread. * * Arguments: * * debug_context The debug context to use * thread_id The thread's ID * key The TSD key * value New TSD value * * Callbacks: * * SUSPEND, RESUME, MALLOC, GETMEM, SETMEM, FREE * * Return value: * * 0 Successful completion * EINVAL debug context or key isn't valid * ESRCH thread not found * ENOTSUP can't set key (thread has no TSD array) */ extern int pthreadDebugTsdSetSpecific ( pthreadDebugContext_t, pthreadDebugId_t, pthread_key_t, pthreadDebugTargetConstAddr_t); /* * pthreadDebugTsdSetName * * Set the name of a TSD key for the debug session. (Setting to "" * removes any existing name.) * * Note that this name applies only within the Debug Assistant session * specified by debug_context. It cannot be seen within the target * process (e.g., by tracing, or pthread_key_getname_np), or by other * Debug Assistant sessions. It will be forgotten when the debug context * is destroyed. * * Arguments: * * debug_context debug context to use * key TSD key * name Pointer to name (up to 31 characters) * * Callbacks: * * MALLOC, FREE * * Return value: * * 0 Successful completion * EINVAL debug context or key isn't valid. * ENOMEM insufficient memory to create name */ extern int pthreadDebugTsdSetName ( pthreadDebugContext_t, pthread_key_t, __pthreadLongConstString_t); /* * pthreadDebugTsdSeqDestroy * * Destroy a TSD traversal context * * Arguments: * * debug_context debug context to use * * Callbacks: * * RESUME, MALLOC, FREE * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid, or no traversal * EBUSY Active traversal of wrong type */ extern int pthreadDebugTsdSeqDestroy ( pthreadDebugContext_t debug_context); /* * pthreadDebugTsdSeqInit * * Initialize a TSD traversal context. * * Arguments: * * debug_context debug context to use * key_id pointer to return first key * * Callbacks: * * SUSPEND, GETMEM, MALLOC, [FREE, RESUME] * * Return value: * * 0 Successful completion * EINVAL debug context or key isn't valid. * EBUSY debug context's key traversal is active * ENOMEM unable to allocate traversal context * ENOENT no keys */ extern int pthreadDebugTsdSeqInit ( pthreadDebugContext_t debug_context, pthreadDebugId_t *key_id); /* * pthreadDebugTsdSeqInit * * Return the next TSD key. * * Arguments: * * debug_context debug context to use * key_id pointer to return next key * * Callbacks: * * GETMEM, MALLOC, FREE * * Return value: * * 0 Successful completion * EINVAL debug context or key isn't valid. * EBUSY debug context's key traversal is active * ENOMEM unable to allocate traversal context * ENOENT no keys */ extern int pthreadDebugTsdSeqNext ( pthreadDebugContext_t debug_context, pthreadDebugId_t *key_id); /* * pthreadDebugThdGetFreg * * Get the thread's current floating point registers. * * Arguments: * * debug_context The debug context to use * thread_id thread id * regs register values * * Callbacks: * * SUSPEND, RESUME, GETMEM, GETREG, MALLOC, GETFREG, FREE * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ESRCH thread not found * any callback errors */ extern int pthreadDebugThdGetFreg ( pthreadDebugContext_t, pthreadDebugId_t, pthreadDebugFregs_p); /* * pthreadDebugThdSetFreg * * Set the thread's current floating point registers. * * Arguments: * * debug_context The debug context to use * thread_id thread id * regs register values * * Callbacks: * * SUSPEND, RESUME, GETMEM, GETREG, MALLOC, SETFREG, FREE * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ESRCH thread not found * any callback errors */ extern int pthreadDebugThdSetFreg ( pthreadDebugContext_t, pthreadDebugId_t, pthreadDebugFregs_p); /* * pthreadDebugThdGetReg * * Get the thread's current general registers. * * Arguments: * * debug_context The debug context to use * thread_id thread id * regs register values * * Callbacks: * * SUSPEND, RESUME, GETMEM, MALLOC, GETREG, FREE * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ESRCH thread not found * any callback errors */ extern int pthreadDebugThdGetReg ( pthreadDebugContext_t, pthreadDebugId_t, pthreadDebugRegs_p); /* * pthreadDebugThdSetReg * * Set the thread's current general registers. * * Arguments: * * debug_context The debug context to use * thread_id thread id * regs register values * * Callbacks: * * SUSPEND, RESUME, GETMEM, MALLOC, SETREG, [GETREG, FREE] * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ESRCH thread not found * any callback errors */ extern int pthreadDebugThdSetReg ( pthreadDebugContext_t, pthreadDebugId_t, pthreadDebugRegs_p); /* * pthreadDebugThdHold * * Make the user thread ineligible for scheduling. * * Arguments: * * debug_context The debug context to use * thread_id thread to hold * * Callbacks: * * SUSPEND, RESUME, GETMEM, MALLOC, SETMEM, HOLD, UNHOLD, FREE * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * EPERM (V2) internal DECthreads thread (can't be held). * EINVAL (V2) thread is terminated * any callback errors */ extern int pthreadDebugThdHold ( pthreadDebugContext_t, pthreadDebugId_t); /* * pthreadDebugThdUnhold * * Make the user thread eligible for scheduling. * * Arguments: * * debug_context The debug context to use * thread_id thread to release * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * EPERM (V2) internal DECthreads thread (can't be held). * EINVAL (V2) thread is terminated */ extern int pthreadDebugThdUnhold ( pthreadDebugContext_t, pthreadDebugId_t); /* * pthreadDebugThdKidToId * * Convert a kernel thread ID into a user thread ID (sequence number). * * Arguments: * * debug_context debug context to use * kid Kernel thread ID. * thread_id Thread ID. * * Callbacks: * * KTHDINFO, GETMEM * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid, or not a thread */ extern int pthreadDebugThdKidToId ( pthreadDebugContext_t, pthreadDebugKId_t, pthreadDebugId_t *); /* * pthreadDebugSuspend * * Invoke the SUSPEND callback to suspend the target process. The * advantage of using this interface rather than "doing it directly" is * that, when debug assistant knows that the target process is suspended, * it can make more efficient use of its internal cache. * * Arguments: * * debug_context debug context to use * * Callbacks: * * SUSPEND * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ENOTSUP SUSPEND callback not supported */ extern int pthreadDebugSuspend (pthreadDebugContext_t); /* * pthreadDebugResume * * Invoke the RESUME callback to suspend the target process. The * advantage of using this interface rather than "doing it directly" is * that, when the assistant knows that the target process is suspended, * it can make more efficient use of its internal cache. * * Arguments: * * debug_context debug context to use * * Callbacks: * * RESUME * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ENOTSUP RESUME callback not supported */ extern int pthreadDebugResume (pthreadDebugContext_t); /* * pthreadDebugGetSpecialThread * * Return the thread Id for a specific "special" kernel thread (if any). * Depends upon the debug client's response to the SPECKTHD callback, * essentially just converting that kernel thread ID into a user thread * ID. * * Arguments: * * debug_context debug context to use * type Type of special thread * thread_id Thread ID (returned) * * Callbacks: * * SPECKTHD, KTHDINFO, GETMEM * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ENOTSUP SPECKTHD callback not supported */ extern int pthreadDebugGetSpecialThread ( pthreadDebugContext_t, pthreadDebugSpecialType_t, pthreadDebugId_t *); /* * pthreadDebugCmd * * This routine implements the commands previously provided by the * pthread_debug_cmd() routine which was run in the context of the * target. These commands operate from the context of the debugger now. * * Note, the process must be suspended for reliable operation. * * Arguments: * * debug_context The debug context to use * command Pointer to an ASCII character string * representing a sequence of pthread_debug() * commands, each separated by ";". * * Callbacks: * * OUTPUT (Potentially all, depending upon the command.) * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ENOTSUP invalid command * ESHUTDOWN command string terminated by "exit" */ extern int pthreadDebugCmd( pthreadDebugContext_t, __pthreadLongConstString_t); /* * pthreadDebugSetErrorWidth * * This routine modifies the output width of the error stream used by * pthreadDebugCmd (and general error tracing output when enabled). The * default if not set is 80 columns. * * Arguments: * * debug_context The debug context to use * width New width for error stream width. * * Callbacks: * * none * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid */ extern int pthreadDebugSetErrorWidth ( pthreadDebugContext_t, int); /* * pthreadDebugSetOutputWidth * * This routine modifies the output width of the output stream used by * pthreadDebugCmd (and tracing output if enabled). The default if not * set is 80 columns. * * Arguments: * * debug_context The debug context to use * width New width for output stream width. * * Callbacks: * * none * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid */ extern int pthreadDebugSetOutputWidth ( pthreadDebugContext_t, int); /* * EVENTS * * The DECthreads event mechanism allows a debugger to determine when "things" * happen within the DECthreads scheduler. For example, when a thread is * created, when it first starts to run, and when it terminates. * * Ultimately the debugger learns of an event by receiving a breakpoint trap * that it has set within the "target" process. It can ask for the address of * a "hook" routine at which to set the breakpoint by calling the routine * pthreadDebugEventGetAddress. However, for performance reasons the * DECthreads scheduler does not normally call these hook routines. The hooks * must be enabled by setting events. (Note that the hook points consist of a * single no-op instruction so that they can be patched without needing to * save and restore the original instruction.) * * In principle, the debugger could begin by setting globally all events in * which it "may have" interest, and simply ignoring the resulting breakpoints * when an event isn't interesting at the moment. However, debugging of * asynchronous programs can be difficult enough without the timing impact of * dealing with extra breakpoints. It is strongly recommended that the * debugger enable only the events in which it is specifically interested, and * then disable them when it no longer needs to know. * * Additionally, when per-thread events are desired the debugger could simply * globally enable and disable any events, and check the current thread ID * during breakpoint processing. But to minimize the impact of events on * application behavior, it would be better to enable events only for specific * threads so that the breakpoint overhead occurs only where its likely to be * of use. */ /* * Event definitions and "stub" prototypes * * Any of these events can be enabled either for specific threads or * "globally", for all threads in the target process. Note that disabling * (clearing) an event for a specific thread doesn't override a global enable * (or vice versa) -- events are reported if the event is enabled either * globally or for the current thread. * * Events are reported in either or both of two mechanisms, when the event * occurs while enabled. * * For the convenience of debuggers running in another process, DECthreads * calls a "breakpoint stub" in the target process -- a debugger may set * breakpoints at these calls to detect the event. Stub routine pointers are * returned by calling pthreadDebugEventGetAddress. Stubs are enabled by * getting a stub address, or by calling pthreadDebugEventSetGlobal or * pthreadDebugEventSetThread. * * For the convenience of code running within the threaded process, such as a * performance analyzer, DECthreads can be configured to call a hook routine * provided by the analyzer. You can set a hook address by calling * __pthread_debug_set_hook. (Note that although the "hook routine" event * interface is documented & prototyped in this header, the __pthread_debug_ * routines are in libpthread.so [PTHREAD$RTL.EXE], not in the debug assistant * library. * * Each hook routine is called with arguments that identify the event, the * thread, and additional parameters giving specific information. Refer to the * pthreadDebugEventActivating_t routine prototype for the arguments passed to * the "Activating" event hook, for example. * * ACTIVATING Report the initial execution of a new thread * (Setting this event for a specific thread is * of minimal use, but is allowed: one example * would be to enable it for the new thread * reported in a Creating event, to determine * when the new thread starts executing.) * BLOCKING Report when a thread blocks * CREATING Report when a thread is created * RUNNING Report when a thread runs (after blocking or * preemption) * TERMINATING Report when a thread terminates (after a * return from its start routine, a call to * pthread_exit, or cancellation). NOTE that * the thread is not yet completely run down. * INITIALIZED Report when the DECthreads core has been * initialized. * FREEING Report when a thread is going to be freed. * This means a thread is completely run down. * UNBLOCK Report when a thread is readied after * having been blocked. * BUGCHECK Report when DECthreads bugchecks (panics) * LASTCHANCE Report when the last chance exception * handler is invoked. * TOOLTEXT Report when a tool library detects some * condition worth of debugger/user attention. */ typedef enum pthreadDebugEvent_tag { PTHREAD_DEBUG_EVENT_NONE = 0, PTHREAD_DEBUG_EVENT_ACTIVATING = 1, PTHREAD_DEBUG_EVENT_BLOCKING = 2, PTHREAD_DEBUG_EVENT_CREATING = 3, PTHREAD_DEBUG_EVENT_RUNNING = 4, PTHREAD_DEBUG_EVENT_TERMINATING = 5, PTHREAD_DEBUG_EVENT_INITIALIZED = 6, PTHREAD_DEBUG_EVENT_FREEING = 7, PTHREAD_DEBUG_EVENT_UNBLOCK = 8, PTHREAD_DEBUG_EVENT_BUGCHECK = 9, PTHREAD_DEBUG_EVENT_LASTCHANCE = 10, PTHREAD_DEBUG_EVENT_TOOLREPORT = 11 } pthreadDebugEvent_t; #define PTHREAD_DEBUG_EVENT_MIN PTHREAD_DEBUG_EVENT_ACTIVATING #define PTHREAD_DEBUG_EVENT_MAX PTHREAD_DEBUG_EVENT_TOOLREPORT #define PTHREAD_DEBUG_EVENT_COUNT (PTHREAD_DEBUG_EVENT_MAX+1) typedef unsigned int pthreadDebugEventMask_t, *pthreadDebugEventMask_p; /* * Flags passed to various event routines by DECthreads to indicate * certain states. */ /* * RUN event: * PREEMPTED: Outgoing thread was preempted * KERNEL: Outgoing thread blocking in kernel */ #define PTHREAD_DEBUG_EVTRUN_PREEMPTED 0x00000001 /* Outgoing preempted */ #define PTHREAD_DEBUG_EVTRUN_KERNEL 0x00000002 /* Outgoing kernel block */ /* * TERMINATE event: * LOCKS: Terminated with locks held */ #define PTHREAD_DEBUG_EVTTRM_LOCKS 0x00000001 /* * UNBLOCK event: * PEND: Unblocked before BLOCK event was seen. */ #define PTHREAD_DEBUG_EVTUBL_PEND 0x00000001 /* * Prototypes showing the arguments passed to the BPT stub routines * (returned by pthreadDebugEventGetAddress). * * A debugger receiving a breakpoint on one of these events can read the * arguments to determine what happened, and then use normal information * interfaces to format and report the data. */ /* * Thread is activating (running for the first time) * * Arguments: * * event PTHREAD_DEBUG_EVENT_ACTIVATING * thread The new thread's sequence number * start_routine Address of the start routine * start_argument The argument passed to the start routine * spare Unused * flags Flags (none currently defined) * * Return value: * * none */ typedef void (*pthreadDebugEventActivating_t) ( pthreadDebugEvent_t, pthreadDebugId_t, void *(*) (void *), void *, void *, unsigned long); /* * Thread is blocking * * Arguments: * * event PTHREAD_DEBUG_EVENT_BLOCKING * thread The thread's sequence number * substate One of KERNEL, MUTEX, CV, TIMED_CV * object Sequence number of mutex or condition variable (or 0 * if none) * spare Unused * flags Flags (none currently defined) * * Return value: * * none */ typedef void (*pthreadDebugEventBlocking_t) ( pthreadDebugEvent_t, pthreadDebugId_t, pthreadDebugSubstate_t, pthreadDebugId_t, void *, unsigned long); /* * Thread is being created * * Arguments: * * event PTHREAD_DEBUG_EVENT_CREATING * thread The creating thread's sequence number * new_thread The new thread's sequence number * start_routine Address of the start routine * start_argument Argument passed to start routine * flags Flags (none currently defined) * * Return value: * * none */ typedef void (*pthreadDebugEventCreating_t) ( pthreadDebugEvent_t, pthreadDebugId_t, pthreadDebugId_t, void *(*) (void *), void *, unsigned long); /* * Thread is running (after having blocked or been preempted) * * Arguments: * * event PTHREAD_DEBUG_EVENT_RUNNING * thread The thread's sequence number * substate Thread's previous substate * previous Sequence number of previous thread * spare Unused * flags Flags (preempted, kernel) * * Return value: * * none */ typedef void (*pthreadDebugEventRunning_t) ( pthreadDebugEvent_t, pthreadDebugId_t, pthreadDebugSubstate_t, pthreadDebugId_t, void *, unsigned long); /* * Thread is terminating * * Arguments: * * event PTHREAD_DEBUG_EVENT_TERMINATING * thread The thread's sequence number * substate Reason for termination: normal, term_cancel * (cancelled) or term_exit (pthread_exit) * result Thread's result value * spare Unused * flags Flags (locks) * * Return value: * * none */ typedef void (*pthreadDebugEventTerminating_t) ( pthreadDebugEvent_t, pthreadDebugId_t, pthreadDebugSubstate_t, void *, void *, unsigned long); /* * The DECthreads code has been initialized. * * NOTE: This is OBSOLETE. It was a hack to allow clients to avoid asking * about state that wasn't available until after initialization. This bug * was long since fixed correctly; a process that hasn't yet completed * DECthreads initialization simply has one thread. * * Arguments: * * event PTHREAD_DEBUG_EVENT_INITIALIZED * thread The thread's sequence number * spare Unused * spare Unused * spare Unused * flags Flags (none currently defined) * * Return value: * * none */ typedef void (*pthreadDebugEventInitialized_t) ( pthreadDebugEvent_t, pthreadDebugId_t, void *, void *, void *, unsigned long); /* * Thread is freeing a zombie TCB * * Arguments: * * event PTHREAD_DEBUG_EVENT_FREEING * thread Thread's sequence number * freed Freed thread's sequence number * spare Unused * spare Unused * flags Flags (none currently defined) * * Return value: * * none */ typedef void (*pthreadDebugEventFreeing_t) ( pthreadDebugEvent_t, pthreadDebugId_t, pthreadDebugId_t, void *, void *, unsigned long); /* * Thread is unblocked from a wait (CV, Mutex, etc.) * * Arguments: * * event PTHREAD_DEBUG_EVENT_UNBLOCK * thread Unblocking thread's sequence number * substate Reason for block: mutex, cv, etc. * unblock Unblocked thread's sequence number * spare Unused * flags Flags (none currently defined) * * Return value: * * none */ typedef void (*pthreadDebugEventUnblock_t) ( pthreadDebugEvent_t, pthreadDebugId_t, pthreadDebugSubstate_t, pthreadDebugId_t, void *, unsigned long); /* * DECthreads bugcheck (unrecoverable inconsistency) * * Arguments: * * event PTHREAD_DEBUG_EVENT_BUGCHECK * thread Bugchecking thread's sequence number * reason String describing reason * spare Unused argument * spare Unused argument * flags Flags (none currently defined) * * Return value: * * none */ typedef void (*pthreadDebugEventBugcheck_t) ( pthreadDebugEvent_t, pthreadDebugId_t, char *, void *, void *, unsigned long); /* * DECthreads last-chance handler (exception not handled by thread) * * Arguments: * * event PTHREAD_DEBUG_EVENT_LASTCHANCE * thread Thread's sequence number * spare1 Unused argument * spare2 Unused argument * spare3 Unused argument * flags Flags (none currently defined) * * Return value: * * none */ typedef void (*pthreadDebugEventLastchance_t) ( pthreadDebugEvent_t, pthreadDebugId_t, void *, void *, void *, unsigned long); /* * TOOL reported condition * * Arguments: * * event PTHREAD_DEBUG_EVENT_BUGCHECK * thread Reporting thread's sequence number * reason String describing condition * command ladebug commands (may be ignored by other debuggers) * spare Unused argument * flags Flags (none currently defined) * * Return value: * * none */ typedef void (*pthreadDebugEventToolReport_t) ( pthreadDebugEvent_t, pthreadDebugId_t, char *, char *, void *, unsigned long); /* * pthreadDebugEventGetAddress * * Get the address of a function in which the debugger can place a break * point in order to know that the specified event has occurred. * * Arguments: * * debug_context The debug context to use * event Event number (pthreadDebugEvent_t) * address pointer to "void*" to receive bpt address * * Callbacks: * * GETMEM * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid * ENOTSUP event code not supported */ extern int pthreadDebugEventGetAddress ( pthreadDebugContext_t, pthreadDebugEvent_t, pthreadDebugTargetAddr_p); /* * pthreadDebugEventGetGlobal * * Get a bitmask representing the global events currently enabled * * Arguments: * * debug_context The debug context to use * mask Event mask (pthreadDebugEventMask_t) * * Callbacks: * * GETMEM * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid */ extern int pthreadDebugEventGetGlobal ( pthreadDebugContext_t, pthreadDebugEventMask_p); /* * pthreadDebugEventGetThread * * Get a bitmask representing the thread events currently enabled * * Arguments: * * debug_context The debug context to use * thread_id The thread for which to get event mask * mask Event mask (pthreadDebugEventMask_t) * * Callbacks: * * GETMEM * * Return value: * * 0 Successful completion * EINVAL debug context isn't valid */ extern int pthreadDebugEventGetThread ( pthreadDebugContext_t, pthreadDebugId_t, pthreadDebugEventMask_p); /* * pthreadDebugEventClearGlobal * * This routine disables global event reporting for an event. * * Arguments: * * debug_context The debug context to use * event Event number (pthreadDebugEvent_t) * * Callbacks: * * GETMEM, SETMEM, SUSPEND, RESUME * * Return value: * * 0 Successful completion * EINVAL debug context or event isn't valid */ extern int pthreadDebugEventClearGlobal ( pthreadDebugContext_t, pthreadDebugEvent_t); /* * pthreadDebugEventSetGlobal * * This routine enables global event reporting for an event. * * Arguments: * * debug_context The debug context to use * event Event number (pthreadDebugEvent_t) * * Callbacks: * * GETMEM, SETMEM, SUSPEND, RESUME * * Return value: * * 0 Successful completion * EINVAL debug context or event isn't valid */ extern int pthreadDebugEventSetGlobal ( pthreadDebugContext_t, pthreadDebugEvent_t); /* * pthreadDebugEventClearThread * * This routine disables event reporting for a specific thread * * Arguments: * * debug_context The debug context to use * thread_id The thread for which to clear the event * event Event number (pthreadDebugEvent_t) * * Callbacks: * * GETMEM, SETMEM, SUSPEND, RESUME * * Return value: * * 0 Successful completion * ESRCH thread not found * EINVAL debug context or event isn't valid */ extern int pthreadDebugEventClearThread ( pthreadDebugContext_t, pthreadDebugId_t, pthreadDebugEvent_t); /* * pthreadDebugEventSetThread * * This routine enables event reporting for a specific thread * * Arguments: * * debug_context The debug context to use * thread_id The thread for which to set the event * event Event number (pthreadDebugEvent_t) * * Callbacks: * * GETMEM, SETMEM, SUSPEND, RESUME * * Return value: * * 0 Successful completion * ESRCH thread not found * EINVAL debug context or event isn't valid */ extern int pthreadDebugEventSetThread ( pthreadDebugContext_t, pthreadDebugId_t, pthreadDebugEvent_t); /* * TRACE STREAM SUPPORT * * Following is a set of interfaces to access a DECthreads log engine trace * stream. This trace stream may be specified as a file, or you may use a * pthreadDebugContext_t to access the in-memory trace buffers of a threaded * process. */ typedef enum _pthreadDebugTraceFmt_tag { PTHREAD_DEBUG_TRACE_FMT_TIME = 0x01, /* Show record's timestamp */ PTHREAD_DEBUG_TRACE_FMT_CYCLE = 0x02, /* Show machine cycles */ PTHREAD_DEBUG_TRACE_FMT_SIZE = 0x04, /* Show record position/size */ PTHREAD_DEBUG_TRACE_FMT_STACK = 0x08, /* Show call stack */ PTHREAD_DEBUG_TRACE_FMT_ABSTIME = 0x10 /* Show timestamp as absolute */ } pthreadDebugTraceFmt_t; typedef enum _pthreadDebugTraceDetail_tag { PTHREAD_DEBUG_TRACE_DETAIL_NONE, /* event names */ PTHREAD_DEBUG_TRACE_DETAIL_BRIEF, /* scalar args, seq #s */ PTHREAD_DEBUG_TRACE_DETAIL_MID, /* Add names, some state */ PTHREAD_DEBUG_TRACE_DETAIL_NORMAL, /* Normal detail */ PTHREAD_DEBUG_TRACE_DETAIL_FULL /* All detail */ } pthreadDebugTraceDetail_t; typedef enum _pthreadDebugTraceSetHow_tag { PTHREAD_DEBUG_TRACE_SETHOW_REPLACE, /* Replace current mask */ PTHREAD_DEBUG_TRACE_SETHOW_SET, /* Add bits to mask */ PTHREAD_DEBUG_TRACE_SETHOW_CLEAR /* Clear bits from mask */ } pthreadDebugTraceSetHow_t; typedef void *pthreadDebugTraceHandle_t; typedef void **pthreadDebugTraceHandle_p; /* * The common header of a log engine's trace record. * * NOTES: * flags OR-ed enum values from pthreadTraceLogHeadFlags_t type * argp Pointer to "raw" event args (usually use iterator) * pc Pointer to array of PC values (stack trace) * name The event name specified at event point (if any) * evtname Formatted "canonical" name for event ("mutex.lock.request") */ typedef struct pthreadDebugTraceHead_tag { pthreadTraceEvent_t event; /* Trace point identifier */ pthreadTraceId_t thread; /* Thread that logged event */ __pthreadLongUint_t sequence; /* Record sequence number */ pthreadTraceTimestamp_t timestamp; /* Timestamp data */ unsigned char flags; /* pthreadTraceLogHeadFlags_t */ unsigned char frames; /* Number of frames in trace */ unsigned char argc; /* Number of arguments */ const unsigned char *argt; /* Address of arg type array */ const void *argp; /* Address of first argument */ const void * const *pc; /* Pointer to PC array */ char name[32]; /* Event name */ char evtname[32]; /* Event point name */ } pthreadDebugTraceHead_t, *pthreadDebugTraceHead_p; /* * pthreadDebugTraceClose * * This routine closes a trace stream opened with pthreadDebugTraceOpen() * * Arguments: * * trace_handle Pointer to returned handle * * Callbacks: * * FREE * * Return value: * * 0 Successful completion * EINVAL trace handle not valid */ extern int pthreadDebugTraceClose (pthreadDebugTraceHandle_t); /* * pthreadDebugTraceOpen * * This routine opens a trace file for analysis. When you specify a trace * file, you can access all data in the trace stream, from process * creation. The callback structure must contain a valid version; it may * also contain malloc, free, output, and error callbacks. Other * callbacks are ignored. * * Arguments: * * caller_context Uninterpreted data returned to callbacks * callbacks Structure of version & callbacks * trace_file Name of trace file (may be NULL) * trace_handle Pointer to returned handle * * Callbacks: * * MALLOC, FREE * * Return value: * * 0 Successful completion * ENOMEM Can't allocate context info * ENOENT File not found * EVERSION Unsupported version * (others from callbacks, if any) */ extern int pthreadDebugTraceOpen ( void *, pthreadDebugCallbacks_p, char *, pthreadDebugTraceHandle_p); /* * pthreadDebugTraceDestroy * * This routine destroys a trace stream initialized with * pthreadDebugTraceInit * * Arguments: * * debug_context The debug context to use * * Callbacks: * * SUSPEND, FREE, GETMEM, RESUME * * Return value: * * 0 Successful completion * EINVAL debug context not valid */ extern int pthreadDebugTraceDestroy (pthreadDebugContext_t); /* * pthreadDebugTraceInit * * Initializes a debug context for access to the active log engine trace * buffers (if any) in the process connected to the debug_context. * * Arguments: * * trace_context New trace context * debug_context The debug context to use * * Callbacks: * * MALLOC, GETMEM, SUSPEND, RESUME * * Return value: * * 0 Successful completion * ENOMEM Can't allocate context info * EINVAL debug context invalid * ESRCH target process isn't tracing * (others from callbacks, if any) */ extern int pthreadDebugTraceInit ( pthreadDebugTraceHandle_p, pthreadDebugContext_t); /* * pthreadDebugTraceSeqDestroy * * This routine destroys a trace sequence iterator, after processing a * set of trace records. * * Arguments: * * trace_handle Pointer to trace context handle * * Callbacks: * * RESUME * * Return value: * * 0 Successful completion * EBUSY Active traversal of wrong type * EINVAL trace context invalid, or no iterator */ extern int pthreadDebugTraceSeqDestroy (pthreadDebugTraceHandle_t); /* * pthreadDebugTraceSeqInit * * This routine creates a trace sequence iterator, to allow the caller to * process the trace records in the active stream. Note that, unless the * active trace stream is a file, the iterator may be unable to return * all records, as it can access only records currently in the target * process' address space (active trace buffers). * * This routine will search the available trace stream for the first * record with a sequence number greater than or equal to the "sequence" * argument. If none can be found, ENOENT is returned; otherwise the * first record is copied to the output buffer ("first_trace"). * * The information returned (particularly the stack trace and arguments, * to which the buffer contains only pointers) is valid only until the * iterator is advanced (by calling pthreadDebugTraceSeqNext) or * destroyed (by calling pthreadDebugTraceSeqDestroy). To save trace * information for later use, the caller must copy the stack trace and * argument data elsewhere. * * The caller must not modify the stack trace or argument data to which * the trace record buffer points. * * Arguments: * * trace_handle Pointer to trace context handle * sequence First sequence number (usually 0) * first_trace Pointer to trace record buffer * * Callbacks: * * SUSPEND, RESUME, GETMEM * * Return value: * * 0 Successful completion * EINVAL trace context invalid, or no iterator * ENOMEM Unable to allocate internal resources * ENOENT No trace records available */ extern int pthreadDebugTraceSeqInit ( pthreadDebugTraceHandle_t, unsigned long, pthreadDebugTraceHead_p); /* * pthreadDebugTraceSeqNext * * This routine returns the next record (if any) of the trace stream * initialized by calling pthreadDebugTraceSeqInit. * * The information returned (particularly the stack trace and arguments, * to which the buffer contains only pointers) is valid only until the * iterator is advanced (by calling pthreadDebugTraceSeqNext) or * destroyed (by calling pthreadDebugTraceSeqDestroy). To save trace * information for later use, the caller must copy the stack trace and * argument data elsewhere. * * The caller must not modify the stack trace or argument data to which * the trace record buffer points. * * Arguments: * * trace_handle Pointer to trace context handle * trace Pointer to trace record buffer * * Callbacks: * * none * * Return value: * * 0 Successful completion * EINVAL trace context invalid, or no iterator * ENOENT No more trace records available */ extern int pthreadDebugTraceSeqNext ( pthreadDebugTraceHandle_t, pthreadDebugTraceHead_p); /* * pthreadDebugTraceFormat * * This routine creates an ASCII representation of the current trace * record, and writes it using the output callback (specified on * pthreadDebugTraceOpen either directly or through the use of a * debug_context). * * Arguments: * * trace_handle Pointer to trace context handle * detail Level of detail desired * flags Formatting flags * * Callbacks: * * none * * Return value: * * 0 Successful completion * EINVAL Trace context invalid, or no current record * ENOSYS No output callback available */ extern int pthreadDebugTraceFormat ( pthreadDebugTraceHandle_t, pthreadDebugTraceDetail_t, pthreadDebugTraceFmt_t); /* * pthreadDebugTraceArgSeqDestroy * * This routine destroys a trace record argument iterator. * * Arguments: * * trace_handle Pointer to trace context handle * trace Pointer to trace record buffer * * Callbacks: * * none * * Return value: * * 0 Successful completion * EINVAL trace context invalid, or no iterator */ extern int pthreadDebugTraceArgSeqDestroy (pthreadDebugTraceHandle_t); /* * pthreadDebugTraceArgSeqInit * * This routine creates a trace record argument iterator, by which the * caller may iterate through the current trace record arguments. * (Instead of parsing the argument array directly from the trace * record.) * * Arguments: * * trace_handle Pointer to trace context handle * type Return PTHREAD_TRACE_TYPE_* value for argument * size Return the size of the argument * data Return pointer to the data * * Callbacks: * * none * * Return value: * * 0 Successful completion * EINVAL trace context invalid, or no iterator * ENOENT No current trace record */ extern int pthreadDebugTraceArgSeqInit ( pthreadDebugTraceHandle_t, pthreadTraceType_p, size_t *, void * const *); /* * pthreadDebugTraceArgSeqNext * * This routine returns the next argument in the current trace record. * * Arguments: * * trace_handle Pointer to trace context handle * type Return PTHREAD_TRACE_TYPE_* value for argument * size Return the size of the argument * data Return pointer to the data * * Callbacks: * * none * * Return value: * * 0 Successful completion * EINVAL trace context invalid, or no iterator * ENOENT No more arguments */ extern int pthreadDebugTraceArgSeqNext ( pthreadDebugTraceHandle_t, pthreadTraceType_p, size_t *, void * const *); /* * pthreadDebugTraceClassGet * * This routine returns the trace class mask enabled for the target * process. * * Arguments: * * debug_context The debug context to use * classes Pointer to mask * * Callbacks: * * GETMEM * * Return value: * * 0 Successful completion * EINVAL debug context invalid */ extern int pthreadDebugTraceClassGet ( pthreadDebugContext_t, unsigned long *); /* * pthreadDebugTraceClassSet * * This routine sets the trace class mask enabled for the target process * * Arguments: * * debug_context The debug context to use * how set, clear, replace * classes new class mask * * Callbacks: * * SUSPEND, RESUME, GETMEM, SETMEM * * Return value: * * 0 Successful completion * ENOSYS Target process isn't tracing * EINVAL debug context invalid, or invalid class bits */ extern int pthreadDebugTraceClassSet ( pthreadDebugContext_t, pthreadDebugTraceSetHow_t, unsigned long); /* * pthreadDebugTraceLoad * * This routine requests that the target process load a (new) trace * engine, and initialize it. * * Arguments: * * debug_context The debug context to use * library Name of trace engine * argc Count of arguments in argv * argv Pointer to array of argument pointers * * Callbacks: * * SETMEM, GETMEM, SUSPEND, RESUME * * Return value: * * 0 Successful completion * ENOSYS Target process isn't tracing * EINVAL debug context invalid, or invalid class bits */ extern int pthreadDebugTraceLoad ( pthreadDebugContext_t, char *, int, char *[]); /* * End of TRACE STREAM SUPPORT */ /* * PROFILING HOOKS * * The following section deserves a separate header, but I'm crunching it in * here for now because the interfaces share some symbols and types with the * other debug interfaces. * * The earlier part of this header was dedicated to interfaces supported by * the debug assistant library, for use by debugger code that runs in another * process. The following interfaces are for profilers that run within the * DECthreads process. They are minimal and preliminary at this point. * * BEWARE: the in-process hook routines are called in places where the * DECthreads scheduling database may be LOCKED. You CANNOT make any calls to * the thread library, or to libc, within the hook routine. (This should be OK * for ATOM tools, but probably not for much of anything else.) */ /* * Prototypes showing the arguments passed to the hook routines (set by * __pthread_debug_set_hook). */ /* * Thread is activating (running for the first time) * * event PTHREAD_DEBUG_EVENT_ACTIVATING * thread The new thread's TEB pointer * start_routine Address of the start routine * start_argument The argument passed to start_routine * spare Unused * flags Flags (none currently defined) */ typedef void (*pthreadDebugHookActivating_t) ( pthreadDebugEvent_t, pthread_t, void *(*) (void *), void *, void *, unsigned long); /* * Thread is blocking * * event PTHREAD_DEBUG_EVENT_BLOCKING * thread The thread's TEB pointer * substate One of KERNEL, MUTEX, CV, TIMED_CV * object Address of blocking object, or NULL * spare Unused * flags Flags (none currently defined) */ typedef void (*pthreadDebugHookBlocking_t) ( pthreadDebugEvent_t, pthread_t, pthreadDebugSubstate_t, void *, void *, unsigned long); /* * Thread is being created * * event PTHREAD_DEBUG_EVENT_CREATING * thread The creating thread's TEB pointer * new_thread The new thread's TEB pointer * start_routine Address of the start routine * start_argument Argument passed to start routine * flags Flags (none currently defined) */ typedef void (*pthreadDebugHookCreating_t) ( pthreadDebugEvent_t, pthread_t, pthread_t, void *(*) (void *), void *, unsigned long); /* * Thread is running (after having blocked or been preempted) * * event PTHREAD_DEBUG_EVENT_RUNNING * thread The thread's TEB pointer * substate Thread's previous substate * previous TEB pointer for previous thread * spare Unused * flags Flags (preempted, kernel) */ typedef void (*pthreadDebugHookRunning_t) ( pthreadDebugEvent_t, pthread_t, pthreadDebugSubstate_t, pthread_t, void *, unsigned long); /* * Thread is terminating * * event PTHREAD_DEBUG_EVENT_TERMINATING * thread The thread's TEB pointer * substate Reason for termination: normal, term_cancel * (cancelled) or term_exit (pthread_exit) * result Thread's result value * spare Unused * flags Flags (locks) */ typedef void (*pthreadDebugHookTerminating_t) ( pthreadDebugEvent_t, pthread_t, pthreadDebugSubstate_t, void *, void *, unsigned long); /* * The DECthreads code has been initialized * * event PTHREAD_DEBUG_EVENT_INITIALIZED * thread TEB pointer of initializing thread * spare Unused * spare Unused * spare Unused * flags Flags (none currently defined) */ typedef void (*pthreadDebugHookInitialized_t) ( pthreadDebugEvent_t, pthread_t, void *, void *, void *, unsigned long); /* * Thread is freeing a zombie TCB * * Arguments: * * event PTHREAD_DEBUG_EVENT_FREEING * thread Thread's TEB pointer * freed TEB of thread being freed * spare Unused * spare Unused * flags Flags (none currently defined) * * Return value: * * none */ typedef void (*pthreadDebugHookFreeing_t) ( pthreadDebugEvent_t, pthread_t, pthread_t, void *, void *, unsigned long); /* * Thread is unblocked from a wait (CV, Mutex, etc.) * * Arguments: * * event PTHREAD_DEBUG_EVENT_UNBLOCK * thread Unblocking thread's TEB pointer * substate One of KERNEL, MUTEX, CV, TIMED_CV * unblock Unblocked thread's sequence number * spare Unused * flags Flags (none currently defined) * * Return value: * * none */ typedef void (*pthreadDebugHookUnblock_t) ( pthreadDebugEvent_t, pthread_t, pthreadDebugSubstate_t, pthread_t, void *, unsigned long); /* * DECthreads bugcheck (unrecoverable inconsistency) * * Arguments: * * event PTHREAD_DEBUG_EVENT_BUGCHECK * thread Bugchecking thread's TEB pointer * reason String describing reason * spare Unused argument * spare Unused argument * flags Flags (none currently defined) * * Return value: * * none */ typedef void (*pthreadDebugHookBugcheck_t) ( pthreadDebugEvent_t, pthread_t, char *, void *, void *, unsigned long); /* * DECthreads last-chance handler (exception not handled by thread) * * Arguments: * * event PTHREAD_DEBUG_EVENT_LASTCHANCE * thread Thread's TEB pointer * spare1 Unused argument * spare2 Unused argument * spare3 Unused argument * flags Flags (none currently defined) * * Return value: * * none */ typedef void (*pthreadDebugHookLastchance_t) ( pthreadDebugEvent_t, pthread_t, void *, void *, void *, unsigned long); extern int __pthread_debug_clear_event (pthreadDebugEvent_t); extern int __pthread_debug_set_hook ( pthreadDebugEvent_t, void *); extern int __pthread_debug_set_event (pthreadDebugEvent_t); /* * Restore the pointer size environment for VMS */ #if defined (_PTHREAD_ENV_ALPHA) && defined (_PTHREAD_ENV_VMS) # pragma __required_pointer_size __restore #endif #ifdef __cplusplus } #endif #endif /* _PTHREAD_DEBUG_H_ */ /* ************************************************************************* * * * Copyright 2000 Compaq Computer Corporation * * * * COMPAQ Registered in U.S. Patent and Trademark Office. * * * * Confidential computer software. Valid license from Compaq or * * authorized sublicensor required for possession, use or copying. * * Consistent with FAR 12.211 and 12.212, Commercial Computer Software, * * Computer Software Documentation, and Technical Data for Commercial * * Items are licensed to the U.S. Government under vendor's standard * * commercial license. * * * * Compaq shall not be liable for technical or editorial errors or * * omissions contained herein. The information in this document is * * subject to change without notice. * * * ************************************************************************* */ /* * @(#)$RCSfile: pthread_exc.h,v $ $Revision: 1.1.15.1 $ (DEC) $Date: 2000/03/01 15:44:47 $ */ /* * FACILITY: * * DECthreads core * * ABSTRACT: * * External definitions for DECthreads POSIX 1003.4a/D4 exception * services (ALL are non-standard, in that while resembling the * 1003.4a/D4 interfaces they report error by raising exceptions rather * than returning -1 and setting errno). * * AUTHORS: * * Paul Curtin * Dave Butenhof * * CREATION DATE: * * 27 August 1990 * * MODIFIED BY: * * Dave Butenhof * Paul Clark * Paul Curtin * Steve Johnson * Brian Keane * Peter Portante * Webb Scales * * LAST MODIFIED: * * 16 September 1998 */ #ifndef PTHREAD_EXC #define PTHREAD_EXC #ifdef __cplusplus extern "C" { #endif #if defined(vms) || defined(__vms) || defined(VMS) || defined(__VMS) # include # ifndef _TIMESPEC_T_ # define _TIMESPEC_T_ typedef struct timespec { unsigned long tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ } timespec_t; # endif #else # include # include #endif /* * The implementation makes these basic decisions */ #ifndef _POSIX_THREADS # define _POSIX_THREADS 1 #endif #ifndef _POSIX_THREAD_ATTR_STACKSIZE # define _POSIX_THREAD_ATTR_STACKSIZE 1 #endif #if _CMA_POSIX_SCHED_ # define _POSIX_THREADS_REALTIME_SCHEDULING 1 #elif defined(_POSIX_THREADS_REALTIME_SCHEDULING) # undef _POSIX_THREADS_REALTIME_SCHEDULING #endif #ifndef _POSIX_THREADS_PER_PROCESS_SIGNALS_1 # define _POSIX_THREADS_PER_PROCESS_SIGNALS_1 1 #endif #if ((_CMA_COMPILER_ != _CMA__DECCPLUS) && (_CMS_OS_ == _CMA__UNIX)) /* * Implement push and pop for cancellation handlers, using the compiler's * native try/finally constructs. */ # define pthread_cleanup_push(_routine_,_arg_) \ { \ pthread_cleanup_t _XXX_proc = (pthread_cleanup_t)(_routine_); \ pthread_addr_t _XXX_arg = (pthread_addr_t)(_arg_); \ int _XXX_completed = 0; \ try { # define pthread_cleanup_pop(_execute_) \ _XXX_completed = 1;} \ finally { \ if ((! _XXX_completed) || (_execute_)) _XXX_proc (_XXX_arg);} \ } #else /* * Implement push and pop for cancellation handlers, using TRY and ENDTRY */ # define pthread_cleanup_push(_routine_,_arg_) \ { \ pthread_cleanup_t _XXX_proc = (pthread_cleanup_t)(_routine_); \ pthread_addr_t _XXX_arg = (pthread_addr_t)(_arg_); \ int _XXX_completed = 0; \ TRY { # define pthread_cleanup_pop(_execute_) \ _XXX_completed = 1;} \ FINALLY { \ if ((! _XXX_completed) || (_execute_)) _XXX_proc (_XXX_arg);} \ ENDTRY} #endif /* * Macros used to convert normal pthread routine calls to exception * returning routines. This is done by including this file, pthread_exc.h, * in the place of pthread.h. */ #define pthread_equal_np(__t1,__t2) \ ptdexc_equal (__t1,__t2) #define pthread_equal(__t1,__t2) \ ptdexc_equal (__t1,__t2) #define pthread_attr_create(__attr) \ ptdexc_attr_create (__attr) #define pthread_attr_delete(__attr) \ ptdexc_attr_delete (__attr) #define pthread_attr_setdetach_np(__attr,__detachstate) \ ptdexc_attr_setdetach_np (__attr,__detachstate) #define pthread_attr_getdetach_np(__attr) \ ptdexc_attr_getdetach_np (__attr) #define pthread_attr_setprio(__attr,__priority) \ ptdexc_attr_setprio (__attr,__priority) #define pthread_attr_getprio(__attr) \ ptdexc_attr_getprio (__attr) #define pthread_attr_setsched(__attr,__scheduler) \ ptdexc_attr_setsched (__attr,__scheduler) #define pthread_attr_getsched(__attr) \ ptdexc_attr_getsched (__attr) #define pthread_attr_setinheritsched(__attr,__inherit) \ ptdexc_attr_setinheritsched (__attr,__inherit) #define pthread_attr_getinheritsched(__attr) \ ptdexc_attr_getinheritsched (__attr) #define pthread_attr_setstacksize(__attr,__stacksize) \ ptdexc_attr_setstacksize (__attr,__stacksize) #define pthread_attr_getstacksize(__attr) \ ptdexc_attr_getstacksize (__attr) #define pthread_attr_setguardsize_np(__attr,__guardsize) \ ptdexc_attr_setguardsize_np (__attr,__guardsize) #define pthread_attr_getguardsize_np(__attr) \ ptdexc_attr_getguardsize_np (__attr) #define pthread_bind_to_cpu_np(__thread,__mask) \ ptdexc_bind_to_cpu_np (__thread,__mask) #define pthread_create(__thread,__attr,__start_routine,__arg) \ ptdexc_create (__thread,__attr,__start_routine,__arg) #define pthread_detach(__thread) \ ptdexc_detach (__thread) #define pthread_exit(__status) \ ptdexc_exit (__status) #define pthread_get_expiration_np(__delta,__abstime) \ ptdexc_get_expiration_np (__delta,__abstime) #define pthread_join(__thread,__status) \ ptdexc_join (__thread,__status) #define pthread_setprio(__thread,__priority) \ ptdexc_setprio (__thread,__priority) #define pthread_setscheduler(__thread,__scheduler,__priority) \ ptdexc_setscheduler (__thread,__scheduler,__priority) #define pthread_yield() \ ptdexc_yield () #define pthread_self() \ ptdexc_self () #define pthread_getunique_np(__thread) \ ptdexc_getunique_np (__thread) #define pthread_getprio(__thread) \ ptdexc_getprio (__thread) #define pthread_getscheduler(__thread) \ ptdexc_getscheduler (__thread) #define pthread_mutexattr_create(__attr) \ ptdexc_mutexattr_create (__attr) #define pthread_mutexattr_delete(__attr) \ ptdexc_mutexattr_delete (__attr) #define pthread_mutexattr_setkind_np(__attr,__kind) \ ptdexc_mutexattr_setkind_np (__attr,__kind) #define pthread_mutexattr_getkind_np(__attr) \ ptdexc_mutexattr_getkind_np (__attr) #define pthread_mutexattr_setmetered_np(__attr,__meter) \ ptdexc_mutexattr_setmetered_np (__attr,__meter) #define pthread_mutexattr_getmetered_np(__attr) \ ptdexc_mutexattr_getmetered_np (__attr) #define pthread_mutex_init(__mutex,__attr) \ ptdexc_mutex_init (__mutex,__attr) #define pthread_mutex_destroy(__mutex) \ ptdexc_mutex_destroy (__mutex) #define pthread_mutex_lock(__mutex) \ ptdexc_mutex_lock (__mutex) #define pthread_mutex_trylock(__mutex) \ ptdexc_mutex_trylock (__mutex) #define pthread_mutex_unlock(__mutex) \ ptdexc_mutex_unlock (__mutex) #define pthread_condattr_create(__attr) \ ptdexc_condattr_create (__attr) #define pthread_condattr_delete(__attr) \ ptdexc_condattr_delete (__attr) #define pthread_cond_init(__cond,__attr) \ ptdexc_cond_init (__cond,__attr) #define pthread_cond_destroy(__cond) \ ptdexc_cond_destroy (__cond) #define pthread_cond_broadcast(__cond) \ ptdexc_cond_broadcast (__cond) #define pthread_cond_signal(__cond) \ ptdexc_cond_signal (__cond) #define pthread_cond_signal_int_np(__cond) \ ptdexc_cond_signal_int_np (__cond) #if _CMA_OS_ == _CMA__UNIX # define pthread_cond_sig_preempt_int_np(__cond,__arg) \ ptdexc_cond_sigprmpt_int_np (__cond,__arg) #else # define pthread_cond_sig_preempt_int_np(__cond) \ ptdexc_cond_sigprmpt_int_np (__cond) #endif #define pthread_cond_wait(__cond,__mutex) \ ptdexc_cond_wait (__cond,__mutex) #define pthread_cond_timedwait(__cond,__mutex,__abstime) \ ptdexc_cond_timedwait (__cond,__mutex,__abstime) #define pthread_once(__once_block,__init_routine) \ ptdexc_once (__once_block,__init_routine) #define pthread_keycreate(__key,__destructor) \ ptdexc_keycreate (__key,__destructor) #define pthread_setspecific(__key,__value) \ ptdexc_setspecific (__key,__value) #define pthread_getspecific(__key,__value) \ ptdexc_getspecific (__key,__value) #define pthread_cancel(__thread) \ ptdexc_cancel (__thread) #define pthread_testcancel() \ ptdexc_testcancel () #define pthread_setasynccancel(__state) \ ptdexc_setasynccancel (__state) #define pthread_setcancel(__state) \ ptdexc_setcancel (__state) #define pthread_delay_np(__interval) \ ptdexc_delay_np (__interval) #define pthread_lock_global_np() \ ptdexc_lock_global_np () #define pthread_unlock_global_np() \ ptdexc_unlock_global_np () # if _CMA_OS_ != _CMA__VMS # define pthread_sig_to_can_thread_np(__sigset,__target,__thread) \ ptdexc_sig_to_can_thread_np (__sigset,__target,__thread) # define pthread_signal_to_cancel_np(__sigset,__target) \ ptdexc_signal_to_cancel_np (__sigset,__target) # endif /* * Sample decisions for the environment types */ typedef cma_t_key pthread_key_t; typedef cma_t_address pthread_addr_t; /* * For compatibility with OSF/1 pthreads */ typedef pthread_addr_t any_t; typedef void (*pthread_cleanup_t) (pthread_addr_t arg); /* * Sample decision for a one-time initialization control block and its * initialization macro. * * Declare a one time initialization control block as: * * static pthread_once_t block = pthread_once_init; */ typedef cma_t_once pthread_once_t; #define pthread_once_init cma_once_init #define CANCEL_ON 1 #define CANCEL_OFF 0 /* * The following are the portable pthread definitions */ /* * Operations on Handles */ /* * Operations on attributes objects */ typedef cma_t_attr pthread_attr_t; /* * An attributes object is created to specify the attributes of other CMA * objects that will be created. */ void _CMA_CALL_ ptdexc_attr_create (pthread_attr_t *attr); /* * An attributes object can be deleted when it is no longer needed. */ void _CMA_CALL_ ptdexc_attr_delete (pthread_attr_t *attr); /* * Operations on threads */ typedef cma_t_thread pthread_t; typedef cma_t_start_routine pthread_startroutine_t; typedef pthread_startroutine_t pthread_func_t; #define PTHREAD_INHERIT_SCHED (int)cma_c_sched_inherit #define PTHREAD_DEFAULT_SCHED (int)cma_c_sched_use_default #define PTHREAD_CREATE_JOINABLE (int)cma_c_create_joinable #define PTHREAD_CREATE_DETACHED (int)cma_c_create_detached #if !_CMA_RT4_KTHREAD_ # define SCHED_FIFO cma_c_sched_fifo # define SCHED_RR cma_c_sched_rr # define SCHED_OTHER cma_c_sched_throughput # define SCHED_FG_NP cma_c_sched_throughput # define SCHED_BG_NP cma_c_sched_background #endif #define PRI_FIFO_MIN cma_c_prio_fifo_min #define PRI_FIFO_MAX cma_c_prio_fifo_max #define PRI_RR_MIN cma_c_prio_rr_min #define PRI_RR_MAX cma_c_prio_rr_max #define PRI_FG_MIN_NP cma_c_prio_through_min #define PRI_FG_MAX_NP cma_c_prio_through_max #define PRI_BG_MIN_NP cma_c_prio_back_min #define PRI_BG_MAX_NP cma_c_prio_back_max #define PRI_OTHER_MIN cma_c_prio_through_min #define PRI_OTHER_MAX cma_c_prio_through_max int _CMA_CALL_ ptdexc_equal ( /* Compare two handles */ pthread_t handle1, pthread_t handle2); /* * Operations to define thread creation attributes */ /* * Set or obtain the default thread priority. */ void _CMA_CALL_ ptdexc_attr_setprio ( pthread_attr_t *attr, int priority); int _CMA_CALL_ ptdexc_attr_getprio (pthread_attr_t attr); /* * Set or obtain the default scheduling algorithm */ void _CMA_CALL_ ptdexc_attr_setsched ( pthread_attr_t *attr, int scheduler); int _CMA_CALL_ ptdexc_attr_getsched ( pthread_attr_t attr); /* * Set or obtain whether a thread will use the default scheduling attributes, * or inherit them from the creating thread. */ void _CMA_CALL_ ptdexc_attr_setinheritsched ( pthread_attr_t *attr, int inherit); int _CMA_CALL_ ptdexc_attr_getinheritsched (pthread_attr_t attr); /* * Set or obtain the default stack size */ void _CMA_CALL_ ptdexc_attr_setstacksize ( pthread_attr_t *attr, long stacksize); unsigned long _CMA_CALL_ ptdexc_attr_getstacksize (pthread_attr_t attr); /* * Set or obtain the default guard size */ void _CMA_CALL_ ptdexc_attr_setguardsize_np ( pthread_attr_t *attr, long guardsize); unsigned long _CMA_CALL_ ptdexc_attr_getguardsize_np (pthread_attr_t attr); /* * Set or obtain the detach state */ void _CMA_CALL_ ptdexc_attr_setdetach_np ( pthread_attr_t *attr, int detachstate); int _CMA_CALL_ ptdexc_attr_getdetach_np (pthread_attr_t attr); /* * The following procedures can be used to control thread creation, * termination and deletion. */ /* * To create a thread object and runnable thread, a routine must be specified * as the new thread's start routine. An argument may be passed to this * routine, as an untyped address; an untyped address may also be returned as * the routine's value. An attributes object may be used to specify details * about the kind of thread being created. */ void _CMA_CALL_ ptdexc_create ( pthread_t *thread, pthread_attr_t attr, pthread_startroutine_t start_routine, pthread_addr_t arg); /* * A thread object may be "detached" to specify that the return value and * completion status will not be requested. */ void _CMA_CALL_ ptdexc_detach (pthread_t *thread); /* * A thread may terminate it's own execution. */ void _CMA_CALL_ ptdexc_exit (pthread_addr_t status); /* * A thread can await termination of another thread and retrieve the return * value of the thread. */ void _CMA_CALL_ ptdexc_join ( pthread_t thread, pthread_addr_t *status); /* * Thread Scheduling Operations */ /* * The current user_assigned priority of a thread can be changed. */ int _CMA_CALL_ ptdexc_setprio ( pthread_t thread, int priority); /* * The current user_assigned scheduler algorithm of a thread can be changed. */ int _CMA_CALL_ ptdexc_setscheduler ( pthread_t thread, int scheduler, int priority); /* * A thread may tell the scheduler that its processor can be made available. */ void _CMA_CALL_ ptdexc_yield (void); /* * Bind a thread to a particular CPU on a multiprocessor system. */ void _CMA_CALL_ ptdexc_bind_to_cpu_np ( pthread_t thread, long cpu_mask); /* * Thread Information Operations */ /* * A thread may obtain a copy of its own thread handle. */ pthread_t _CMA_CALL_ ptdexc_self (void); /* * Obtain a thread's sequence number. This will usually be a unique integer * across all threads within a process (until a large number of threads has * been created). */ long _CMA_CALL_ ptdexc_getunique_np (pthread_t *thread); /* * The current user_assigned priority of a thread can be read. */ int _CMA_CALL_ ptdexc_getprio (pthread_t thread); /* * The current user_assigned scheduler algorithm of a thread can be read. */ int _CMA_CALL_ ptdexc_getscheduler (pthread_t thread); /* * Operations on Mutexes */ #define MUTEX_FAST_NP (int)cma_c_mutex_fast #define MUTEX_RECURSIVE_NP (int)cma_c_mutex_recursive #define MUTEX_NONRECURSIVE_NP (int)cma_c_mutex_nonrecursive typedef cma_t_attr pthread_mutexattr_t; typedef cma_t_mutex pthread_mutex_t; void _CMA_CALL_ ptdexc_mutexattr_create (pthread_mutexattr_t *attr); void _CMA_CALL_ ptdexc_mutexattr_delete (pthread_mutexattr_t *attr); void _CMA_CALL_ ptdexc_mutexattr_setkind_np ( pthread_mutexattr_t *attr, int kind); int _CMA_CALL_ ptdexc_mutexattr_getkind_np (pthread_mutexattr_t attr); void _CMA_CALL_ ptdexc_mutexattr_setmetered_np ( pthread_mutexattr_t *attr, int meter); int _CMA_CALL_ ptdexc_mutexattr_getmetered_np (pthread_mutexattr_t attr); /* * The following routines create, delete, lock and unlock mutexes. */ void _CMA_CALL_ ptdexc_mutex_init ( pthread_mutex_t *mutex, pthread_mutexattr_t attr); void _CMA_CALL_ ptdexc_mutex_destroy (pthread_mutex_t *mutex); void _CMA_CALL_ ptdexc_mutex_lock (pthread_mutex_t *mutex); int _CMA_CALL_ ptdexc_mutex_trylock (pthread_mutex_t *mutex); void _CMA_CALL_ ptdexc_mutex_unlock (pthread_mutex_t *mutex); /* * Operations on condition variables */ typedef cma_t_attr pthread_condattr_t; typedef cma_t_cond pthread_cond_t; void _CMA_CALL_ ptdexc_condattr_create (pthread_condattr_t *attr); void _CMA_CALL_ ptdexc_condattr_delete (pthread_condattr_t *attr); /* * A thread can create and delete condition variables. */ void _CMA_CALL_ ptdexc_cond_init ( pthread_cond_t *cond, pthread_condattr_t attr); void _CMA_CALL_ ptdexc_cond_destroy (pthread_cond_t *cond); /* * A thread can signal to and broadcast on a condition variable. */ void _CMA_CALL_ ptdexc_cond_broadcast (pthread_cond_t *cond); void _CMA_CALL_ ptdexc_cond_signal (pthread_cond_t *cond); void _CMA_CALL_ ptdexc_cond_signal_int_np (pthread_cond_t *cond); void _CMA_CALL_ ptdexc_cond_sigprmpt_int_np ( #if _CMA_OS_ == _CMA__UNIX pthread_cond_t *condition, pthread_addr_t scp); #else pthread_cond_t *condition); #endif /* * A thread can wait for a condition variable to be signalled or broadcast. */ void _CMA_CALL_ ptdexc_cond_wait ( pthread_cond_t *cond, pthread_mutex_t *mutex); /* * Operations for timed waiting */ /* * A thread can perform a timed wait on a condition variable. */ int _CMA_CALL_ ptdexc_cond_timedwait ( pthread_cond_t *cond, pthread_mutex_t *mutex, struct timespec *abstime); /* * Operations for client initialization. */ typedef void (*pthread_initroutine_t) (void); void _CMA_CALL_ ptdexc_once ( pthread_once_t *once_block, pthread_initroutine_t init_routine); /* * Operations for per-thread context */ typedef cma_t_destructor pthread_destructor_t; /* * A unique per-thread context key can be obtained for the process */ void _CMA_CALL_ ptdexc_keycreate ( pthread_key_t *key, pthread_destructor_t destructor); /* * A thread can set a per-thread context value identified by a key. */ void _CMA_CALL_ ptdexc_setspecific ( pthread_key_t key, pthread_addr_t value); /* * A thread can retrieve a per-thread context value identified by a key. */ void _CMA_CALL_ ptdexc_getspecific ( pthread_key_t key, pthread_addr_t *value); /* * Operations for alerts. */ /* * The current thread can request that a thread terminate it's execution. */ void _CMA_CALL_ ptdexc_cancel (pthread_t thread); /* * The current thread can poll for alert delivery. */ void _CMA_CALL_ ptdexc_testcancel (void); /* * The current thread can enable or disable alert delivery (PTHREAD * "cancels"); it can control "general cancelability" (CMA "defer") or * just "asynchronous cancelability" (CMA "asynch disable"). */ int _CMA_CALL_ ptdexc_setasynccancel (int state); int _CMA_CALL_ ptdexc_setcancel (int state); #ifndef _CMA_SUPPRESS_EXTERNALS_ _CMA_IMPORT_ pthread_attr_t pthread_attr_default; _CMA_IMPORT_ pthread_mutexattr_t pthread_mutexattr_default; _CMA_IMPORT_ pthread_condattr_t pthread_condattr_default; #endif /* * Define nonportable extensions */ extern void _CMA_CALL_ ptdexc_get_expiration_np ( struct timespec *delta, struct timespec *abstime); extern void _CMA_CALL_ ptdexc_delay_np (struct timespec *interval); extern void _CMA_CALL_ ptdexc_lock_global_np (void); extern void _CMA_CALL_ ptdexc_unlock_global_np (void); #if _CMA_OS_ != _CMA__VMS extern void _CMA_CALL_ ptdexc_sig_to_can_thread_np ( sigset_t *sigset, pthread_t *target, pthread_t *thread); extern void _CMA_CALL_ ptdexc_signal_to_cancel_np ( sigset_t *sigset, pthread_t *target); #endif #ifdef __cplusplus } #endif #endif /* ************************************************************************* * * * Copyright 2000 Compaq Computer Corporation * * * * COMPAQ Registered in U.S. Patent and Trademark Office. * * * * Confidential computer software. Valid license from Compaq or * * authorized sublicensor required for possession, use or copying. * * Consistent with FAR 12.211 and 12.212, Commercial Computer Software, * * Computer Software Documentation, and Technical Data for Commercial * * Items are licensed to the U.S. Government under vendor's standard * * commercial license. * * * * Compaq shall not be liable for technical or editorial errors or * * omissions contained herein. The information in this document is * * subject to change without notice. * * * ************************************************************************* */ /* * @(#)$RCSfile: pthread_exception.h,v $ $Revision: 1.1.35.2 $ (DEC) $Date: 2000/10/19 15:13:05 $ */ /* * FACILITY: * * DECthreads core * * FILENAME: * * pthread_exception.h * * ABSTRACT: * * Header file for exception handling in C * * AUTHORS: * * Eric Roberts * Bob Conti * Dave Butenhof * * CREATION DATE: * * 15 March 1989 * * MODIFIED BY: * * Dave Butenhof * Bob Conti * Paul Curtin * Webb Scales * Peter Portante * Brian Silver * Mark Simons * Richard Love * Tom Dahl * * LAST MODIFICATION DATE: * * 21 October 1999 */ /* * This header file consists of two sections. The first is ANSI/POSIX * "clean", with no names disallowed by the standards (all names either begin * with "_" and a capital letter, or "__" and a lower case letter, or use the * POSIX 1003.1c-1995 "extension" namespace "PTHREAD" prefix with "_NP" * suffix or "pthread" prefix with "_np" suffix). The second contains the * "namespace-polluting" (non-standard) definitions that we've traditionally * documented for client use -- TRY, ENDTRY, and so forth. The two sections * each have separate "ifndef" tests, which allows this header file to be * included twice by the same module (once for the clean definitions and once * for the polluting definitions) and have everything work out nicely. Note * that always includes this header, so a separate include of * after will automatically activate the * "unclean" definitions. (A strictly conforming standard application must not * do this, since is not defined by any standard.) * * Note that on Tru64 UNIX you cannot, currently, use this header AND * (for native compiler try/except/finally handling) unless you * compile with _OSF_SOURCE defined. This is because is not * "namespace clean" for POSIX or XOPEN, and (because this header requires * definitions from ) in strict standards mode we need to "fake" a * definition that will conflict with the actual definition in * . This is OK, since, by default, all programs will be built with * _OSF_SOURCE defined (by ), and a POSIX/XOPEN conforming * program (defining _XOPEN_SOURCE=500 or _POSIX_C_SOURCE=199506L) should not * be including non-standard headers like . If you must compile * with c89, which automatically defines _XOPEN_SOURCE, but really don't wish * to require a strict XOPEN namespace, you can add "-D_OSF_SOURCE" to the c89 * command to avoid this problem. */ #ifndef _PTHREAD_EXCEPTION_CLEAN # define _PTHREAD_EXCEPTION_CLEAN # ifdef __cplusplus extern "C" { # endif /* * INCLUDE FILES */ # if defined (__cplusplus) || defined (__DECCXX) # define _PTHREAD_EXC_CXX # endif # if defined (__DECC) || defined (__decc) # define _PTHREAD_EXC_DECC # endif # if defined (VMS) || defined (__VMS) || defined (__vms) || defined (vms) # define _PTHREAD_EXC_VMS # endif # if defined (__unix__) || defined (__unix) || defined (unix) # define _PTHREAD_EXC_UNIX # endif # if defined (vax) || defined (VAX) || defined (__vax) || defined (__VAX) # define _PTHREAD_EXC_VAX # endif # if defined (__alpha) || defined (__ALPHA) # define _PTHREAD_EXC_ALPHA # endif # if defined (__ia64__) # define _PTHREAD_EXC_IA64 # endif # if defined (_M_IX86) # define _PTHREAD_EXC_X86 # endif # if !defined (_PTHREAD_EXC_DECC) && defined (_PTHREAD_EXC_VAX) # if defined (vaxc) || defined (VAXC) || defined (__vaxc) || defined (__VAXC) # define _PTHREAD_EXC_VAXC # endif # endif # if defined (_PTHREAD_EXC_DECC) && defined (_PTHREAD_EXC_VMS) # pragma __extern_model __save # pragma __extern_model __strict_refdef # define _PTHREAD_EXC_IMPORT_ extern # include # elif defined (_PTHREAD_EXC_VAXC) # pragma nostandard # define _PTHREAD_EXC_IMPORT_ globalref # else # define _PTHREAD_EXC_IMPORT_ extern # endif /* * Include the appropriate header files for the different operating systems. */ # if defined (_PTHREAD_EXC_VMS) # if defined (_PTHREAD_EXC_ALPHA) # include # endif # include # include # endif # include # include # if defined (_PTHREAD_EXC_UNIX) && defined (_PTHREAD_EXC_DECC) # ifdef _OSF_SOURCE # include /* Must be after setjmp.h */ # else extern void *__exception_info (void); # endif # define _PTHREAD_EXC_USE_NATIVE # define _PTHREAD_NATIVE_TRY __builtin_try # define _PTHREAD_NATIVE_EXCEPT __builtin_except # define _PTHREAD_NATIVE_FINALLY __builtin_finally # define _PTHREAD_NATIVE_INFO __exception_info () # define _PTHREAD_NATIVE_HANDLE EXCEPTION_EXECUTE_HANDLER # endif /* * This constant helps to identify a context block or exception created with * DECthreads BL9 or later; the new structures include a version field to * better manage future changes. */ # define _PTHREAD_EXC_NEWMAGIC 0x45586732 /* Identify ctx block with version */ # define _PTHREAD_EXC_THDBASE (_PTHREAD_EXC_NEWMAGIC | 0x01) /* * Define version constants to be put into exception structures. * * o V2 is for OpenVMS and non-native Tru64 UNIX exception handling. * o V3 is for native Tru64 UNIX exception handling (as defined before the * __flags field was added to _pthreadExcExt_t). * o V4 is for native Tru64 UNIX exception handling with the __flags field. * * This code checks the version to see how it should behave. */ # define _PTHREAD_EXC_VER_V2 2 # define _PTHREAD_EXC_VER_V3 3 # define _PTHREAD_EXC_VER_V4 4 # if defined (_PTHREAD_EXC_UNIX) && defined (_PTHREAD_EXC_DECC) # define _PTHREAD_EXC_VER_CUR _PTHREAD_EXC_VER_V4 # else # define _PTHREAD_EXC_VER_CUR _PTHREAD_EXC_VER_V2 # endif /* * NOTE: on UNIX systems, these status codes must be kept unique. We do this * arbitrarily by setting some high order bits which happen to be the same as * we use on VMS. */ # if defined (_PTHREAD_EXC_VMS) # define _PTHREAD_EXC_FACILITY 00020100000 # define _PTHREAD_STATUS_(_val_, _sev_) \ ((__pthreadStatus_t)(_PTHREAD_EXC_FACILITY | ((_val_) << 3) | (_sev_))) # else # define _PTHREAD_EXC_FACILITY 0x177db000 # define _PTHREAD_STATUS_(_val_, _sev_) \ ((__pthreadStatus_t)(_PTHREAD_EXC_FACILITY | (_val_))) # endif /* * Define all of the status codes used by DECthreads. * * For VMS, these must remain in synch with the CMA_MESSAGE.MSG message file. * * These values cannot be altered, as they have already been shipped! */ /* * Messages directly related to exceptions */ # define __pthread_exception_s _PTHREAD_STATUS_ (1, 4) # define __pthread_exccop_s _PTHREAD_STATUS_ (2, 4) # define __pthread_uninitexc_s _PTHREAD_STATUS_ (3, 4) # define __pthread_unkstatus_s _PTHREAD_STATUS_ (128, 4) # define __pthread_exccoplos_s _PTHREAD_STATUS_ (129, 4) # define __pthread_noexcmem_s _PTHREAD_STATUS_ (131, 4) /* * These should be set to match with underlying system exception codes on * platforms where that is appropriate (e.g., ss$_ codes on VMS). */ # if defined (_PTHREAD_EXC_VMS) # pragma nostandard /* * A few of these codes are somewhat imaginary, since VMS doesn't support * condition codes that very closely approximate the sense of some UNIX * signals. SIGTRAP, SIGABRT, and SIGEMT have no clear parallels, and the * values chosen are fairly arbitrary. For two others, we chose what seemed * close equivalents: SIGPIPE becomes "no mailbox", and SIGXFSZ becomes "disk * quota exceeded". */ # define __pthread_illaddr_s SS$_ACCVIO # define __pthread_exquota_s SS$_EXQUOTA # define __pthread_insfmem_s SS$_INSFMEM # define __pthread_nopriv_s SS$_NOPRIV # define __pthread_normal_s SS$_NORMAL # define __pthread_illinstr_s SS$_OPCDEC # define __pthread_resaddr_s SS$_RADRMOD # define __pthread_privinst_s SS$_OPCDEC # define __pthread_resoper_s SS$_ROPRAND # define __pthread_SIGTRAP_s SS$_BREAK # define __pthread_SIGABRT_s SS$_ABORT # define __pthread_SIGEMT_s SS$_COMPAT # define __pthread_aritherr_s SS$_FLTOVF # define __pthread_SIGSYS_s SS$_BADPARAM # define __pthread_SIGPIPE_s SS$_NOMBX # define __pthread_excpu_s SS$_EXCPUTIM # define __pthread_exfilsiz_s SS$_EXDISKQUOTA # define __pthread_intovf_s SS$_INTOVF # define __pthread_intdiv_s SS$_INTDIV # define __pthread_fltovf_s SS$_FLTOVF # define __pthread_fltdiv_s SS$_FLTDIV # define __pthread_fltund_s SS$_FLTUND # define __pthread_decovf_s SS$_DECOVF # define __pthread_subrng_s SS$_SUBRNG # define __pthread_stackovf_s SS$_STKOVF # pragma standard # else # define __pthread_illaddr_s _PTHREAD_STATUS_ (5, 4) # define __pthread_exquota_s _PTHREAD_STATUS_ (6, 4) # define __pthread_insfmem_s _PTHREAD_STATUS_ (7, 4) # define __pthread_nopriv_s _PTHREAD_STATUS_ (8, 4) # define __pthread_normal_s _PTHREAD_STATUS_ (9, 1) # define __pthread_illinstr_s _PTHREAD_STATUS_ (10, 4) # define __pthread_resaddr_s _PTHREAD_STATUS_ (11, 4) # define __pthread_privinst_s _PTHREAD_STATUS_ (12, 4) # define __pthread_resoper_s _PTHREAD_STATUS_ (13, 4) # define __pthread_SIGTRAP_s _PTHREAD_STATUS_ (14, 4) # define __pthread_SIGABRT_s _PTHREAD_STATUS_ (15, 4) # define __pthread_SIGEMT_s _PTHREAD_STATUS_ (16, 4) # define __pthread_aritherr_s _PTHREAD_STATUS_ (17, 4) # define __pthread_SIGSYS_s _PTHREAD_STATUS_ (18, 4) # define __pthread_SIGPIPE_s _PTHREAD_STATUS_ (19, 4) # define __pthread_excpu_s _PTHREAD_STATUS_ (20, 4) # define __pthread_exfilsiz_s _PTHREAD_STATUS_ (21, 4) # define __pthread_intovf_s _PTHREAD_STATUS_ (22, 4) # define __pthread_intdiv_s _PTHREAD_STATUS_ (23, 4) # define __pthread_fltovf_s _PTHREAD_STATUS_ (24, 4) # define __pthread_fltdiv_s _PTHREAD_STATUS_ (25, 4) # define __pthread_fltund_s _PTHREAD_STATUS_ (26, 4) # define __pthread_decovf_s _PTHREAD_STATUS_ (27, 4) # define __pthread_subrng_s _PTHREAD_STATUS_ (28, 4) # define __pthread_stackovf_s _PTHREAD_STATUS_ (57, 4) # endif /* * Synonyms for signal-based exception statuses. */ # define __pthread_SIGIOT_s __pthread_SIGABRT_s # define __pthread_SIGSEGV_s __pthread_illaddr_s # define __pthread_SIGBUS_s __pthread_resaddr_s # define __pthread_SIGFPE_s __pthread_aritherr_s /* * Internal DECthreads exception statuses. */ # define __pthread_cancel_s _PTHREAD_STATUS_ (48, 4) # define __pthread_exit_s _PTHREAD_STATUS_ (52, 4) /* * The DECthreads "uniplemented" status. */ # define _PTHREAD_UNIMP_S _PTHREAD_STATUS_ (61, 4) /* * TYPEDEFS */ # if defined (_PTHREAD_EXC_VMS) && defined (_PTHREAD_EXC_ALPHA) # ifdef __INITIAL_POINTER_SIZE # pragma __required_pointer_size __save # pragma __required_pointer_size __short # endif # endif typedef void *__pthreadExcAddr_t, **__pthreadExcAddr_p; typedef long __pthreadExcLong_t, *__pthreadExcLong_p; typedef short __pthreadExcShort_t, *__pthreadExcShort_p; typedef unsigned long __pthreadExcUns_t, *__pthreadExcUns_p; typedef unsigned long __pthreadStatus_t; /* * Constants for the kind of an exception object. * * There are *currently* only two kinds. In the address-kind, the identity * of an exception object is its address; in the value-kind, the * identity of an exception object is an integer, typically, * a system-defined-status-value. These coded kinds also * serve as sentinels to help detect uninitialized exceptions. */ typedef enum __pthreadExcKind_t { _PTHREAD_EXC_KIND_NONE = 0, _PTHREAD_EXC_KIND_ADDR = 0x02130455, _PTHREAD_EXC_KIND_STATUS = 0x02130456 } __pthreadExcKind_t; # if defined (_PTHREAD_EXC_VMS) # if defined (_PTHREAD_EXC_VAX) typedef int __pthreadExcJumpBuf_t[14]; # else typedef unsigned __int64 __pthreadExcJumpBuf_t[(14+8+3)]; # endif # else typedef sigjmp_buf __pthreadExcJumpBuf_t; # endif # if defined (_PTHREAD_EXC_VMS) && defined (_PTHREAD_EXC_ALPHA) typedef __int64 __pthreadExcArg_t, *__pthreadExcArg_p; # else typedef long __pthreadExcArg_t, *__pthreadExcArg_p; # endif /* * Flags which are stored in the __flags field below. */ # define _PTHREAD_EXC_FLG_NATEXC 0x1 /* __args pts to native exc */ # define _PTHREAD_EXC_FLG_HEAPARG 0x2 /* __args points to heap mem */ typedef struct __pthreadExcExt { __pthreadExcLong_t __sentinel; __pthreadExcShort_t __version; __pthreadExcShort_t __flags; # if defined (_PTHREAD_EXC_UNIX) unsigned int __reserved0; /* Alignment padding */ # endif __pthreadExcAddr_t __extend; __pthreadExcArg_p __args; } __pthreadExcExt_t; typedef struct __pthreadExcKindV1Addr { __pthreadExcKind_t __kind; # if defined (_PTHREAD_EXC_UNIX) unsigned int __reserved0; /* Alignment padding */ # endif __pthreadExcAddr_t __address; __pthreadExcUns_t __filler[6]; } __pthreadExcKindV1Addr_t; typedef struct __pthreadExcKindV1Status { __pthreadExcKind_t __kind; # if defined (_PTHREAD_EXC_UNIX) unsigned int __reserved0; /* Alignment padding */ # endif __pthreadExcUns_t __status; __pthreadExcUns_t __filler[6]; } __pthreadExcKindV1Status_t; typedef struct __pthreadExcKindAddr { __pthreadExcKind_t __kind; # if defined (_PTHREAD_EXC_UNIX) unsigned int __reserved0; /* Alignment padding */ # endif __pthreadExcAddr_t __address; __pthreadExcExt_t __ext; } __pthreadExcKindAddr_t; typedef struct __pthreadExcKindStatus { __pthreadExcKind_t __kind; # if defined (_PTHREAD_EXC_UNIX) unsigned int __reserved0; /* Alignment padding */ # endif __pthreadStatus_t __status; __pthreadExcExt_t __ext; } __pthreadExcKindStatus_t; typedef union __pthreadExceptionObj { __pthreadExcKind_t __kind; __pthreadExcKindV1Status_t __v1status; __pthreadExcKindV1Addr_t __v1address; __pthreadExcKindStatus_t __status; __pthreadExcKindAddr_t __address; } __pthreadExceptionObj_t, *__pthreadExceptionObj_p; /* * Constants for the state of handling in the current TRY clause. * * The implementations of TRY/ENDTRY use the "NONE", "ACTIVE" and "HANDLED" * states. The state variable defined by the TRY macro is set to "NONE" when * no exception has been raised, "ACTIVE" when one has been raised but has not * been caught by a CATCH clause, and "HANDLED" after the exception has been * caught and handled by some CATCH clause. */ typedef enum __pthreadExcState_t { _PTHREAD_EXC_STATE_ACTIVE = 0, /* This must be the 0 state, see pop_ctx */ _PTHREAD_EXC_STATE_NONE = 1, _PTHREAD_EXC_STATE_HANDLED = 2, _PTHREAD_EXC_STATE_POPPED = 3 } __pthreadExcState_t; /* * Structure of a context block. * * A context block is allocated in the current stack frame for each * TRY clause. These context blocks are linked to form a stack of * all current TRY blocks in the current thread. Each context block * contains a jump buffer for use by setjmp and longjmp. Note that * for binary compatibility reasonse the jump buffer must be at the * beginning. */ # if defined (_PTHREAD_EXC_VMS) # define _PTHREAD_EXC_ARGS 160 / sizeof (__pthreadExcArg_t) # endif # if defined (_PTHREAD_EXC_UNIX) /* * Define the maximum number of parameters we will save in the DECthreads * exception block. Also used to define the cut-off between the fast path * storing of a native exception and the slow path (exceptions larger than * this number of arguments take the slow path). */ # define _PTHREAD_EXC_ARGS 5 /* * Definition of a native Tru64 UNIX exception; a copy of system_exrec_type * from excpt.h (but that master definition is not included here for * namespace reasons). */ typedef struct __pthreadExcNative { long __exceptionCode; /* reason for exception */ __pthreadExcUns_t __exceptionFlags; /* in progress, e.g. unwind */ void *__exceptionRecord; /* rec chain, e.g.nested info */ void *__exceptionAddress; /* where error occurred */ __pthreadExcUns_t __numberParameters; /* # of ExceptionInformation's*/ __pthreadExcUns_t __exceptionInformation[_PTHREAD_EXC_ARGS]; } __pthreadExcNative_t; # endif typedef struct __pthreadExcCtx { __pthreadExcJumpBuf_t __jmp; /* Jump buffer */ volatile struct __pthreadExcCtx *__link; /* Link to ctx block stack */ volatile __pthreadExceptionObj_t __cur_exception; /* Copy of exception */ volatile __pthreadExcState_t __exc_state; /* State of handling for TRY */ # if defined (_PTHREAD_EXC_VMS) __pthreadExcAddr_t __current_frame; /* Addr of curr stack frame */ # if defined (_PTHREAD_EXC_VAX) __pthreadExcAddr_t __old_handler; /* Addr of prev handler */ # endif # endif # if defined (_PTHREAD_EXC_UNIX) unsigned int __reserved0; /* Alignment padding */ # endif __pthreadExcLong_t __sentinel; /* Identify ctx block */ __pthreadExcLong_t __version; /* Client context version */ # if defined (_PTHREAD_EXC_UNIX) __pthreadExcNative_t __exrec_copy; /* Copy of small foreign exc */ # endif # if defined (_PTHREAD_EXC_VMS) __pthreadExcArg_t __exc_args[_PTHREAD_EXC_ARGS]; # endif } __pthreadExcCtx_t, *__pthreadExcCtx_p; # if defined (_PTHREAD_EXC_VMS) && defined (_PTHREAD_EXC_ALPHA) # ifdef __INITIAL_POINTER_SIZE # pragma __required_pointer_size __restore # endif # endif /* * EXTERNAL ROUTINES */ # if defined (_PTHREAD_EXC_VMS) && defined (_PTHREAD_EXC_ALPHA) && defined (_PTHREAD_CORE_BUILD_) # define __pthread_exc_handler_np excCoreHandler # else # define __pthread_exc_handler_np pthread_exc_handler_np # endif # if defined (_PTHREAD_EXC_VMS) # if defined (_PTHREAD_EXC_VAX) extern int pthread_exc_savecontext_np (volatile int *); # else extern int pthread_exc_savecontext_np (volatile unsigned __int64 *); # endif extern unsigned long pthread_exc_restorecontext_np (void); # else # if defined (_PTHREAD_EXC_UNIX) /* * Tru64 UNIX already provides prototypes for setjmp and longjmp in * /usr/include/setjmp.h; the prototypes here must be compatible, so we'll * just cast the volatile jump buffer inside the macro instead of defining an * appropriate prototype as we do elsewhere. */ # define pthread_exc_savecontext_np(__env) sigsetjmp ((__env), 1) # else # define pthread_exc_savecontext_np(__env) setjmp ((__env)) # endif # endif /* * Use the most efficient code available to determine the address of the * current procedure frame on OpenVMS systems (which we need to integrate * well with native condition handling). * * - VAX C and DEC C under OpenVMS VAX support instruction "builtins" to * access general registers. * * - Otherwise, declare an extern function (part of DECthreads' assembly * code) that will return the value. */ # if defined (_PTHREAD_EXC_VMS) # if defined (_PTHREAD_EXC_VAX) && (defined (_PTHREAD_EXC_DECC) || defined (_PTHREAD_EXC_VAXC)) # if defined (_PTHREAD_EXC_VAXC) # pragma builtins # endif # define pthread_exc_fetch_fp_np() ((__pthreadExcAddr_t)_READ_GPR (13)) # else extern __pthreadExcAddr_t pthread_exc_fetch_fp_np (void); # endif # endif # if defined (_PTHREAD_EXC_USE_NATIVE) extern int pthread_exc_filter_np (__pthreadExcState_t, void *, __pthreadExceptionObj_p); # endif extern void pthread_exc_get_message_np (__pthreadExceptionObj_p, int, char *); extern void pthread_exc_pop_ctx_np (__pthreadExcCtx_p); extern void pthread_exc_push_ctx_np (__pthreadExcCtx_p); extern void pthread_exc_raise_np (__pthreadExceptionObj_p); extern void pthread_exc_raise_status_np (__pthreadStatus_t); extern void pthread_exc_report_np (__pthreadExceptionObj_p); # if defined (_PTHREAD_EXC_VMS) && !defined (_PTHREAD_SUPPRESS_EXTERNALS_) /* * System condition handler * * The declaration below is conditionalized to allow for compilation on * V7.1 systems. On OpenVMS V7.1, for the __NEW_STARLET case only, * chf$mech_array equates to a type (CHFDEF2), whereas for the default * (__OLD_STARLET) case, it equates to a structure tag. As of V7.2, * chfdef.h was modified to equate chf$mech_array to the structure tag * regardless of the __NEW_STARLET value. */ # pragma nostandard extern int # if (__VMS_VER < 70200000) && defined (__NEW_STARLET) __pthread_exc_handler_np (unsigned int[], chf$mech_array*); # else __pthread_exc_handler_np (unsigned int[], struct chf$mech_array*); # endif # ifdef _PTHREAD_EXC_VAX extern void pthread_exc_sethandler_np (int (*) (unsigned int[], struct chf$mech_array*)); # endif # pragma standard # endif /* * CONSTANTS AND MACROS */ /* * Define exception initializer macro. All exceptions *must* be initialized * using this macro. */ # if defined (_PTHREAD_EXC_UNIX) # define PTHREAD_EXCEPTION_INIT_NP(_e_) ( \ (_e_).__address.__address = (__pthreadExcAddr_t)&(_e_), \ (_e_).__address.__kind = _PTHREAD_EXC_KIND_ADDR, \ (_e_).__address.__ext.__sentinel = _PTHREAD_EXC_NEWMAGIC, \ (_e_).__address.__ext.__version = _PTHREAD_EXC_VER_CUR, \ (_e_).__address.__ext.__flags = 0, \ (_e_).__address.__ext.__reserved0 = 0, \ (_e_).__address.__ext.__extend = (__pthreadExcAddr_t)NULL, \ (_e_).__address.__ext.__args = (__pthreadExcArg_p)NULL) # else # define PTHREAD_EXCEPTION_INIT_NP(_e_) ( \ (_e_).__address.__address = (__pthreadExcAddr_t)&(_e_), \ (_e_).__address.__kind = _PTHREAD_EXC_KIND_ADDR, \ (_e_).__address.__ext.__sentinel = _PTHREAD_EXC_NEWMAGIC, \ (_e_).__address.__ext.__version = _PTHREAD_EXC_VER_CUR, \ (_e_).__address.__ext.__flags = 0, \ (_e_).__address.__ext.__extend = (__pthreadExcAddr_t)NULL, \ (_e_).__address.__ext.__args = (__pthreadExcArg_p)NULL) # endif /* * Define a function to convert a portable address exception to a platform * specific status exception. */ # if defined (_PTHREAD_EXC_VMS) # define pthread_exc_set_status_np(_e_,_s_) ( \ (_e_)->__status.__kind = _PTHREAD_EXC_KIND_STATUS, \ (_e_)->__status.__status = ((_s_) & ~7) | 4) # else # define pthread_exc_set_status_np(_e_,_s_) ( \ (_e_)->__status.__kind = _PTHREAD_EXC_KIND_STATUS, \ (_e_)->__status.__status = (_s_)) # endif /* * Define "routine" to return the status of an exception. Returns 0 if status * kind (and value of status in *s), or EINVAL if not status kind. */ # define pthread_exc_get_status_np(_e_,_s_) ( \ (_e_)->__status.__kind == _PTHREAD_EXC_KIND_STATUS ? \ (*(_s_) = (_e_)->__status.__status, 0) : \ EINVAL) /* * Define "routine" to determine if two exceptions match. */ # if defined (_PTHREAD_EXC_VMS) # define _PTHREAD_EXC_STATUS_MASK 0xffffff8 # define pthread_exc_matches_np(_e1_,_e2_) \ ((_e1_)->__kind == _PTHREAD_EXC_KIND_STATUS \ ? (((_e1_)->__status.__status & _PTHREAD_EXC_STATUS_MASK) \ == ((_e2_)->__status.__status & _PTHREAD_EXC_STATUS_MASK)) \ : (((_e1_)->__address.__kind == (_e2_)->__address.__kind) && \ ((_e1_)->__address.__address == (_e2_)->__address.__address))) # else # define pthread_exc_matches_np(_e1_,_e2_) \ (((_e1_)->__address.__kind == (_e2_)->__address.__kind) && \ ((_e1_)->__address.__address == (_e2_)->__address.__address)) # endif /* * Define "statement" for clients to use to raise an exception. */ # define PTHREAD_RAISE_NP(_e_) pthread_exc_raise_np (&(_e_)) # if defined (_PTHREAD_EXC_VMS) # if defined (_PTHREAD_EXC_VAX) /* * For OpenVMS VAX, try to integrate peacefully with native condition * handling. Save the previous handler for the frame, and restore it on * ENDTRY. The DECthreads condition handler will call the saved handler * before resignalling a condition that we don't want to handle, unless it is * the DECthreads condition handler (to avoid infinite recursion). */ # define pthread_exc_establish_np(_exc_ctx_) ( \ (_exc_ctx_)->__current_frame = pthread_exc_fetch_fp_np (), \ (_exc_ctx_)->__old_handler = \ *((__pthreadExcAddr_p)(_exc_ctx_)->__current_frame), \ *((__pthreadExcAddr_p)(_exc_ctx_)->__current_frame) = \ ((__pthreadExcAddr_t)__pthread_exc_handler_np)) # define pthread_exc_unestablish_np(_exc_ctx_) \ *(__pthreadExcAddr_p)(_exc_ctx_)->__current_frame = \ (_exc_ctx_)->__old_handler; # elif defined (_PTHREAD_EXC_ALPHA) # pragma nostandard # define pthread_exc_establish_np(_exc_ctx_) \ (_exc_ctx_)->__current_frame = \ ((__pthreadExcAddr_t)pthread_exc_fetch_fp_np ()); \ lib$establish (__pthread_exc_handler_np); # pragma standard # define pthread_exc_unestablish_np(_exc_ctx_) # else # error "Unrecognized architecture for OpenVMS" # endif # else # define pthread_exc_establish_np(_exc_ctx_) # define pthread_exc_unestablish_np(_exc_ctx_) # endif /* * Define version constants to be put into exception context structures. * * o V2 is for OpenVMS and non-native Digital UNIX exception handling. * o V3 is for native Digital UNIX exception handling. * o V4 was added in Digital UNIX V4.0D (with the __reserved0 field). * o V5 is for support of UNIX foreign exceptions (space added to hold a copy * of a small native exception with arguments). * * This code checks the version to see how it should behave. */ # define _PTHREAD_EXC_CTX_V2 2 # define _PTHREAD_EXC_CTX_V3 3 # define _PTHREAD_EXC_CTX_V4 4 # define _PTHREAD_EXC_CTX_V5 5 # if defined (_PTHREAD_EXC_USE_NATIVE) # if defined (_PTHREAD_EXC_UNIX) # define _PTHREAD_EXC_CTX_CUR _PTHREAD_EXC_CTX_V5 # else # define _PTHREAD_EXC_CTX_CUR _PTHREAD_EXC_CTX_V4 # endif # else # define _PTHREAD_EXC_CTX_CUR _PTHREAD_EXC_CTX_V2 # endif /* * Start a new TRY block, which may contain exception handlers. * * For Tru64 UNIX: * * Set up a native C "try {} except() {}" block. Note that previous * implementations of TRY/ENDTRY on Tru64 UNIX used setjmp/longjmp as * described below. We still have to use a context block to make sure * pthread_exc_raise_np() will know how to raise the exception. So we * allocate a context block on the stack to remember the current exception. * Push it on the context block stack. Initialize this context block to * indicate that no exception is active. Then we enter the while loop * surrounding the native try block. The try block guards a block of * statements ended by one of the following macros: CATCH, CATCH_ALL, * FINALLY or ENDTRY. * * For all other platforms: * * Allocate a context block on the stack to remember the current exception. * Push it on the context block stack. Initialize this context block to * indicate that no exception is active. Do a SETJMP to snapshot this * environment (or return to it). Then, start a block of statements to be * guarded by the TRY clause. This block will be ended by one of the * following macros: CATCH, CATCH_ALL, FINALLY or ENDTRY. */ # if defined (_PTHREAD_EXC_VMS) # define _PTHREAD_INIT_CTX(_ctx_) \ PTHREAD_EXCEPTION_INIT_NP (_ctx_.__cur_exception); \ _ctx_.__cur_exception.__kind = _PTHREAD_EXC_KIND_STATUS; \ _ctx_.__exc_state = _PTHREAD_EXC_STATE_NONE; \ _ctx_.__sentinel = _PTHREAD_EXC_NEWMAGIC; \ _ctx_.__version = _PTHREAD_EXC_CTX_CUR; \ _ctx_.__exc_args[0] = (__pthreadExcArg_t)0 # else # define _PTHREAD_INIT_CTX(_ctx_) \ PTHREAD_EXCEPTION_INIT_NP (_ctx_.__cur_exception); \ _ctx_.__cur_exception.__kind = _PTHREAD_EXC_KIND_STATUS; \ _ctx_.__exc_state = _PTHREAD_EXC_STATE_NONE; \ _ctx_.__sentinel = _PTHREAD_EXC_NEWMAGIC; \ _ctx_.__version = _PTHREAD_EXC_CTX_CUR # endif # if defined (_PTHREAD_EXC_USE_NATIVE) # define PTHREAD_TRY_NP \ { \ __pthreadExcCtx_t __exc_ctx__; \ _PTHREAD_INIT_CTX (__exc_ctx__); \ pthread_exc_push_ctx_np (&__exc_ctx__); \ while (__exc_ctx__.__exc_state != _PTHREAD_EXC_STATE_HANDLED) { \ _PTHREAD_NATIVE_TRY { \ if (__exc_ctx__.__exc_state == _PTHREAD_EXC_STATE_NONE) { /* user's block of code goes here */ # else # define PTHREAD_TRY_NP \ { \ __pthreadExcCtx_t __exc_ctx__; \ _PTHREAD_INIT_CTX (__exc_ctx__); \ pthread_exc_push_ctx_np (&__exc_ctx__); \ pthread_exc_establish_np (&__exc_ctx__); \ if (!pthread_exc_savecontext_np (__exc_ctx__.__jmp)) { /* user's block of code goes here */ # endif /* * Define an PTHREAD_CATCH_NP(_e_) clause (or exception handler). * * For all platforms: * * First, end the prior block. Then, check if the current exception matches * what the user is trying to catch with the CATCH clause. If there is a * match, a variable is declared to support lexical nesting of * PTHREAD_RERAISE_NP statements, and the state of the current exception is * changed to "handled". * * For Tru64 UNIX: * Note we have to make sure we are in the correct state to deal with with * the exception at all. */ # if defined (_PTHREAD_EXC_USE_NATIVE) # define PTHREAD_CATCH_NP(_e_) \ } \ if ((__exc_ctx__.__exc_state == _PTHREAD_EXC_STATE_ACTIVE) \ && (pthread_exc_matches_np ( \ &__exc_ctx__.__cur_exception, \ &(_e_)))) { \ __pthreadExceptionObj_p PTHREAD_THIS_CATCH_NP = \ (__pthreadExceptionObj_p)&__exc_ctx__.__cur_exception; \ __exc_ctx__.__exc_state = _PTHREAD_EXC_STATE_HANDLED; /* user's block of code goes here */ # else # define PTHREAD_CATCH_NP(_e_) \ } \ else if (pthread_exc_matches_np (&__exc_ctx__.__cur_exception, &(_e_))) { \ __pthreadExceptionObj_p PTHREAD_THIS_CATCH_NP = \ (__pthreadExceptionObj_p)&__exc_ctx__.__cur_exception; \ __exc_ctx__.__exc_state = _PTHREAD_EXC_STATE_HANDLED; /* user's block of code goes here */ # endif /* * Define an PTHREAD_CATCH_ALL_NP clause (or "catchall" handler). * * For all other platforms: * * First, end the prior block. Then, unconditionally, let execution enter * into the catchall code. As with a normal catch, a variable is declared * to support lexical nesting of PTHREAD_RERAISE_NP statements, and the * state of the current exception is changed to "handled". * * For Tru64 UNIX: * Note we have to make sure we are in the correct state to deal with with * the exception at all. */ # if defined (_PTHREAD_EXC_USE_NATIVE) # define PTHREAD_CATCH_ALL_NP \ } \ if (__exc_ctx__.__exc_state == _PTHREAD_EXC_STATE_ACTIVE) { \ __pthreadExceptionObj_p PTHREAD_THIS_CATCH_NP = \ (__pthreadExceptionObj_p)&__exc_ctx__.__cur_exception; \ __exc_ctx__.__exc_state = _PTHREAD_EXC_STATE_HANDLED; /* user's block of code goes here */ # else # define PTHREAD_CATCH_ALL_NP \ } \ else { \ __pthreadExceptionObj_p PTHREAD_THIS_CATCH_NP = \ (__pthreadExceptionObj_p)&__exc_ctx__.__cur_exception; \ __exc_ctx__.__exc_state = _PTHREAD_EXC_STATE_HANDLED; /* user's block of code goes here */ # endif /* * Define a PTHREAD_RERAISE_NP statement. * * This "statement" is valid only if lexically nested in a CATCH or * CATCH_ALL clause. Reraise the current lexically visible exception. */ # define PTHREAD_RERAISE_NP pthread_exc_raise_np (PTHREAD_THIS_CATCH_NP) /* * Define a PTHREAD_FINALLY_NP clause * * For all platforms: * * This "keyword" starts a PTHREAD_FINALLY_NP clause. It must appear before * an ENDTRY. A PTHREAD_FINALLY_NP clause will be entered after normal exit * of the TRY block, or if an unhandled exception tries to propagate * out of the TRY block. * * Unlike Modula 3's TRY clause, we do not expend overhead trying to * enforce that FINALLY be mutually exclusive with CATCH clauses. Currently, * if they are used together, then control will drop into a FINALLY clause * under the following conditions: * o normal exit from TRY, * o an exception is raised and no CATCH is present (recommended usage) * o CATCH's are present but none matches the exception. * o CATCH's are present and one matches the exception, but it * does not raise or reraise any exceptions. * That is, FINALLY is always entered after TRY unless a CATCH clause raises * (or re-raises) an exception. * * ** WARNING ** * You should *avoid* using FINALLY with CATCH clauses, that is, use it * only as TRY {} FINALLY {} ENDTRY. Source code that combines CATCHes * with FINALLY in the same TRY clause is considered "unsupported" * -- that is, such code may be broken by a future version of this * package. * * There are several reasons this restriction is necessary: * o FINALLY may be added to C++ and its combination with CATCH * clauses may have different semantics than implemented by these macros. * o The restriction is consistant with the same restriction in Modula 3 * o It allows the use of the 2-phase or "debugging" implementation * technique of the SRC exception package for these same macros. */ # if defined (_PTHREAD_EXC_USE_NATIVE) # define PTHREAD_FINALLY_NP \ } \ if (__exc_ctx__.__exc_state == _PTHREAD_EXC_STATE_NONE) { \ pthread_exc_pop_ctx_np (&__exc_ctx__); \ __exc_ctx__.__exc_state = _PTHREAD_EXC_STATE_HANDLED; \ } \ { \ __pthreadExceptionObj_p PTHREAD_THIS_CATCH_NP = \ (__pthreadExceptionObj_p)&__exc_ctx__.__cur_exception; /* user's block of code goes here */ # else # define PTHREAD_FINALLY_NP \ } \ if (__exc_ctx__.__exc_state == _PTHREAD_EXC_STATE_NONE) \ pthread_exc_pop_ctx_np (&__exc_ctx__); \ { \ __pthreadExceptionObj_p PTHREAD_THIS_CATCH_NP = \ (__pthreadExceptionObj_p)&__exc_ctx__.__cur_exception; /* user's block of code goes here */ # endif /* * End the whole TRY clause * * For Tru64 UNIX: * There are two main parts to the operation to this macro. The first thing * we do is close of the previous block. Then we define the except clause * for the native try/except block and then we close out the while loop. * The while loop is used to drive the state machine which the TRY macro * began to setup. If we have reached this point in the loop and the state * of the exception is "ACTIVE" we will raise the exception to allow * another frame to handle it. Note that we don't have to remove the * context block from the stack since the process of raising an exception * already does. If the state is "NONE" when we reach this point, we remove * the context block and change our state to "HANDLED" so that we can exit * TRY block normally. * * The except clause is what causes the state to be changed from "NONE" to * "ACTIVE". When a native exception is raised, the except clause calls the * filter routine to decide if the exception should be handled. The filter * is called with the current state of our TRY block, the exception which * is being raised and the __pthreadExceptionObj_t structure to be filled * in should we want to handle the exception. The filter asks if the * exception is a native DECthreads exception being raised. If so, the * exception structure is filled in and then exception facility called the * exception block defined after the except statement. The exception block * simply changes the state of our TRY block from "NONE" to "ACTIVE". We * have now "caught" the exception and we loop back up to beginning of the * TRY block and look for any CATCH blocks or a FINALLY block to execute. * * For all other platforms: * We close off the block for the previous block and then tear down the * context we established in the opening TRY. If an exception never * occurred or we did not handle the exception, we pop the context block * off the context stack. Note that popping the context block off the stack * will cause an exception to be raised if the context block describes an * unhandled exception. */ # if defined (_PTHREAD_EXC_USE_NATIVE) # define PTHREAD_ENDTRY_NP \ } \ if ((__exc_ctx__.__exc_state == _PTHREAD_EXC_STATE_NONE) \ || (__exc_ctx__.__exc_state == _PTHREAD_EXC_STATE_ACTIVE)) \ pthread_exc_pop_ctx_np (&__exc_ctx__); \ __exc_ctx__.__exc_state = _PTHREAD_EXC_STATE_HANDLED; \ } \ _PTHREAD_NATIVE_EXCEPT (pthread_exc_filter_np ( \ __exc_ctx__.__exc_state, \ (void *)_PTHREAD_NATIVE_INFO, \ (__pthreadExceptionObj_p)&__exc_ctx__.__cur_exception)) { \ __exc_ctx__.__exc_state = _PTHREAD_EXC_STATE_ACTIVE; \ } \ } \ } # else # define PTHREAD_ENDTRY_NP \ } \ pthread_exc_unestablish_np (&__exc_ctx__); \ if ((__exc_ctx__.__exc_state == _PTHREAD_EXC_STATE_NONE) \ || (__exc_ctx__.__exc_state == _PTHREAD_EXC_STATE_ACTIVE)) \ pthread_exc_pop_ctx_np (&__exc_ctx__); \ } # endif /* * Define the exception variables */ # if defined (__STDC__) || defined (_PTHREAD_EXC_DECC) || defined (_PTHREAD_EXC_CXX) # define _PTHREAD_EXCNAME(name) pthread_exc_##name##_e # define _PTHREAD_PTDNAME(name) pthread_##name##_e # else # define _PTHREAD_EXCNAME(name) pthread_exc_/**/name/**/_e # define _PTHREAD_PTDNAME(name) pthread_/**/name/**/_e # endif # if !defined (_EXC_NO_EXCEPTIONS_) && !defined (_PTHREAD_CORE_BUILD_) _PTHREAD_EXC_IMPORT_ __pthreadExceptionObj_t _PTHREAD_EXCNAME (uninitexc), _PTHREAD_EXCNAME (illaddr), _PTHREAD_EXCNAME (exquota), _PTHREAD_EXCNAME (insfmem), _PTHREAD_EXCNAME (nopriv), _PTHREAD_EXCNAME (illinstr), _PTHREAD_EXCNAME (resaddr), _PTHREAD_EXCNAME (privinst), _PTHREAD_EXCNAME (resoper), _PTHREAD_EXCNAME (SIGTRAP), _PTHREAD_EXCNAME (SIGABRT), _PTHREAD_EXCNAME (SIGEMT), _PTHREAD_EXCNAME (aritherr), _PTHREAD_EXCNAME (SIGSYS), _PTHREAD_EXCNAME (SIGPIPE), _PTHREAD_EXCNAME (excpu), _PTHREAD_EXCNAME (exfilsiz), _PTHREAD_EXCNAME (intovf), _PTHREAD_EXCNAME (intdiv), _PTHREAD_EXCNAME (fltovf), _PTHREAD_EXCNAME (fltdiv), _PTHREAD_EXCNAME (fltund), _PTHREAD_EXCNAME (decovf), _PTHREAD_EXCNAME (subrng), _PTHREAD_PTDNAME (cancel), _PTHREAD_PTDNAME (exit), _PTHREAD_PTDNAME (stackovf), _PTHREAD_EXCNAME (noexcmem); # define pthread_exc_SIGIOT_e pthread_exc_SIGABRT_e # define pthread_exc_SIGSEGV_e pthread_exc_illaddr_e # define pthread_exc_SIGBUS_e pthread_exc_resaddr_e # define pthread_exc_SIGFPE_e pthread_exc_aritherr_e # define pthread_exc_SIGILL_e pthread_exc_illinstr_e # endif # if defined (_PTHREAD_EXC_DECC) && defined (_PTHREAD_EXC_VMS) # pragma __extern_model __restore # elif defined (_PTHREAD_EXC_VAXC) # pragma standard # endif # ifdef __cplusplus } # endif #endif /* _PTHREAD_EXCEPTION_CLEAN */ /* * The following section of this file contains definitions which are not in * the protected part of the namespace. */ #if !defined (_PTHREAD_EXCEPTION_POLLUTING) && !defined (_PTHREAD_EXC_INCL_CLEAN) # define _PTHREAD_EXCEPTION_POLLUTING # ifdef __cplusplus extern "C" { # endif /* * Define external version of status codes */ # define pthread_exception_s __pthread_exception_s # define pthread_exccop_s __pthread_exccop_s # define pthread_uninitexc_s __pthread_uninitexc_s # define pthread_unkstatus_s __pthread_unkstatus_s # define pthread_exccoplos_s __pthread_exccoplos_s # define pthread_noexcmem_s __pthread_noexcmem_s # define pthread_illaddr_s __pthread_illaddr_s # define pthread_exquota_s __pthread_exquota_s # define pthread_nopriv_s __pthread_nopriv_s # define pthread_insfmem_s __pthread_insfmem_s # define pthread_normal_s __pthread_normal_s # define pthread_illinstr_s __pthread_illinstr_s # define pthread_resaddr_s __pthread_resaddr_s # define pthread_privinst_s __pthread_privinst_s # define pthread_resoper_s __pthread_resoper_s # define pthread_SIGTRAP_s __pthread_SIGTRAP_s # define pthread_SIGABRT_s __pthread_SIGABRT_s # define pthread_SIGEMT_s __pthread_SIGEMT_s # define pthread_aritherr_s __pthread_aritherr_s # define pthread_SIGSYS_s __pthread_SIGSYS_s # define pthread_SIGPIPE_s __pthread_SIGPIPE_s # define pthread_excpu_s __pthread_excpu_s # define pthread_exfilsiz_s __pthread_exfilsiz_s # define pthread_intovf_s __pthread_intovf_s # define pthread_intdiv_s __pthread_intdiv_s # define pthread_fltovf_s __pthread_fltovf_s # define pthread_fltdiv_s __pthread_fltdiv_s # define pthread_fltund_s __pthread_fltund_s # define pthread_decovf_s __pthread_decovf_s # define pthread_subrng_s __pthread_subrng_s # define pthread_stackovf_s __pthread_stackovf_s # define pthread_SIGIOT_s __pthread_SIGABRT_s # define pthread_SIGSEGV_s __pthread_illaddr_s # define pthread_SIGBUS_s __pthread_resaddr_s # define pthread_SIGFPE_s __pthread_aritherr_s # define pthread_cancel_s __pthread_cancel_s # define pthread_exit_s __pthread_exit_s typedef __pthreadExceptionObj_t EXCEPTION; /* * Define the documented ("polluted") external names for the exception * macros. */ # define EXCEPTION_INIT(__e) PTHREAD_EXCEPTION_INIT_NP (__e) # define RAISE(__e) PTHREAD_RAISE_NP (__e) # define TRY PTHREAD_TRY_NP # define ENDTRY PTHREAD_ENDTRY_NP # define FINALLY PTHREAD_FINALLY_NP # define CATCH_ALL PTHREAD_CATCH_ALL_NP # define RERAISE PTHREAD_RERAISE_NP # define THIS_CATCH PTHREAD_THIS_CATCH_NP # define CATCH(__e) PTHREAD_CATCH_NP (__e) # ifdef __cplusplus } # endif #endif /* ************************************************************************* * * * Copyright 2000 Compaq Computer Corporation * * * * COMPAQ Registered in U.S. Patent and Trademark Office. * * * * Confidential computer software. Valid license from Compaq or * * authorized sublicensor required for possession, use or copying. * * Consistent with FAR 12.211 and 12.212, Commercial Computer Software, * * Computer Software Documentation, and Technical Data for Commercial * * Items are licensed to the U.S. Government under vendor's standard * * commercial license. * * * * Compaq shall not be liable for technical or editorial errors or * * omissions contained herein. The information in this document is * * subject to change without notice. * * * ************************************************************************* */ /* * @(#)$RCSfile: pthread_trace.h,v $ $Revision: 1.1.31.4 $ (DEC) $Date: 2000/08/01 17:07:35 $ */ /* * FACILITY: * * DECthreads POSIX 1003.1c * * ABSTRACT: * * External definitions for DECthreads tracing functions. * * IMPORTANT: * ---------- * * The interfaces defined in this header file are intended for use only * by debuggers and analysis tools. The interfaces WILL change * incompatibly when such changes are necessary to fix problems, or to * improve the exchange of information between debuggers and thread * library. * * *************************************************** * Do not use the interfaces described in this header * unless you are prepared to rebuild (and potentially * recode) on each release of the operating system. * *************************************************** * * AUTHORS: * * Dave Butenhof * * CREATION DATE: * * 9 June 1997 * * MODIFIED BY: * * Dave Butenhof * Richard Love * Peter Portante * Webb Scales * Mark Simons * Tom Dahl * */ #ifndef _PTHREAD_TRACE_H_ # define _PTHREAD_TRACE_H_ #ifdef __cplusplus extern "C" { #endif #include #include #include #ifndef _DECTHREADS_ # error " depends upon DECthreads internals" #endif /* * The trace version number comprises a major and minor version into one * number. Conceptually, the version number is of the form "V##.##", where the * number before the decimal point is the major version, and the number * following the decimal point is the minor version. The minor version can * range between 0 and 99 inclusive. */ #define PTHREAD_TRACE_VERSION 100 /* Current interface version */ /* * GENERAL NOTES ON USING THIS HEADER * * The header describes the functional interface and data * structures used to communicate with the DECthreads tracing facility. This * facility is designed to support the collection of realtime "event" data on * the operation of multithreaded programs. Note that, like any method of * observation applied to any phenomenon, use of this facility will perturb * the execution of the application being observed. This being the case, there * can be no guarantee that information abstracted from such analysis will * accurately reflect the behavior of the "real" application. Nevertheless, in * most cases the information will approximate the real application's behavior * closely enough to be of some use. */ /* * MACROS */ /* * TYPEDEFS */ /* * On OpenVMS Alpha, we specify long pointer sizes for all pointers. To make * things simple, we just compile the entire header inside an explicit long * pointer region. Since this header is used only to build certain types of * DEVELOPMENT TOOLS, and is never needed for any end user programs, it's * reasonable to require that it be compiled using a recent version of DEC C. * (Unfortunately, DEC C++ does not yet support long pointer access on OpenVMS * Alpha, and is therefore not supported. DEC C++, or other C++ compilers, may * be used on UNIX or OpenVMS VAX.) */ #if defined (_PTHREAD_ENV_ALPHA) && defined (_PTHREAD_ENV_VMS) # ifndef __INITIAL_POINTER_SIZE # ifdef __cplusplus # error " requires pointer size support and cannot be used under DEC C++" # else # error " requires DEC C version 5.0 or later, with pointer size support" # endif # endif # pragma __required_pointer_size __save # pragma __required_pointer_size __long #endif /* * Define the maximum number of arguments allowed in a single trace record. * This is arbitrary, but having a limit makes processing easier. */ #define PTHREAD_TRACE_MAXARGS 64 /* * Trace event identifier. This can be viewed as either an integer ID, or as * a structure consisting of three fields: * * 1) "object": a byte (8 bits) describing the type of object to which the * event applies. May be taken as an integer code, or as a single ASCII * character. * 2) "operation": A word (16 bits) describing the operation applied to an * object. May be taken as an integer code, or as two ASCII characters. * 3) "flags": a binary field of 8 flag bits * * The integer type pthreadTraceEvent_t is the usual representation, but you * can use pthreadTraceEventStruct_t to easily extract or view the individual * fields. */ typedef int pthreadTraceEvent_t; typedef struct pthreadTraceEventStruct_tag { unsigned int object : 8; /* The object code */ unsigned int operation : 16; /* The operation code */ unsigned int flags : 8; /* The status flags */ } pthreadTraceEventStruct_t; typedef union pthreadTraceEventUnion_tag { pthreadTraceEvent_t mask; pthreadTraceEventStruct_t fields; } pthreadTraceEventUnion_t; /* * Standard event ID object values. Lowercase letters are reserved for user * events. A name for these events may be provided by writing an event.setname * event with arguments of type OBJECT and NAME. (For example, OBJECT='s', * NAME='server'). */ typedef enum pthreadTraceObject_tag { PTHREAD_TRACE_OBJ_ANALYZE = 'A', /* Event analysis tool */ PTHREAD_TRACE_OBJ_INTERRUPT = 'B', /* Software interrupts (ASTs/Signals) */ PTHREAD_TRACE_OBJ_COND = 'C', /* Condition variable */ PTHREAD_TRACE_OBJ_KERNEL = 'D', /* DECthreads dispatcher */ PTHREAD_TRACE_OBJ_EVENT = 'E', /* The event stream */ PTHREAD_TRACE_OBJ_EF = 'F', /* Event flag upcalls */ PTHREAD_TRACE_OBJ_DEBUG = 'G', /* "Gofer"? Debug-related work */ PTHREAD_TRACE_OBJ_HIBER = 'H', /* $HIBER/$WAKE upcalls */ PTHREAD_TRACE_OBJ_IMS = 'I', /* Inner mode semaphore upcalls */ PTHREAD_TRACE_OBJ_KEY = 'K', /* Thread-specific data key */ PTHREAD_TRACE_OBJ_LOCK = 'L', /* Read-write lock */ PTHREAD_TRACE_OBJ_MUTEX = 'M', /* Mutex */ PTHREAD_TRACE_OBJ_ONCE = 'O', /* One-time init routine */ PTHREAD_TRACE_OBJ_PRIVATE = 'P', /* DECthreads library generic */ PTHREAD_TRACE_OBJ_SYSTEM = 'S', /* Used to block in system */ PTHREAD_TRACE_OBJ_THREAD = 'T', /* Thread */ PTHREAD_TRACE_OBJ_USER = 'U', /* Generic user event */ PTHREAD_TRACE_OBJ_VP = 'V', /* DECthreads virtual processor */ PTHREAD_TRACE_OBJ_CTX = 'W', /* Context wait upcalls */ PTHREAD_TRACE_OBJ_EXIT = 'X', /* $EXIT/$FORCEX upcalls */ PTHREAD_TRACE_OBJ_PGFLT = 'Y', /* Pagefault upcalls */ PTHREAD_TRACE_OBJ_notused = '\0' /* End of list placeholder */ } pthreadTraceObject_t; /* * Standard event ID operation values. Codes that begin with a lowercase * letter are reserved for user events. A name for these events may be * provided by writing an event.setname event with arguments of type OPERATION * and NAME. (For example, OPERATION='t', NAME='tune'). User events may also * use the standard operation types. (Note: in this list, the indented codes * represent convenience aliases to a "base code" -- for example, CREATE is an * alias to INIT.) */ #pragma message save #pragma message disable multichar typedef enum pthreadTraceOperation_tag { PTHREAD_TRACE_OP_APPLICATION= 'IA', /* Application info */ PTHREAD_TRACE_OP_ASSERT = 'AS', /* Assertion check */ PTHREAD_TRACE_OP_BLOCK = 'BL', /* Thread blocking itself */ PTHREAD_TRACE_OP_CANCEL = 'CA', /* pthread_cancel */ PTHREAD_TRACE_OP_CATCH = 'CE', /* Catch DECthreads exception */ PTHREAD_TRACE_OP_CREATE = 'IN', /* Create (alias for INIT) */ PTHREAD_TRACE_OP_DESTROY = 'DE', /* Destroy/Delete */ PTHREAD_TRACE_OP_DETACH = 'DT', /* Detach a thread */ PTHREAD_TRACE_OP_ENTER = 'NT', /* vp.enter */ PTHREAD_TRACE_OP_EXCEPT = 'EX', /* Raise thread exception */ PTHREAD_TRACE_OP_EXIT = 'XT', /* vp.exit/pthread_exit */ PTHREAD_TRACE_OP_GETPROP = 'GP', /* Get object property (TSD) */ PTHREAD_TRACE_OP_HEADER = 'HD', /* event.header (special fmt) */ PTHREAD_TRACE_OP_IMAGE = 'II', /* Binary image info */ PTHREAD_TRACE_OP_INIT = 'IN', /* Initialize/Create */ PTHREAD_TRACE_OP_JOIN = 'JN', /* Join with thread */ PTHREAD_TRACE_OP_KILL = 'KI', /* pthread_kill */ PTHREAD_TRACE_OP_LOCK = 'LK', /* Lock mutex, rwl */ PTHREAD_TRACE_OP_NULL = 'NL', /* No (or generic) operation */ PTHREAD_TRACE_OP_ONCE = 'ON', /* Call to pthread_once */ PTHREAD_TRACE_OP_PREEMPT = 'PR', /* Thread preemption */ PTHREAD_TRACE_OP_PROCESS = 'IP', /* Process info */ PTHREAD_TRACE_OP_READY = 'RD', /* Thread is readied to run */ PTHREAD_TRACE_OP_RESUME = 'RE', /* Resume a thread */ PTHREAD_TRACE_OP_RUN = 'RN', /* Thread is running */ PTHREAD_TRACE_OP_SETCAN = 'SC', /* Set thread cancelation */ PTHREAD_TRACE_OP_SETNAME = 'NA', /* Change name of object */ PTHREAD_TRACE_OP_SETPROP = 'SP', /* Set object property */ PTHREAD_TRACE_OP_SETSCHED = 'SD', /* Set scheduling */ PTHREAD_TRACE_OP_SIGINT = 'SI', /* Signal from interrupt */ PTHREAD_TRACE_OP_SIGNAL = 'SG', /* Signal/broadcast a cond */ PTHREAD_TRACE_OP_SIGWAIT = 'SW', /* sigwait */ PTHREAD_TRACE_OP_SEARCH = 'SE', /* Snoop other VP's ready q's */ PTHREAD_TRACE_OP_STACKHIGH = 'SH', /* Change in stack highwater */ PTHREAD_TRACE_OP_START = 'ST', /* Thread start */ PTHREAD_TRACE_OP_SUSPEND = 'SU', /* Suspend a thread */ PTHREAD_TRACE_OP_SYSTEM = 'IS', /* System info */ PTHREAD_TRACE_OP_TERM = 'TR', /* Thread terminate */ PTHREAD_TRACE_OP_UNBLOCK = 'UB', /* Thread being unblocked */ PTHREAD_TRACE_OP_UNLOCK = 'UL', /* Unlock a mutex or rwl */ PTHREAD_TRACE_OP_WAIT = 'WA', /* Wait for a condition var */ PTHREAD_TRACE_OP_WRITE = 'WR', /* Write (e.g. trace buffer) */ PTHREAD_TRACE_OP_YIELD = 'YE' /* Thread yield */ } pthreadTraceOperation_t; #pragma message restore /* * Event ID status flags: */ typedef enum pthreadTraceStatus_tag { PTHREAD_TRACE_STAT_FAIL = 0x01, /* Operation failed */ PTHREAD_TRACE_STAT_MULTIPLE = 0x02, /* Multiple targets */ PTHREAD_TRACE_STAT_NONBLOCK = 0x04, /* Nonblocking (trylock) */ PTHREAD_TRACE_STAT_TIMED = 0x08, /* Timed operation */ PTHREAD_TRACE_STAT_USER = 0x10, /* pthread_trace_write_np */ PTHREAD_TRACE_STAT_PRIVATE = 0x20, /* DECthreads debug event */ PTHREAD_TRACE_STAT_CANCEL = 0x40, /* Operation cancelled */ PTHREAD_TRACE_STAT_REQUEST = 0x80 /* Requesting (part 1) op */ } pthreadTraceStatus_t; /* * Help in constructing (or deconstructing) event IDs: */ #define PTHREAD_TRACE_ID_OBJ_M 0x000000ff /* Mask for OBJECT */ #define PTHREAD_TRACE_ID_OP_M 0x00ffff00 /* Mask for OPERATION */ #define PTHREAD_TRACE_ID_STS_M 0xff000000 /* Mask for STATUS */ #define PTHREAD_TRACE_ID_OBJ_B 0 /* Initial bit for OBJECT */ #define PTHREAD_TRACE_ID_OP_B 8 /* Initial bit for OPERATION */ #define PTHREAD_TRACE_ID_STS_B 24 /* Initial bit for STATUS */ /* * This macro constructs an event ID from an object, operation, and status * set. */ #define pthreadTraceMakeId(_ob,_op,_st) ((((_st<<16)|(_op))<<8)|(_ob)) /* * These are the "trace classes" that can be selected for recording and/or * analysis. */ typedef enum pthreadTraceClass_tag { PTHREAD_TRACE_CLASS_COND = 0x0001, /* Condition var ops */ PTHREAD_TRACE_CLASS_ERROR = 0x0002, /* Errors */ PTHREAD_TRACE_CLASS_KEY = 0x0004, /* TSD ops */ PTHREAD_TRACE_CLASS_LOCK = 0x0008, /* R/W lock ops */ PTHREAD_TRACE_CLASS_MUTEX = 0x0010, /* Mutex ops */ PTHREAD_TRACE_CLASS_ONCE = 0x0020, /* Once time init */ PTHREAD_TRACE_CLASS_SCHED = 0x0040, /* Scheduling ops */ PTHREAD_TRACE_CLASS_THREAD = 0x0080, /* Thread ops */ PTHREAD_TRACE_CLASS_USER = 0x0100, /* User tracepoints */ /* * Following are INTERNAL to DECthreads, and will result in data that * cannot be analyzed by external tools. (Some will not occur except * in internal debug builds, for performance reasons.) */ PTHREAD_TRACE_CLASS_ICOND = 0x00010000, /* Internal condition */ PTHREAD_TRACE_CLASS_ILOCK = 0x00020000, /* Internal rwlock */ PTHREAD_TRACE_CLASS_IMUTEX = 0x00040000, /* Internal mutex */ PTHREAD_TRACE_CLASS_ITHREAD = 0x00080000, /* Internal thread */ PTHREAD_TRACE_CLASS_ISCHED = 0x00100000, /* Internal scheduling */ PTHREAD_TRACE_CLASS_IUPCALL = 0x00200000, /* Internal upcalls */ PTHREAD_TRACE_CLASS_IVP = 0x00400000, /* Internal vp ops */ PTHREAD_TRACE_CLASS_IKERNEL = 0x00800000, /* Internal kernel ops */ PTHREAD_TRACE_CLASS_IVPC = 0x01000000, /* Internal VP critical */ PTHREAD_TRACE_CLASS_IMISC = 0x40000000 /* Others */ } pthreadTraceClass_t; #define PTHREAD_TRACE_CLASS_EXTERNALS \ (PTHREAD_TRACE_CLASS_COND|PTHREAD_TRACE_CLASS_ERROR| \ PTHREAD_TRACE_CLASS_KEY|PTHREAD_TRACE_CLASS_LOCK| \ PTHREAD_TRACE_CLASS_MUTEX|PTHREAD_TRACE_CLASS_ONCE| \ PTHREAD_TRACE_CLASS_THREAD|PTHREAD_TRACE_CLASS_SCHED| \ PTHREAD_TRACE_CLASS_USER) #define PTHREAD_TRACE_CLASS_INTERNALS \ (PTHREAD_TRACE_CLASS_ICOND|PTHREAD_TRACE_CLASS_ILOCK| \ PTHREAD_TRACE_CLASS_IMUTEX|PTHREAD_TRACE_CLASS_ITHREAD| \ PTHREAD_TRACE_CLASS_ISCHED|PTHREAD_TRACE_CLASS_IUPCALL| \ PTHREAD_TRACE_CLASS_IVP|PTHREAD_TRACE_CLASS_IKERNEL| \ PTHREAD_TRACE_CLASS_IVPC|PTHREAD_TRACE_CLASS_IMISC) #define PTHREAD_TRACE_CLASS_ALL \ (PTHREAD_TRACE_CLASS_EXTERNALS|PTHREAD_TRACE_CLASS_INTERNALS) /* * These represent the TYPES of data that may appear in a trace record. */ typedef enum pthreadTraceType_tag { /* INPUT OUTPUT FORMAT */ PTHREAD_TRACE_TYPE_UNUSED = 0, PTHREAD_TRACE_TYPE_CHAR, /* char %c */ PTHREAD_TRACE_TYPE_BOOL, /* char TRUE, FALSE */ PTHREAD_TRACE_TYPE_SHORT, /* short %hd */ PTHREAD_TRACE_TYPE_INT, /* int %d */ PTHREAD_TRACE_TYPE_LONG, /* long %ld */ #define PTHREAD_TRACE_TYPE_HEXINT PTHREAD_TRACE_TYPE_INT #define PTHREAD_TRACE_TYPE_HEXLONG PTHREAD_TRACE_TYPE_POINTER PTHREAD_TRACE_TYPE_THREADID,/* long * thread %ld */ PTHREAD_TRACE_TYPE_MUTEXID, /* long * mutex %ld */ PTHREAD_TRACE_TYPE_LOCKID, /* long * rwlock %ld */ PTHREAD_TRACE_TYPE_CONDID, /* long * cond %ld */ PTHREAD_TRACE_TYPE_POINTER, /* void* %p */ PTHREAD_TRACE_TYPE_ERRNO, /* int strerror (%d) */ PTHREAD_TRACE_TYPE_EXCADDR, /* void* %p */ PTHREAD_TRACE_TYPE_EXCSTAT, /* long %#lx */ PTHREAD_TRACE_TYPE_THDARG, /* void* %#lx */ PTHREAD_TRACE_TYPE_STRING, /* char* %s */ PTHREAD_TRACE_TYPE_NAME, /* char* %s */ PTHREAD_TRACE_TYPE_BINARY, /* (void*,long) %#lx... */ PTHREAD_TRACE_TYPE_MUTEX, /* pthread_mutex_t* long mutex %ld */ PTHREAD_TRACE_TYPE_COND, /* pthread_cond_t* long cond %ld */ PTHREAD_TRACE_TYPE_THREAD, /* pthread_t long thread %ld */ PTHREAD_TRACE_TYPE_KEY, /* pthread_key_t long key %ld */ PTHREAD_TRACE_TYPE_LOCK, /* pthread_rwlock_t* long rwlock %ld */ PTHREAD_TRACE_TYPE_TIME, /* pthreadTraceTimespec_t* */ PTHREAD_TRACE_TYPE_SCHED, /* (int, int) %s, prio %d */ PTHREAD_TRACE_TYPE_MINIT, /* pthreadTraceMutexInit_t* */ PTHREAD_TRACE_TYPE_CINIT, /* pthreadTraceCondInit_t* */ PTHREAD_TRACE_TYPE_TINIT, /* pthreadTraceThreadInit_t* */ PTHREAD_TRACE_TYPE_KINIT, /* pthreadTraceKeyInit_t* */ PTHREAD_TRACE_TYPE_LINIT, /* pthreadTraceRwlockInit_t* */ PTHREAD_TRACE_TYPE_CANCEL, /* pthreadTraceCancel_t */ PTHREAD_TRACE_TYPE_OBJECT, /* char object %1s */ PTHREAD_TRACE_TYPE_OPERATION, /* int op %2s */ PTHREAD_TRACE_TYPE_BLOCK_REASON, /* pthreadTraceBlockReason_t */ PTHREAD_TRACE_TYPE_ENVIRONMENT, /* pthreadTraceEnvironment_t */ PTHREAD_TRACE_TYPE_LABEL, /* char* %s: */ PTHREAD_TRACE_TYPE_JAVA_STACK, /* char* %s */ PTHREAD_TRACE_TYPE_VP, /* (vp*) long vp %ld */ PTHREAD_TRACE_TYPE_EXCNATIVE, /* char* %s */ /* * (*) The MUTEXID, CONDID, LOCKID, and THREADID type codes exist only * within the thread library and trace engine. In the output stream (at * least for the log engine) they are identical to a MUTEX, COND, LOCK, or * THREAD type specified with the address of an object containing the same * sequence number. The ID variants are used when no actual object is * available. */ /* * The following are types for VT-internal use. */ PTHREAD_TRACE_TYPE_AID = 48, /* Analysis ID */ /* * Start any additional DECthreads-internal types, which cannot be * analyzed by external tracing tools, at value 64 or higher. It would be * best to define them to behave like "TYPE_BLOCK", with an explicit size, * so that formatters can easily skip them. */ PTHREAD_TRACE_TYPE_MAX /* Maximum value (unused) */ } pthreadTraceType_t, *pthreadTraceType_p; /* * This code is passed to the reinit routine of the active tracing engine * (also known as an "event library") so it can deal with a fork. */ typedef enum pthreadTraceForkCode_tag { PTHREAD_TRACE_REINIT_PREPARE, /* PREfork, in parent */ PTHREAD_TRACE_REINIT_PARENT, /* POSTfork, in parent */ PTHREAD_TRACE_REINIT_CHILD /* POSTfork, in child */ } pthreadTraceForkCode_t; /* * These values are flags to the event.image (E.II) event. There are * 11 arguments to the event: file path, three triplets of data for * each of 3 image regions (image base address, mapped memory * address, and size, for each of "program text" [code], "data", and * "bss" [UNIX initialized data]), then flags. */ typedef enum pthreadTraceImageFlags_tag { PTHREAD_TRACE_IMAGE_MAIN = 0x00000001, /* Main image */ PTHREAD_TRACE_IMAGE_UPCALLS = 0x00000002, /* Upcalls (VMS only) */ PTHREAD_TRACE_IMAGE_KTHREAD = 0x00000004 /* Kthreads (VMS only) */ } pthreadTraceImageFlags_t; /* * This code is passed to the fini routine of the active tracing engine (also * known as an "event library") so it can deal with a flush or shutdown * request. * * PTHREAD_TRACE_FINI_FLUSH is a request to flush volatile data (generally to * protect against a process crash). * * PTHREAD_TRACE_FINI_DESIST is a request to shut down the tracing engine, * possibly because another tracing engine has been selected. Usually, the * process will continue running, (and this engine may not be called again), * so all resources should be deallocated. * * PTHREAD_TRACE_FINI_TERMINATE is much like DESIST, except that the process * is about to terminate. It's not necessary, therefore, to deallocate all * resources, since the system will generally handle that anyway. (It's OK to * treat TERMINATE and DESIST as the same thing, though.) */ typedef enum pthreadTraceFiniCode_tag { PTHREAD_TRACE_FINI_FLUSH, /* Flush buffers, continue */ PTHREAD_TRACE_FINI_DESIST, /* Flush and shut down */ PTHREAD_TRACE_FINI_TERMINATE /* Process termination */ } pthreadTraceFiniCode_t; typedef enum pthreadTraceLockState_tag { PTHREAD_TRACE_LOCK_ALL = 0x1, /* Full lock */ PTHREAD_TRACE_LOCK_CANCEL = 0x2, /* Lock cancel only */ PTHREAD_TRACE_LOCK_RESTORE = 0x10, /* (internal use only) */ PTHREAD_TRACE_LOCK_NEST = 0x20 /* (internal use only) */ } pthreadTraceLockState_t; /* * This describes the reason why a thread has blocked. (Used by scheduling * events.) */ typedef enum pthreadTraceBlockVariant_tag { PTHREAD_TRACE_BLKVAR_OTHER = 0, /* Old: for compatibility */ PTHREAD_TRACE_BLKVAR_UNIX = 1, /* Old: for compatibility */ PTHREAD_TRACE_BLKVAR_OPENVMS = 2, /* Old: for compatibility */ PTHREAD_TRACE_BLKVAR_NONE = 3, /* No blocking state */ PTHREAD_TRACE_BLKVAR_SYNC = 4, /* $SYNC */ PTHREAD_TRACE_BLKVAR_WFL = 5, /* Event flag wait */ PTHREAD_TRACE_BLKVAR_HIBER = 6, /* $HIBER */ PTHREAD_TRACE_BLKVAR_IMS = 7, /* Inner-mode semaphore */ PTHREAD_TRACE_BLKVAR_PFW = 8, /* Pagefault wait */ PTHREAD_TRACE_BLKVAR_WAIT = 9, /* Generic internal wait */ PTHREAD_TRACE_BLKVAR_SETAST = 10, /* $SETAST wait */ PTHREAD_TRACE_BLKVAR_SYSCALL = 11 /* System call wait */ } pthreadTraceBlockVariant_t; typedef union pthreadTraceBlockReason_tag { pthreadTraceBlockVariant_t variant; /* Which type */ struct { pthreadTraceBlockVariant_t type; /* Type of block */ int efn; /* Event flag */ unsigned short *iosb; /* IOSB (SYNC only) */ unsigned short status; /* (Generally zero) */ } sync; struct { pthreadTraceBlockVariant_t type; /* Type of block */ int and; /* "logical and" wait */ unsigned int efm[2]; /* Wait mask */ } wfl; struct { pthreadTraceBlockVariant_t type; /* Type of block */ #if _PTHREAD_HARDWARE_ == _PTHREAD__ALPHA int padding; #endif __pthreadLongUint_t seq; /* Sequence # */ } ims; struct { pthreadTraceBlockVariant_t type; /* Type of block */ int collided; /* Collided fault */ void *va; /* Address */ } pfw; struct { pthreadTraceBlockVariant_t type; /* Type of block */ unsigned char fault; /* Fault occured too */ unsigned char habitat; /* Habitat */ unsigned short number; /* Syscall number */ void *va; /* Page fault address */ } syscall; __pthreadLongUint_t reserved[9]; } pthreadTraceBlockReason_t, *pthreadTraceBlockReason_p; /* * Identifier of an object -- thread, condition variable, mutex, etc. This * is the debug "sequence number" of the object. */ typedef __pthreadLongInt_t pthreadTraceId_t; /* * This is essentially a POSIX "struct timespec", except that it uses a 64-bit * value for the number of seconds. It is also the same size on both OpenVMS * Alpha and UNIX Alpha. Use of this type allows trace log files to be moved * between the two platforms. */ typedef struct pthreadTraceTimespec_tag { __pthreadLongInt_t tv_sec; __pthreadLongUint_t tv_nsec; } pthreadTraceTimespec_t, *pthreadTraceTimespec_p; /* * The Timestamp structure contains 3 fields: * * time standard system time (seconds & nanoseconds since * UNIX Epoch). * toffset user-mode analogy to the high 32-bits returned by RPCC * on UNIX and OpenVMS. (An adjustment factor for the time * this thread has not been running on the VP.) * cycles adjusted cycles the VP had run, computed by combining * the two halves of RPCC. (This may be inaccurate on an * SMP, if the kernel thread has moved between * processors.) */ typedef struct pthreadTraceTimestamp_tag { pthreadTraceTimespec_t time; /* current clock time */ int toffset; /* Thread cycle offset */ unsigned int cycles; /* Adjusted CPU cycle counter */ } pthreadTraceTimestamp_t, *pthreadTraceTimestamp_p; /* * The Debugger info structure currently contains two fields * * flags Info flags (PTHREAD_TRACE_INFO_*) * events The events in which debugger has expressed interest. */ typedef enum pthreadTraceDebugInfoFlags_tag { PTHREAD_TRACE_INFO_DEBUGGER = 0x00000001, /* Debugger attached */ PTHREAD_TRACE_INFO_MULTIPLE = 0x00000002 /* Multiple debuggers */ } pthreadTraceDebugInfoFlags_t; typedef struct pthreadTraceDebugInfo_tag { __pthreadLongUint_t flags; /* PTHREAD_TRACE_INFO_* */ __pthreadLongUint_t events; /* as pthreadDebugEventMask_t */ } pthreadTraceDebugInfo_t, *pthreadTraceDebugInfo_p; /* * Environment block passed to pthread_trace__init and event.system * event. */ typedef struct pthreadTraceEnvironment_tag { __pthreadLongUint_t bin_version; /* Binary DECthreads version */ char thread_version[32]; /* ASCII DECthreads version */ char os_name[32]; /* ASCII O/S name */ char os_release[32]; /* ASCII O/S release */ char os_version[32]; /* ASCII O/S version */ char hw_name[32]; /* ASCII hardware name */ char chip_name[32]; /* ASCII chip name */ int cpu_speed; /* chip speed (cycles/sec) */ int cpus_online; /* CPUs in box */ int cpus_active; /* CPUs in running system */ #if _PTHREAD_HARDWARE_ == _PTHREAD__ALPHA int padding; #endif __pthreadLongUint_t memory; /* Memory (Mb) */ } pthreadTraceEnvironment_t, *pthreadTraceEnvironment_p; /* * Types describing the information reported about a thread. */ typedef enum pthreadTraceCancel_tag { PTHREAD_TRACE_CANCEL_PENDING = 0x0001, /* Cancel is pending */ PTHREAD_TRACE_CANCEL_STATE = 0x0002, /* Cancel enabled */ PTHREAD_TRACE_CANCEL_SYSTEM = 0x0004, /* System cancel enabled */ PTHREAD_TRACE_CANCEL_TYPE = 0x0008 /* Cancel async */ } pthreadTraceCancel_t; /* * Type defining thread "kinds". All threads created by a program through * DECthreads interfaces are of kind NORMAL. A debugger should usually show * threads of other kinds only when a special switch or mode is used (e.g., * pthread_trace's "thread -a".) */ typedef enum pthreadTraceThreadKind_tag { PTHREAD_TRACE_THD_KIND_INITIAL = 1, /* Initial thread */ PTHREAD_TRACE_THD_KIND_NORMAL = 2, /* Normal thread */ PTHREAD_TRACE_THD_KIND_NULL = 3, /* DECthreads null thread */ PTHREAD_TRACE_THD_KIND_MGR = 4, /* DECthreads manager thread */ PTHREAD_TRACE_THD_KIND_FOREIGN = 5, /* A non-DECthreads NT thread */ PTHREAD_TRACE_THD_KIND_EXITHAND = 6 /* The exit handler thread */ } pthreadTraceThreadKind_t; /* * Creator codes to show whether an thread was created by POSIX, CMA, etc. */ typedef enum pthreadTraceCreator_tag { PTHREAD_TRACE_CREATOR_NONE = 0, /* Unknown */ PTHREAD_TRACE_CREATOR_POSIX = 1, /* POSIX interface */ PTHREAD_TRACE_CREATOR_CMA = 2, /* CMA interface */ PTHREAD_TRACE_CREATOR_DCE = 3, /* vanilla DCE thread */ PTHREAD_TRACE_CREATOR_DCEEXC = 4, /* exception DCE thread */ PTHREAD_TRACE_CREATOR_TIS = 5 /* Prototype TIS TEB */ } pthreadTraceCreator_t; /* * Type defining information reported about a thread's creation. * * NOTES: * * 1) The "sequence" field is traditionally reported as a signed number when * the PTHREAD_TRACE_THD_INTERNAL flag is set, even though the sequence * is technically an unsigned number. * 2) If the stack was created with a user specified stack ("stackaddr" * attribute), the PTHREAD_TRACE_THD_STACKADDR flag will be set. In this * case, all of the thread's stack information fields, except stack_base, * are guesses, and probably inaccurate. You shouldn't, for example, * compare a later stack highwater mark against stack_reserve to check for * stack overflows. If the stacksize attribute has also been modified in * the attributes object, DECthreads will guess that the creator intended * that as the size of the user stack. Because the standard does not * specify any such relationship, this is still an unreliable guess. * (There's no specific indication that both stackaddr and stacksize were * set. However, if DECthreads must guess, we guess PTHREAD_STACK_MIN. So * it's reasonable for you to guess that, if the stacksize of a user stack * isn't PTHREAD_STACK_MIN, the user also specified a stacksize.) * * However, if the flag PTHREAD_TRACE_THD_ESTACKADDR is also set, then the * "extended stackaddr" interface, pthread_setstackaddr_np, was used, which * allows the caller to specify the size and base address. In this case, * all stack information may be considered valid. */ #define PTHREAD_TRACE_THD_NAME 0x00000001 /* Name != "" */ #define PTHREAD_TRACE_THD_SYS_SCOPE 0x00000002 /* System contention scope */ #define PTHREAD_TRACE_THD_INTERNAL 0x00000004 /* DECthreads internal */ #define PTHREAD_TRACE_THD_ERROR 0x00000008 /* Init failed */ #define PTHREAD_TRACE_THD_INVATTR 0x00000010 /* ERROR was bad attr. */ #define PTHREAD_TRACE_THD_DETACH 0x00000020 /* Created detached */ #define PTHREAD_TRACE_THD_STACKADDR 0x00000040 /* User stack */ #define PTHREAD_TRACE_THD_ESTACKADDR 0x00000080 /* .. Base and size known */ /* * (*) NOSIG and NOSYSCAN will be set for threads created using the LEGACY * interfaces (CMA, DCE threads), for binary compatibility with the original * implementation that delivered async signals to the initial thread, and * that did not support cancellation of syscalls. [UNIX only]. */ /* * NOTE: if the ERROR bit is set in flags, the following fields will be * initialized to 0 (NULL): teb, stack_base, stack_reserve, stack_yellow, * stack_guard. * * If the INVATTR flag is also set, the following additional fields will be * set to 0: kind, policy, priority, and stack_size. */ typedef struct pthreadTraceThreadInit_tag { unsigned int flags; /* PTHREAD_TRACE_THD_ flags */ pthreadTraceThreadKind_t kind; /* Kind of thread */ pthread_t teb; /* Pointer to thread's TEB */ pthread_t *handle; /* "Handle" (where pthread_create stored the TEB pointer) */ pthread_attr_t *attributes; /* Attributes object pointer */ int policy; /* Thread's scheduling policy */ int priority; /* Thread's (base) priority */ void *stack_base; /* Base of thread's stack */ void *stack_reserve; /* First byte of reserved zone */ void *stack_yellow; /* First byte of yellow zone */ void *stack_guard; /* First byte of guard zone */ __pthreadLongUint_t stack_size; /* Total usable stack (bytes) */ void *(*start)(void*); /* Thread start rtn */ void *start_arg; /* Thread start arg */ __pthreadLongUint_t cpu_mask; /* (TBD: some binding ID) */ pthreadTraceCreator_t creator; /* Creating interface */ unsigned int cancel; /* Initial cancel state */ } pthreadTraceThreadInit_t, *pthreadTraceThreadInit_p; /* * Types describing the information reported about a mutex. */ typedef enum pthreadTraceMutexType_tag { PTHREAD_TRACE_MUT_TYPE_NORMAL = 1, /* Normal mutex */ PTHREAD_TRACE_MUT_TYPE_RECURSIVE = 2, /* Recursive mutex */ PTHREAD_TRACE_MUT_TYPE_ERRORCHECK = 3 /* Error-check mutex */ } pthreadTraceMutexType_t; typedef enum pthreadTraceMutexProtocol_tag { PTHREAD_TRACE_MUT_PROTO_NONE = 1, /* Normal */ PTHREAD_TRACE_MUT_PROTO_PROTECT = 2, /* Priority ceiling */ PTHREAD_TRACE_MUT_PROTO_INHERIT = 3 /* Priority inheritance */ } pthreadTraceMutexProtocol_t; #define PTHREAD_TRACE_MUT_NAME 0x00000001 /* Name != "" */ #define PTHREAD_TRACE_MUT_INTERNAL 0x00000002 /* DECthreads internal */ #define PTHREAD_TRACE_MUT_PSHARED 0x00000004 /* "Process shared" */ #define PTHREAD_TRACE_MUT_ERROR 0x00000008 /* Init failed */ #define PTHREAD_TRACE_MUT_INVATTR 0x00000010 /* ERROR was bad attr. */ /* * NOTE: if the ERROR bit is set in flags, the following fields will be * initialized to 0 (NULL): (n/a) * * If the INVATTR flag is also set, the following additional fields will be * set to 0: type, protocol, prioceiling, priority. */ typedef struct pthreadTraceMutexInit_tag { unsigned int flags; /* Miscellaneous flags */ pthreadTraceMutexType_t type; /* Mutex type */ pthread_mutex_t *address; /* Mutex address */ pthread_mutexattr_t *attributes; /* Attributes object pointer */ pthreadTraceMutexProtocol_t protocol; /* Mutex protocol (nyi) */ int prioceiling; /* Priority ceiling (nyi) */ int priority; /* Current priority (nyi) */ } pthreadTraceMutexInit_t, *pthreadTraceMutexInit_p; /* * Structure defining information reported about a rwlock initialization, or * the first use of a statically initialized rwlock. */ #define PTHREAD_TRACE_RW_NAME 0x00000001 /* Name != "" */ #define PTHREAD_TRACE_RW_INTERNAL 0x00000002 /* DECthreads internal */ #define PTHREAD_TRACE_RW_PSHARED 0x00000004 /* "Process shared" */ #define PTHREAD_TRACE_RW_ERROR 0x00000008 /* Init failed */ #define PTHREAD_TRACE_RW_INVATTR 0x00000010 /* ERROR was bad attr. */ typedef struct pthreadTraceRwlockInit_tag { unsigned int flags; /* Miscellaneous flags */ #if _PTHREAD_HARDWARE_ == _PTHREAD__ALPHA int padding; #endif pthread_rwlock_t *address; /* Rwlock address */ pthread_rwlockattr_t *attributes; /* Attributes object pointer */ } pthreadTraceRwlockInit_t, *pthreadTraceRwlockInit_p; /* * Structure defining information recorded about a condition variable * initialization, or the first use of a statically initialized condition * variable. */ #define PTHREAD_TRACE_COND_NAME 0x00000001 /* Name != "" */ #define PTHREAD_TRACE_COND_INTERNAL 0x00000002 /* DECthreads internal */ #define PTHREAD_TRACE_COND_PSHARED 0x00000004 /* "Process shared" */ #define PTHREAD_TRACE_COND_ERROR 0x00000008 /* Init failed */ #define PTHREAD_TRACE_COND_INVATTR 0x00000010 /* ERROR was bad attr. */ typedef struct pthreadTraceCondInit_tag { unsigned int flags; /* Miscellaneous flags */ #if _PTHREAD_HARDWARE_ == _PTHREAD__ALPHA int padding; #endif pthread_cond_t *address; /* Condition address */ pthread_condattr_t *attributes; /* Attributes object pointer */ } pthreadTraceCondInit_t, *pthreadTraceCondInit_p; /* * Structure defining information recorded about a thread specific data key * creation. * * NOTES: * * 1) EXTENDED tsd keys have additional semantics. In particular, they may * have a constructor routine (called at thread startup) as well as a * destructor routine (called at thread termination). * 2) EXTENDED tsd key destructor routines are called with additional * arguments: as well as the current value of the tsd key in that thread, * they receive the thread ID (pthread_t) and the tsd key itself. * 3) EXTENDED tsd keys can be created with the PTHREAD_KEY_ALLTHREAD_NP * flag. The constructor (if any) will immediately be run for each thread * that currently exists. Similarly, when the key is destroyed the * destructor will immediately be run for each thread. Note that the * constructor and destructor are, in these cases, run in the context of * the thread creating or destroying the key, NOT in the context of the * various threads -- thus the constructor and destructor must be carefully * constructed (which is why the behavior is an option). * 4) While trace points are defined for changing the value of a thread * specific data key, it is legal and supported for applications to get and * set thread specific data values directly, without calls -- these * operations cannot be traced by DECthreads, and therefore may not * appear in the trace log. */ #define PTHREAD_TRACE_KEY_NAME 0x00000001 /* Name != "" */ #define PTHREAD_TRACE_KEY_RESERVED 0x00000002 /* DECthreads reserved */ #define PTHREAD_TRACE_KEY_ALLTHREAD 0x00000004 /* Const/Dest in all thds */ #define PTHREAD_TRACE_KEY_EXTENDED 0x00000008 /* Extended (TLS) key */ #define PTHREAD_TRACE_KEY_ERROR 0x00000010 /* Init failed */ /* * NOTE: if the ERROR bit is set in flags, the following fields will be * initialized to 0 (NULL): key. */ typedef struct pthreadTraceKeyInit_tag { unsigned int flags; /* Miscellaneous flags */ #if _PTHREAD_HARDWARE_ == _PTHREAD__ALPHA int padding; #endif pthread_key_t *address; /* Address where key was stored */ __pthreadConstructor_t constructor; /* Constructor routine */ union { /* Destructor routine */ __pthreadDestructor_t standard; __pthreadExtDestructor_t extended; } destructor; } pthreadTraceKeyInit_t, *pthreadTraceKeyInit_p; /* * This describes a native exception buffer as captured in a log. */ typedef enum pthreadTraceNatExcVariant_tag { PTHREAD_TRACE_NATEXC_OTHER, /* Unknown */ PTHREAD_TRACE_NATEXC_UNIX, /* Tru64 UNIX */ PTHREAD_TRACE_NATEXC_OPENVMS /* OpenVMS */ } pthreadTraceNatExcVariant_t; #define PTHREAD_TRACE_NATEXC_SIZE_MAX 256 /* Bytes */ typedef struct pthreadTraceNatExc_tag { int size; /* Of the os member used, in bytes */ pthreadTraceNatExcVariant_t variant; /* Which OS? */ char os[PTHREAD_TRACE_NATEXC_SIZE_MAX]; /* Data */ } pthreadTraceNatExc_t, *pthreadTraceNatExc_p; /* * The pthread_trace_write_np() function can be called by any application code * to generate a trace point. Use pthreadTraceMakeId() to create the ID, using * the PTHREAD_TRACE_OP_ and PTHREAD_TRACE_STAT_ codes above. * PTHREAD_TRACE_OBJ_ codes other than PTHREAD_TRACE_OBJ_USER cannot be used * by this interface. Also, you cannot specify the PTHREAD_TRACE_STAT_PRIVATE * flag, and PTHREAD_TRACE_STAT_USER will be added to all trace points. * * event event code (pthreadTraceMakeId) * name optional name string for trace point: uninterpreted, and may * be NULL * count the number of argument pairs following. * ... each argument consists of two or more values: a * PTHREAD_TRACE_TYPE_ code followed by the arguments for that * type; usually either a scalar value or a pointer. * * The return value will be ENOSYS if no event engine is loaded. Some engines * might report additional errors. * * NOTE: pthread_trace_write_np is the only function in this header intended * for use by application code, rather than by trace engines. The prototype * is here, rather than in , due to the dependency on the event * definition and object/operation/status types. */ extern int pthread_trace_write_np ( pthreadTraceEvent_t, const char *, int, ...); /* * Define the programming interfaces. * * These functions are intended for use by tracing tools, and are not for * general use. (They will not be documented outside of this header, and will * have limited support.) */ /* * These typedefs describe the trace engine "hooks", which are called by the * DECthreads tracing code. * * A trace engine has a "name", which is used to construct the actual entry * points. The engine is packaged as a shared library with the name * libpthreadevent_%s.so, (UNIX), or %s_TRACE_ENGINE, (OpenVMS), where %s is * replaced by the engine name. E.g., libpthreadevent_vt.so or VT_TRACE_ENGINE * for the Visual Threads engine. (On OpenVMS, LIB$FIND_IMAGE_SYMBOL will * provide the default file type of ".EXE".) Each of the defined entry points * is resolved using dlsym (or LIB$FIND_IMAGE_SYMBOL) for names also * constructed using the engine name, which will be called using the following * typedef prototypes: * * pthreadTraceEngineInit_t pthread_trace_%s_init * pthreadTraceEngineWrite_t pthread_trace_%s_write * pthreadTraceEngineSetClass_t pthread_trace_%s_setclass * pthreadTraceEngineFini_t pthread_trace_%s_fini * pthreadTraceEngineReinit_t pthread_trace_%s_reinit * pthreadTraceEngineVersion_t pthread_trace_%s_version * pthreadTraceEngineHandshake_t pthread_trace_%s_handshake * * The environment in which most of these functions are called is "delicate". * They must avoid any thread library calls, in addition to any other calls * (such as libc stdio) that might involve synchronization. These are only * some of the restrictions. */ /* * Finalize the trace stream. * * Arguments: * * reason PTHREAD_TRACE_FINI_ * * Return: * * status value (may be logged, but otherwise ignored) */ typedef int (*pthreadTraceEngineFini_t) (pthreadTraceFiniCode_t); /* * Agree on protocol version (which currently means that a client could, at * least in theory, support old trace protocols). * * Arguments: * * version Current thread trace protocol version * * Return: * * version to use (currently must match version argument) */ typedef __pthreadLongUint_t (*pthreadTraceEngineHandshake_t) ( __pthreadLongUint_t); /* * Initialize the trace engine * * Arguments: * * environment Thread library's environment block * argc The number of engine arguments * argv Pointer to array of argc arguments * * Return: * * if not 0 (success), tracing won't initialize. */ typedef int (*pthreadTraceEngineInit_t) ( pthreadTraceEnvironment_p, int, __pthreadLongString_t[]); /* * Re-initialize the trace engine around fork. Called before the fork, and * after the fork in both parent and child. Distinguish by the value of the * "why" arguments. * * Arguments: * * why PTHREAD_TRACE_REINIT_ * * Return: * * currently ignored. */ typedef int (*pthreadTraceEngineReinit_t) (pthreadTraceForkCode_t); /* * Inform engine of changes to trace class mask. It may choose to write an * event, for example, "event.setprop". * * Arguments: * * class New class mask * * Return: * * currently ignored. */ typedef int (*pthreadTraceEngineSetClass_t) (int); /* * Obsolete variant of pthreadTraceEngineHandshake. This version expects the * engine to return the trace protocol version against which it was compiled, * with no input from the trace facility. (In other words, if the engine knows * how to handle versions 0 and 1, it has no idea which value to use.) * * Arguments: * * none * * Return: * * trace protocol version required */ typedef int (*pthreadTraceEngineVersion_t) (void); /* * Write a trace record. The engine routine needs to sequence through the * tuples of (type, value) argument descriptors, and "do whatever it needs to * do" to capture the trace record. * * Arguments: * * event The event ID of the record (e.g., mutex.init) * name The event "name" string * thread The calling thread's ID * count Count of argument pairs * ap stdargs descriptor of the first argument type. * * Return: * * trace protocol version required */ typedef int (*pthreadTraceEngineWrite_t) ( pthreadTraceEvent_t, __pthreadLongConstString_t, pthread_t, int, va_list); extern int __pthread_trace_getclass (__pthreadLongUint_t *); extern int __pthread_trace_gettimestamp ( pthread_t, pthreadTraceTimestamp_p); extern int __pthread_trace_getdebugger ( int, pthreadTraceDebugInfo_p); /* * Lock out scheduling for the duration of a function that might be a * cancellation point, or which might invoke 2-level scheduling. For example, * any I/O operation within a tracing engine or ATOM analysis routine should * use this function. To restore, call again with the return value: * * int lockState; * lockState = _pthread_trace_lock (PTHREAD_TRACE_LOCK_ALL); * [...] * _pthread_trace_lock (lockState); * * The value of "which" may be PTHREAD_TRACE_LOCK_ALL or * PTHREAD_TRACE_LOCK_CANCEL. ("ALL" includes "CANCEL", so there's no need to * specify both.) */ extern int __pthread_trace_lock (int); extern int __pthread_trace_toolreport ( const char *, const char *); extern int __pthread_trace_setclass (__pthreadLongUint_t); /* *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * Information specific to the "log" trace engine that is built into * the POSIX thread library. *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ #define PTHREAD_TRACE_LOG_VERSION 7 /* Current version */ #ifdef _PTHREAD_ENV_VMS # define PTHREAD_TRACE_LOG_BUFSIZE (1<<15) /* (RMS limitation) */ #else # define PTHREAD_TRACE_LOG_BUFSIZE (1024*1024) /* 1Mb buffers */ #endif /* * This is stored at the beginning of a log file: the "magic number". It * includes the version of the log engine. */ typedef struct pthreadTraceLogFilHdr_tag { char traceMagic[4]; /* "ThTr" */ char engine[8]; /* "LOG " */ char version[2]; /* version, "%0.2d" */ char reserved[2]; } pthreadTraceLogFilHdr_t, *pthreadTraceLogFilHdr_p; typedef enum pthreadTraceLogCompress_tag { PTHREAD_TRACE_LOG_COMPRESS_NONE = 0, PTHREAD_TRACE_LOG_COMPRESS_ZIP = 1 } pthreadTraceLogCompress_t; typedef enum pthreadTraceLogHeadFlags_tag { PTHREAD_TRACE_HEAD_SYNC = 0x01, /* Synch trace (vt only) */ PTHREAD_TRACE_HEAD_NAME = 0x02, /* Record has a name */ PTHREAD_TRACE_HEAD_MOREFRAMES = 0x04 /* Exceeds MAX frame depth */ } pthreadTraceLogHeadFlags_t; /* * Special case of pthreadTraceLogHead_t. This will always be the first event * in a trace buffer. It is uncompressed in a compressed buffer. "Event" and * "size" are as in a standard event, but the rest is specialized. The "size" * field includes the event itself and the buffer data. That is, for * decompression (or processing), you must subtract the size of the event. The * "fullsize" field, however, is the size of the uncompressed data, which does * not include a header. * * This is stored at the beginning of each trace buffer written by the builtin * "log" trace engine, and is written to the output stream. Buffers may be * written out of order. The analyzer must sort them into the proper order (by * sequence number) to correctly follow the sequence of events. */ typedef struct pthreadTraceLogBufEvt_tag { pthreadTraceEvent_t event; /* EHD<0> (event.header) */ unsigned int size; /* Size of buffer data. */ __pthreadLongUint_t sequence; /* Buffer's sequence # */ pthreadTraceLogCompress_t compression; /* Compression for buffer */ unsigned int fullsize; /* Uncompressed size */ } pthreadTraceLogBufEvt_t, *pthreadTraceLogBufEvt_p; /* * The common header of a trace record. */ typedef struct pthreadTraceLogHead_tag { pthreadTraceEvent_t event; /* Trace point identifier */ unsigned int size; /* Size of packet (bytes) */ pthreadTraceId_t thread; /* Thread that logged event */ __pthreadLongUint_t sequence; /* Event sequence number */ pthreadTraceTimestamp_t timestamp; /* Timestamp data */ unsigned char flags; /* Flag bits */ unsigned char frames; /* Number of frames in trace */ unsigned char argc; /* Number of arguments */ unsigned char argt[1]; /* Array of argument types */ #ifdef THESE_ARE_FOR_DOCUMENTATION_ONLY /* * Fields beyond this point cannot be referenced directly. The definitions * provide (minimal) documentation of the record's layout. * * 1) If the PTHREAD_TRACE_HEAD_NAME flag is set, the event's name string * comes next, in the form of a PTHREAD_TRACE_TYPE_STRING argument. * * 2) Pad to 8 byte alignment. * * 3) The arguments begin here, one for each element in the argtypes * array. The maximum number of arguments is PTHREAD_TRACE_MAXARGS. * Each argument is naturally aligned for its type. * * 4) After the final argument, pad to 8-byte alignment for the list of * stack trace PCs. The count of frames is in the "frames" field. */ pthreadLongAddr_t trace[frames]; /* Stack trace (end) */ #endif } pthreadTraceLogHead_t, *pthreadTraceLogHead_p; /* *--------------------------------------------------------------------------- * End of information specific to the "log" trace engine that is built into * the POSIX thread library. *--------------------------------------------------------------------------- */ /* * Restore the pointer size environment for VMS */ #if defined (_PTHREAD_ENV_ALPHA) && defined (_PTHREAD_ENV_VMS) # pragma __required_pointer_size __restore #endif #ifdef __cplusplus } #endif #endif /* _PTHREAD_TRACE_H_ */