Tru64 UNIX
Guide to the POSIX Threads Library


Previous Contents Index


Appendix C
Debugging Multithreaded Applications

The debugging information in this appendix is specific to applications that use the POSIX Threads Library.

C.1 Using PTHREAD_CONFIG

During initialization of the Threads Library run-time environment, the PTHREAD_CONFIG environment variable (on Tru64 UNIX systems) or logical symbol (on OpenVMS systems), if defined, is used to set static options for the multithreaded program. You can set PTHREAD_CONFIG to assist you in debugging a Threads Library application.

C.1.1 Major and Minor Keywords

As summarized in Table C-1, PTHREAD_CONFIG takes "major keywords" as arguments. Use a "minor keyword" to specify a value for each major keyword.

Table C-1 PTHREAD_CONFIG Settings
Major keyword Minor keyword Meaning
dump= file-path Path of bugcheck file (OpenVMS only)
meter= condition Meter condition variable operations
  mutex Meter mutex operations
 
stack
Record thread greatest stack extent
  all Meter all available operations
  none No metering
width= bugcheck_output_width Width of output from bugcheck output

C.1.2 Specifying Multiple Values

When setting PTHREAD_CONFIG , use a semicolon to separate major keyword expressions and use a comma to separate minor keyword values. For example, using DCL under OpenVMS, you can set PTHREAD_CONFIG as follows:


 
   $ define PTHREAD_CONFIG "meter=(stack,mutex);dump=/tmp/dump-d.dmp;width=132" 
 

C.2 Running in Metered Mode

Metering tells the Threads Library 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 the Threads Library 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 the Threads Library to gather and record statistics and history information for all synchronization operations.

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.

C.3 Visual Threads

We recommend Visual Threads to debug Threads Library applications on Tru64 UNIX and OpenVMS systems. Visual Threads can be used to automatically diagnose common problems associated with multithreading, including deadlock, protection of shared data (on Tru64 UNIX systems only), and thread usage errors. It can also be used to monitor the thread-related performance of an application, helping you to identify bottlenecks or locking granularity problems. It is a unique debugging tool because it can be used to identify problem areas even if an application does not show any specific symptoms.

See the online Visual Threads documentation at www.compaq.com/visualthreads/ for more information.

C.4 Using Ladebug on Tru64 UNIX Systems

The Compaq Ladebug debugger provides commands to display the state of threads, mutexes, and condition variables.

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.

C.5 Debugging Threads on OpenVMS Systems

This section presents particular topics that relate to debugging a multithreaded application under OpenVMS.

C.5.1 Display of Stack Trace from Unhandled Exception

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 TRY / CATCH , TRY / FINALLY , or POSIX cleanup handlers are used, from the point where it was last reraised to the bottom of the stack.


Appendix D
Migrating from the d4 Interface

This appendix provides migration information for the routines in the POSIX 1003.4a/Draft 4 (or d4) interface.

Note

Applications that use the d4 routines require significant modification to be migrated to the pthread interface described in Part 2.

D.1 Overview

Routines in the pthread interface differ significantly from the original POSIX 1003.4a/Draft 4 implementation. This section describes the major changes between the interfaces.

D.2 Error Status and Function Returns

The pthread interface does not use the global variable errno. (Note that the Threads Library provides a thread-specific errno for use by libraries and application code, but the 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 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).

D.3 Replaced or Renamed Routines

Many routines in the d4 interface have been replaced or renamed in the pthread interface, as shown in Table D-1.

Table D-1 pthread Routines That Replace d4 Routines
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/getguardsize_np() pthread_attr_set/getguardsize()
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()
pthread_setasynccancel() pthread_setcanceltype()
pthread_setcancel() pthread_setcancelstate()
pthread_set/getprio() pthread_set/getschedparam()
pthread_set/getscheduler() pthread_set/getschedparam()
pthread_yield() sched_yield()

D.4 Routines with No Changes to Syntax

Except for the return value, the following routines in the d4 interface have no changes to syntax in the pthread interface:

pthread_attr_setinheritsched()
pthread_cancel()
pthread_cond_broadcast()
pthread_cond_destroy()
pthread_cond_signal()
pthread_cond_signal_int_np()
pthread_cond_timedwait()
pthread_cond_wait()
pthread_delay_np()
pthread_equal()
pthread_exit()
pthread_get_expiration_np()
pthread_join() (now detaches the thread)
pthread_mutex_destroy()
pthread_mutex_lock()
pthread_mutex_trylock()
pthread_mutex_unlock()
pthread_once()

The following routines have no changes in syntax or return value:

pthread_self()
pthread_testcancel()

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).

D.5 Routines with Prototype or Syntax Changes

Table D-2 shows the routines in the d4 interface that have changes to their argument syntax in the pthread interface.

Table D-2 d4 Routines With Syntax Changes as pthread Routines
Old Syntax New Syntax
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_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 D-3 shows routines in the 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 the Threads Library.

If your original code used the standard Threads Library datatypes, then this migration requirement might not impact your code.

Table D-3 d4 Routines Whose pthread Counterpart Uses Standard Datatypes
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)

D.6 New Routines

The following are routines in the pthread interface that did not exist at the time of the implementation of the d4 interface:

pthread_atfork() (Tru64 UNIX only)
pthread_attr_getscope()
pthread_attr_setscope()
pthread_key_delete()
pthread_kill() (Tru64 UNIX only)
All pthread_rwlockattr_ and pthread_rwlock_ routines
pthread_sigmask() (Tru64 UNIX only)
All _getpshared and _setpshared routines


Previous Next Contents Index