On DIGITAL UNIX systems only, DECthreads forms the bugcheck output file's name using the process ID number (PID) as the %d format item.
On DIGITAL UNIX systems only, PTHREAD_CONFIG can be the object of the export command.
Metering tells DECthreads to collect statistical and historical information about the use of synchronization objects within your program. This affects all synchronization within the program, including that within DECthreads itself and any other libraries that use threads. Therefore, metering provides a very powerful tool for debugging multithreaded code.
To enable metering, define PTHREAD_CONFIG prior to running any threaded application. The variable should have a value of meter=all to enable metering. This causes DECthreads to gather and record statistics and history information for all synchronization operations. Additionally, when running in metered mode, DECthreads marks all thread stacks (except the main thread stack) with a specific pattern.
Programs running in metered mode are somewhat slower than unmetered programs. Also, normal mutexes that are metered can behave like errorcheck mutexes in many ways. This does not affect the behavior of correct programs, but you should be aware of some differences between normal and errorcheck mutexes. The most important difference is that normal mutexes do not report a number of usage errors, while errorcheck mutexes do.
Because it can be expensive to detect these conditions, a normal mutex may not always report these errors. Regardless of whether the program seems to work correctly under these circumstances, the operations are illegal. A metered normal mutex will report these errors under more circumstances than will an unmetered normal mutex.
The DIGITAL Ladebug debugger provides commands to display the state of threads, mutexes, and condition variables, without using the built-in DECthreads debug facility.
Using the Ladebug commands, you can examine core files and remote debug sessions, as well as run processes.
The basic commands are:
Refer to the Ladebug documentation for further details.
This section presents particular topics that relate to debugging a multithreaded application under OpenVMS.
When a program incurs an unhandled exception, a stack trace is produced that shows the call frames from the point where the exception was raised or, if DECthreads TRY/CATCH, TRY/FINALLY, or POSIX cleanup handlers are used, from the point where it was last reraised to the bottom of the stack.
The WinDbg Debugger, provided with the Windows NT Software Development Kit (SDK), provides support for debugging a threaded program. When working with DECthreads in WinDbg, be aware that terminating a thread with pthread_exit() raises an exception as a normal part of the exiting process. Unless you explicitly tell WinDbg to ignore this exception, it catches the exception and stops execution. To allow the thread to exit properly and your application to continue, use the WinDbg gn (go not handled) command. This command tells WinDbg to ignore the exception.
WinDbg also stops at each DECthreads exception block for this exception and has to be continued using the WinDbg gn command until the thread's stack is completely unwound. The exception used by DECthreads for thread rundown is 0x177db052.
DECthreads also generates an exception in a thread as a normal part of thread cancelation. When canceling a thread with pthread_cancel(), an exception value of 0x177db048 is raised. This exception should be allowed to propagate all the way to the base of the thread's stack. If WinDbg halts execution of the program and indicates that this exception is being raised, use the WinDbg gn command to allow the exception to continue.
You can use the Microsoft Visual C++ debugger's graphical user interface to debug exceptions and to indicate how to handle various exceptions. In this case, choose "Stop if not handled" for the exception codes mentioned above.
However, be aware that you cannot fully debug an application that uses pthread_exit() to exit a Win32 thread or uses pthread_cancel() to cancel a Win32 thread. For a thread created using the Win32 API, using pthread_exit() to exit, or using pthread_cancel() to cancel, that thread causes a library-defined unhandled exception filter routine to be invoked. Unhandled exception filter routines cannot be executed in a debugger environment. Any unhandled exception causes the process to exit.
This appendix presents information that helps you migrate existing programs and applications that use the DIGITAL-proprietary DECthreads CMA (or cma) interface to use the DECthreads pthread interface, based on the IEEE POSIX 1003.1c-1995 standard.
Note
In future DECthreads releases, the cma interface will continue to exist and be supported, but it will no longer be documented or enhanced. Therefore, it is recommended that you port your cma-based programs and applications to the pthread interface as soon as possible. The DECthreads pthread interface is the most portable, efficient, and robust multithreading run-time library offered by DIGITAL.
The DECthreads pthread interface differs significantly from the cma interface, though there are many similarities between the functions that individual routines perform. This section gives hints about the relationship between the two sets of routines, to assist you in migrating applications.
Note that routines whose names have the _np suffix are not portable---that is, the routine might not be available except in DECthreads.
You need not prototype the pthread routines if you include the C language pthread.h header file.
A cma handle is storage, similar to a pointer, that refers to a specific DECthreads object (thread, mutex, condition variable, queue, or attributes object).
Handles are allocated by the user application. They can be freely copied by the program and stored in any class of storage; objects are managed by DECthreads.
In the cma interface, because objects are accessed only by handles, you can think of the handle as if it were the object itself. DECthreads objects are accessed by handles (rather than pointers), because handles allow for greater robustness and portability. Handles allow DECthreads to detect the following types of run-time errors:
Handles are not supported in the DECthreads pthread interface. Although this provides less robustness due to more limited error checking, it allows better performance by decreasing memory use and memory access. (That is, handles result in pointers to pointers.)
As summarized in Table E-1, many cma routines perform functions nearly identical to corresponding routines in the pthread interface. The syntax and semantics differ, but the similarities are also notable.
cma Routine | pthread Routine | Notes |
---|---|---|
cma_alert_disable_asynch() | pthread_setcancelstate()/ pthread_setcanceltype() | |
cma_alert_disable_general() | pthread_setcancelstate()/ pthread_setcanceltype() | |
cma_alert_enable_asynch() | pthread_setcancelstate()/ pthread_setcanceltype() | |
cma_alert_enable_general() | pthread_setcancelstate()/ pthread_setcanceltype() | |
cma_alert_restore() | pthread_setcancelstate()/ pthread_setcanceltype() | |
cma_alert_test() | pthread_testcancel() | |
cma_attr_create() | pthread_attr_init() | |
cma_attr_delete() | pthread_attr_destroy() | |
cma_attr_get_guardsize() | pthread_attr_getguardsize_np() | |
cma_attr_get_inherit_sched() | pthread_attr_getinheritsched() | |
cma_attr_get_mutex_kind() | pthread_mutexattr_gettype_np() | |
cma_attr_get_priority() | pthread_attr_setsched_param() | |
cma_attr_get_sched() | pthread_attr_getschedpolicy() | |
cma_attr_get_stacksize() | pthread_attr_getstacksize() | |
cma_attr_set_guardsize() | pthread_attr_setguardsize_np() | |
cma_attr_set_inherit_sched() | pthread_attr_setinheritsched() | |
cma_attr_set_mutex_kind() | pthread_mutexattr_settype_np() | |
cma_attr_set_priority() | pthread_attr_setsched_param() | |
cma_attr_set_sched() | pthread_attr_setschedpolicy() | |
cma_attr_set_stacksize() | pthread_attr_setstacksize() | |
cma_cond_broadcast() | pthread_cond_broadcast() | |
cma_cond_create() | pthread_cond_init() | |
cma_cond_delete() | pthread_cond_destroy() | |
cma_cond_signal() | pthread_cond_signal() | |
cma_cond_signal_int() | pthread_cond_signal_int_np() | |
cma_cond_timed_wait() | pthread_cond_timedwait() | |
cma_cond_wait() | pthread_cond_wait() | |
cma_delay() | pthread_delay_np() | |
cma_handle_assign() | none | Use Language assignment operator. |
cma_handle_equal() | pthread_equal() | |
cma_init() | none | Not necessary. |
cma_key_create() |
pthread_key_create()
(Note: pthread_key_delete() is available as well.) |
|
cma_key_get_context() | pthread_getspecific() | |
cma_key_set_context() | pthread_setspecific() | |
cma_lock_global() | pthread_lock_global_np() | |
cma_mutex_create() | pthread_mutex_init() | |
cma_mutex_delete() | pthread_mutex_delete() | |
cma_mutex_lock() | pthread_mutex_lock() | |
cma_mutex_try_lock() | pthread_mutex_trylock() | |
cma_mutex_unlock() | pthread_mutex_unlock() | |
cma_once() | pthread_once() | |
cma_stack_check_limit_np() | ||
cma_thread_alert() | pthread_cancel() | |
cma_thread_bind_to_cpu() | none | |
cma_thread_create() | pthread_create() | |
cma_thread_detach() | pthread_detach() | |
cma_thread_exit_error() | pthread_exit() | With Status. |
cma_thread_exit_normal() | pthread_exit() | With Status. |
cma_thread_get_priority() | pthread_getschedparam() | |
cma_thread_get_sched() | pthread_setschedparam() | |
cma_thread_get_self() | pthread_self() | |
cma_thread_join() | pthread_join() | |
cma_thread_set_priority() | pthread_setschedparam() | |
cma_thread_set_sched() | pthread_setschedparam() | |
cma_time_get_expiration() | pthread_get_expiration_np() | |
cma_unlock_global() | pthread_unlock_global_np() | |
cma_yield() | pthread_yield() |
Notice that the cma routine cma_cond_timed_wait() requires the time argument expiration to be specified in local time; whereas the pthread routine pthread_cond_timedwait() requires the time argument abstime to be specified in Universal Coordinated Time (UTC).
The following are pthread interface routines that have no functional similarities in the cma interface:
This appendix provides migration information for the routines in the DECthreads POSIX 1003.4a/Draft 4 (or d4) interface.
Note
Applications that use the DECthreads d4 routines require significant modification to be migrated to the pthread interface described in Part 2.
Routines in the DECthreads pthread interface differ significantly from the original DECthreads POSIX 1003.4a/Draft 4 implementation. This section describes the major changes between the interfaces.
The DECthreads pthread interface does not use the global variable errno. (Note that DECthreads provides a thread-specific errno for use by libraries and application code, but the DECthreads pthread interface does not write to it.)
If an error condition occurs, a pthread routine returns an integer value that indicates the type of error. For example, a call to the DECthreads d4 interface's implementation of pthread_cond_destroy() that returned a --1 and set errno to [EBUSY], returns [EBUSY] as the routine's return value in the pthread interface implementation.
On successful completion, most pthread interface routines return zero (0).
Many routines in the DECthreads d4 interface have been replaced or renamed in the pthread interface, as shown in Table F-1.
d4 Routine | Replacement pthread Routine |
---|---|
pthread_attr_create() | pthread_attr_init() |
pthread_attr_delete() | pthread_attr_destroy() |
pthread_attr_set/getdetach_np() | pthread_attr_set/getdetachstate() |
pthread_attr_set/getprio() | pthread_attr_set/getschedparam() |
pthread_attr_set/getsched() | pthread_attr_set/getschedpolicy() |
pthread_condattr_create() | pthread_condattr_init() |
pthread_condattr_delete() | pthread_condattr_destroy() |
pthread_keycreate() | pthread_key_create() |
pthread_mutexattr_create() | pthread_mutexattr_init() |
pthread_mutexattr_delete() | pthread_mutexattr_destroy() |
pthread_mutexattr_get/setkind_np() | pthread_mutexattr_get/settype_np() |
pthread_setasynccancel() | pthread_setcanceltype() |
pthread_setcancel() | pthread_setcancelstate() |
pthread_set/getprio() | pthread_set/getschedparam() |
pthread_set/getscheduler() | pthread_set/getschedparam() |
pthread_yield() | sched_yield() |
Except for the return value, the following routines in the DECthreads d4 interface have no changes to syntax in the DECthreads pthread interface:
The following routines have no changes in syntax or return value:
Notice that the d4 routine pthread_cond_timedwait() requires the time argument abstime to be specified in local time; whereas the pthread routine pthread_cond_timedwait() requires the time argument abstime to be specified in Universal Coordinated Time (UTC).
Table F-2 shows the routines in the DECthreads d4 interface that have changes to their argument syntax in the DECthreads pthread interface.
Old Syntax | New Syntax |
---|---|
unsigned long
pthread_attr_getguardsize_np(
pthread_attr_t attr) |
int
pthread_attr_getguardsize_np(
const pthread_attr_t * attr, size_t * guardsize) |
int
pthread_attr_getinheritsched(
pthread_attr_t attr) |
int
pthread_attr_getinheritsched(
const pthread_attr_t * attr, int * inheritsched) |
unsigned long
pthread_attr_getstacksize(
pthread_attr_t attr) |
int
pthread_attr_getstacksize(
const pthread_attr_t * attr, size_t * stacksize) |
unsigned long
pthread_attr_setguardsize_np(
pthread_attr_t * attr, long guardsize) |
int
pthread_attr_setguardsize_np(
pthread_attr_t * attr, size_t guardsize) |
unsigned long
pthread_attr_setstacksize(
pthread_attr_t * attr, long stacksize) |
int
pthread_attr_setstacksize(
const pthread_attr_t * attr, size_t stacksize) |
int
pthread_cleanup_pop(
int execute) |
void
pthread_cleanup_pop(
int execute) |
int
pthread_cond_init(
pthread_cond_t * cond, pthread_condattr_t attr) |
int
pthread_cond_init(
pthread_cond_t * cond, pthread_condattr_t * attr) |
int
pthread_create(
pthread_t * thread, pthread_attr_t attr, pthread_startroutine_t start_routine, pthread_addr_t arg) |
int
pthread_create(
pthread_t * thread, const pthread_attr_t * attr, void* (* start_routine)(void *), void * arg) |
int
pthread_detach(
pthread_t * thread) |
int
pthread_detach(
pthread_t thread) |
int
pthread_getspecific(
pthread_key_t key, void ** value) |
void*
pthread_getspecific(
pthread_key_t key) |
void pthread_lock_global_np() | int pthread_lock_global_np(void) |
void pthread_unlock_global_np() | int pthread_unlock_global_np(void) |
int
pthread_mutex_init(
pthread_mutex_t * mutex, pthread_mutexattr_t attr) |
int
pthread_mutex_init(
pthread_mutex_t * mutex, const pthread_mutexattr_t * attr) |
Table F-3 shows routines in the DECthreads d4 interface that have a corresponding pthread routine that does not support the obsolete d4-style datatypes. These datatypes were documented for previous releases of DECthreads.
If your original code used the standard DECthreads datatypes, then this migration requirement might not impact your code.
New Standard Datatype Syntax | Nonstandard Datatype Syntax |
---|---|
void
pthread_cleanup_push(
void (* routine)(void *), void * arg) |
int
pthread_cleanup_push(
pthread_cleanup_t * routine, pthread_addr_t arg) |
int
pthread_create(
pthread_t * thread, const pthread_attr_t * attr, void *(* start_routine)(void *), void * arg) |
int
pthread_create(
pthread_t * thread, pthread_attr_t attr, pthread_startroutine_t start_routine, pthread_addr_t arg) |
int
pthread_exit(
void * value_ptr) |
int
pthread_exit(
pthread_addr_t status) |
void *
pthread_getspecific(
pthread_key_t key) |
int
pthread_getspecific(
pthread_key_t key, pthread_addr_t * value) |
int
pthread_join(
pthread_t thread, void ** value_ptr) |
int
pthread_join(
pthread_t thread, pthread_addr_t * status) |
int
pthread_once(
pthread_once_t * once_control, void (* init_routine)(void)) |
int
pthread_once(
pthread_once_t * once_block, pthread_initroutine_t init_routine) |
int
pthread_setspecific(
pthread_key_t key, const void * value) |
int
pthread_setspecific(
pthread_key_t key, pthread_addr_t value) |
The following are routines in the DECthreads pthread interface that did not exist at the time of the implementation of the d4 interface: