The DECthreads and Win32 threads libraries are interoperable. Threads created using the Win32 API can use DECthreads synchronization primitives, and threads created using one of the DECthreads APIs can use the Win32 synchronization primitives. See Section C.5 for additional information.
Compile all multithreaded applications on Windows NT and Windows 95 systems with the -D_MT switch. This ensures that reentrant definitions, such as errno, are used with the application being built. Applications should also use the -DWIN32 and -D_DLL compiler switches. For example:
% CL /c myprog.c -D_MT -DWIN32 -D_DLL
The appropriate switches for compiling a multithreaded application can be obtained by using the $(CVARSMTDLL) switch found in the ntwin32.mak file. See the Building Apps/DLLs QuickRef documentation available through the Win32 SDK Online References (Common) online help icon for more build details.
Applications using C run-time library functions should be linked against one of the C run-time libraries that support multithreaded applications---either libcmt.lib, crtdll.lib or msvcrt.lib (depending on the compiler version being used.) For example:
% CL /link myprog.obj CRTDLL.LIB
libcmt.lib is a statically linked library that supports multithreading. crtdll.lib is an export library for crtdll.dll, a dynamically linked library that also supports multithreading. Multithreaded applications should not link against libc.lib because it does not support multithreaded applications.
DECthreads provides the following public header files:
Both exc_handling.h and pthread_exc.h are public files, and they may be included in customer code.
Threads created by DECthreads are fully interoperable with the Win32 API and can create and use Win32 synchronization elements and other constructs. Threads created using the Win32 API routine, CreateThread(), can also create and use DECthreads (POSIX 1003.4a) synchronization elements and other constructs.
The first time a thread created using the Win32 API makes a call into the DECthreads API, it becomes registered with the DECthreads package and is allowed to make use of DECthreads primitives. This type of thread should not call pthread_exit() because Win32 API threads are not set up to exit like a DECthreads API thread.
DECthreads considers threads created by the Win32 API detached by default and does not allow any other thread to join it. However, any Win32 created thread can join a DECthreads API created thread.
Threads created using the C run-time library function, _beginthread(), will interoperate with DECthreads the same way as a thread created using the Win32 API routine CreateThread().
DECthreads structured exception handling is interoperable with Microsoft C exception handling, but has slightly different syntax. DECthreads supports a different set of tokens for establishing exception blocks. The DECthreads tokens include TRY, CATCH, CATCH_ALL, FINALLY and ENTRY. The Microsoft tokens include try and except. The DECthreads exception semantics support multiple catch clauses and provide support for creating unique (address) exceptions. For more information about using the DECthreads exception-handling package, see Chapter 5. See the Microsoft C documentation for Microsoft C exception-handling information.
It is strongly recommended that the Win32 API routine TerminateThread() not be used. This routine terminates a thread immediately but does not provide a means for the thread to clean up any context it may have acquired while executing. Context that is left in an inconsistent state when calling TerminateThread(), such as a locked mutex, can cause unpredictable results. The only time that this routine should be used is if the entire process is being terminated one thread at a time. It is not recommended to terminate only one thread in an application with this routine and allow the process to continue.
The Win32 API routine ExitThread() should not be called by a thread created using any of the DECthreads creation routines (for example, pthread_create()). ExitThread() bypasses normal cleanup handlers and internal management routines. ExitThread() also leaves internal data structures in an inconsistent state and can produce unpredictable results.
System calls are not cancelation points. None of the system calls should be called with asynchronous cancelation enabled. For more information, see Section 2.3.7.
The following DECthreads interface routines are not implemented or supported on Windows NT or Windows 95:
If these routines are called by your application (because, for example, you are using the same code base on multiple Digital operating systems), and you do not want to remove them, then ensure that your code checks these functions' return values for unimplemented or unsupported or catches the unimplemented exception and takes appropriate action. The alternative is to conditionally compile the preceding unsupported routine calls.
Calling one of the above pthread_* routines will return a -1 and set errno to [ENOSYS].
Calling one of the preceding cma_* routines will raise the cma_e_unimp exception.
The following DECthreads interface routines are not implemented and do not return errors or generate exceptions. Do not use these routines. They will be fixed in a future release to return errors and generate exceptions.
The cma_attr_set_stacksize() and pthread_attr_setstacksize() routines do not change the stack size of newly created threads. Each DECthreads thread on Windows NT is created with its stack size set to the same size as the primary thread of the process in which it is created. The stack size grows as needed. See the Win32 documentation for CreateThread().
No errors or exceptions are generated as a result of using the cma_attr_set_stacksize() and pthread_attr_setstacksize() routines. Their corresponding routines cma_attr_get_stacksize() and pthread_attr_getstacksize() return the values set using cma_attr_set_stacksize() and pthread_attr_setstacksize(); but this is not useful because DECthreads threads are not created using the stacksize attribute.
These routines accept a maximum time_interval (or interval) value of 4294967.295 seconds. Values greater than this will raise the cma_e_badparam exception for cma_delay() and return -1 and set errno to [EINVAL] for pthread_delay_np().
During calls to cma_delay(), pthread_delay_np(), pthdexc_delay_np(), cma_timed_cond_wait(), pthread_cond_timed_wait(), and pthdexc_cond_timedwait(), an application might return before the expiration of the entire time interval specified in the call with no evidence of a premature return (exception or return status). This early return is a problem with the internal Win32 behavior of WaitForSingleObject(). The return might be up to 0.05 seconds earlier than the desired delay.
The debugging information in this appendix is specific to applications that use DECthreads. It describes how to use the DECthreads Debugger and provides additional debugging information for the Windows NT programmer.
The DECthreads Debugger is a powerful tool designed to complement your existing debugger. It provides you with thread-specific command-string debugging, statistical and historical thread information on request, and many useful thread debugging commands and qualifiers. To invoke the DECthreads Debugger:
SET IMAGE PTHREAD$RTL CALL PTHREAD_DEBUG
define/command pthread_debug= "set image pthread$rtl; call PTHREAD_DEBUG"
Notes
The DECthreads Debugger must be run within the context of a program being debugged. You cannot apply it to a core dump.The syntax of commands (and the list of supported commands) will change over time according to the needs of individual platforms. Never use calls to pthread_debug() or pthread_debug_cmd() as a part of a production application. It is for debugging use only and can be phased out when system debuggers take on all required debugging capabilities.
On Digital UNIX, when pthread_debug() or pthread_debug_cmd() is called for the first time within a process, DECthreads may need to dynamically load the DECthreads debug image (libpthreaddebug.so). Because the dlopen() function uses DECthreads synchronization, there are situations in which this may not succeed. In such cases, try loading the image early---that is, call pthread_debug_cmd() from the program's main routine, for example. Or use Ladebug thread commands, as described in Section D.2.
The pthread_debug() subsystem prompts for commands until the exit command is entered (Ctrl/Z on OpenVMS systems, or Ctrl/D on Digital UNIX systems). Entering an unrecognized command results in a short help message listing the valid commands and arguments. The help command gives more extensive information on the switches available for each command.
The command syntax resembles UNIX shell syntax: a command name followed by a list of arguments and switches, separated by blanks (spaces and tabs). The arguments and switches may appear in any order. The command name itself can be abbreviated. You can combine multiple switches into a single argument. For example:
thread -tf
instead of
Instead of calling pthread_debug(), you can call pthread_debug_cmd(). The pthread_debug_cmd() function implements the same commands, except that instead of prompting it processes command strings specified as an argument to the function.
You can include multiple commands by separating them with semicolons (;). For example:
pthread_debug_cmd ("thread -if;cond -f");
The pthread_debug_cmd() function returns a value representing the status of the last command executed. When called from a program, you can check the return status values listed in Table D-1 against the various status constants defined in the pthread.h header file.
Return Status | Meaning |
---|---|
PTHREAD_DBG_SUCCESS | Command was successful. |
PTHREAD_DBG_QUIT | Last command was quit or exit. |
PTHREAD_DBG_NONESEL | No objects were selected (no output). |
PTHREAD_DBG_NOPRIV | Unable to complete command due to privilege violation. |
PTHREAD_DBG_INVPARAM | Invalid command parameter (such as bad policy keyword). |
PTHREAD_DBG_INVSEQ | Invalid sequence number. |
PTHREAD_DBG_INCONSTATE | Inconsistent state detected in internal data; this may mean a thread is currently modifying data. |
PTHREAD_DBG_CORRUPT | Corrupt data detected (inconsistent state prevents the command from continuing). |
PTHREAD_DBG_INVOPTION | Invalid command option specified. |
PTHREAD_DBG_NOARG | No arguments specified to command that requires them. |
PTHREAD_DBG_INVADDR | Invalid address argument specified. |
PTHREAD_DBG_INVCMD | Invalid command specified. |
PTHREAD_DBG_NULLCMD | No command specified. |
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 the environment variable (or OpenVMS logical name) PTHREAD_CONFIG prior to running any threaded application. The variable (or logical name) 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 "poisons" all thread stacks (except the main thread stack) with a specific pattern. When using the thread -f or stack command in pthread_debug(), DECthreads computes the number of bytes actually modified by the program on each stack.
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.
The following operations are illegal and are always reported as errors when used on errorcheck mutexes but might not be reported for nonmetered normal mutexes:
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.
DECthreads Debugger commands and their qualifiers are listed in the following sections. Individual DECthreads objects may be referenced by their sequence number. Each object has a number that is unique within its object class; this number is displayed when an object is listed.
The conditions command lists all known condition variables in use.
DECthreads may not know about condition variables that were statically initialized and have not been used recently. It cannot keep track of each pthread_cond_t structure within a program---only "auxiliary" structures that are allocated within DECthreads when a thread blocks on a condition variable. When metering, all condition variables that have ever been used are known.
Format:
conditions[condition-variable-number] [qualifier]
condition-variable-number
One or more object sequence numbers separated by spaces. If specified, only those condition variables whose sequence numbers are listed are displayed. Each argument that does not begin with "-" is interpreted as the sequence number of a condition variable.
Table D-2 lists the valid qualifier argument switches.
Qualifier | Description |
---|---|
-a | Include internal condition variables created by DECthreads. |
-f | Display complete information about the state of each condition variable, including whether there are deferred signal operations or pending wakeups that need to be processed. |
-h | Display the history buffer of recent operations carried out on each condition variable. This history is maintained only when DECthreads is run with metering enabled. Each line in the history shows a specific operation (wait, signal, or broadcast), with additional information such as whether a signal or broadcast awakened another thread. It also shows the thread that invoked the function and the program PC from which DECthreads was called. This information is available when DECthreads is run with metering enabled. |
-q | Display the sequence number of each thread that is waiting on a condition variable (if there are any waiters). |
-s | Display statistics for each condition variable. This includes the number of waits, signals, and broadcasts, the number of times a thread actually blocked on the condition variable, the maximum and average number of threads blocked on the condition variable at any time. This information is available when DECthreads is run with metering enabled. |
-w | List only condition variables that have threads waiting on them. |
Exit or quit pthread_debug() or pthread_debug_cmd() and return to the program (or the debugger) immediately.
Format:
The help command describes the commands and options available within pthread_debug(). Without arguments, help provides a one-line description of each command, with a list of the options supported. You can also specify an argument; help will give a full description of all commands having the argument as an initial string.
Format:
help[command]
command
Any DECthreads Debugger command. For example, help t will describe the thread and tset commands in detail. To get a full description of all commands, you can type help*. When you enter a command that is not recognized, pthread_debug will display the same output as help without arguments.
The keys command displays the thread-specific data keys currently defined in the process. They are identified by sequential integers. The address of the destructor routine (if any) is displayed for each.
Format:
List all known mutexes in use. DECthreads may not know about mutexes that were statically initialized and haven't been used recently. It cannot keep track of each pthread_mutex_t structure within a program---only "auxiliary" structures that are allocated within DECthreads when a thread blocks on a mutex. When metering, all mutexes that have ever been used are known.
Format:
mutexes[object-number] [qualifier]
object-number
One or more object sequence numbers separated by spaces. If specified, only those objects whose sequence numbers are listed are displayed. Each argument that does not begin with "-" is interpreted as the sequence number of an object.
Table D-3 lists the valid qualifier argument switches.
Qualifier | Description |
---|---|
-a | Include internal mutexes created by DECthreads. |
-f | List additional information for each mutex. |
-h | Display the history buffer of recent operations carried out on each mutex. This history is maintained only when DECthreads is run with metering enabled. Each line in the history shows a specific operation (lock or unlock), with additional information such as whether an unlock awakened another thread and whether a lock attempt resulted in blocking the thread. It also shows the thread that invoked the function and the program PC from which DECthreads was called. This information is available when DECthreads is run with metering enabled. |
-l | List only locked mutexes. |
-q | Display the sequence number of each thread waiting to lock a mutex (if there are any waiters). |
-s | Display statistics for each mutex. This includes the number of locks and unlocks, the number of times a thread actually blocked on the mutex, the maximum number of threads blocked on the mutex at any time, and an average "contention" for the mutex, which is the average number of waiters. This information is available when DECthreads is run with metering enabled. |
The show command displays various types of DECthreads information.
Format:
show[qualifier]
Table D-4 lists the valid qualifier argument switches.
Qualifier | Description |
---|---|
-c | Identify the thread currently executing the show -c command. |
-s | List the scheduling policies supported by DECthreads, with the range of priorities allowed for each. |
-v | Display the state of all current kernel "threads" in the process, whether active or cached (valid in a DECthreads implementation that uses kernel-supplied concurrency objects). |
The stack command displays information on DECthreads stacks. It displays the start and end address of each stack area. When running in metered mode, it also displays an estimate of the number of bytes used on each thread's stack (except for the default stack).
Format:
stack[stack-number] [qualifier]
stack-number
Each argument that does not begin with "-" is interpreted as an address within some thread's stack. This will cause the command to give information only on the stacks containing the specified addresses. An address is specified in C language syntax as follows: <NUMBER> for decimal, 0<NUMBER> for octal, or 0x<NUMBER> for hexadecimal.)
Table D-5 lists the valid qualifier argument switches:
Qualifier | Description |
---|---|
-f | List the start and end address of the stack guard pages for each allocated stack. |
-s | Include statistics for each stack. Currently, the only statistic reported is the maximum number of bytes written by the thread. This information can only be calculated for stacks other than the default process stack. This information is available when DECthreads is run with metering enabled. |
The system command displays information about the system on which you are running. This includes the name of the hardware (where DECthreads can determine it), for example "DEC 3000 model 300 AXP," the size of physical memory, and the number of CPUs.
Format:
The threads command lists all known threads except internal threads created by DECthreads (including the null threads, which are run when a virtual processor can find no other thread to execute).
Format:
threads[threads-number] [qualifier]
6493P017.HTM OSSG Documentation 22-NOV-1996 13:20:22.52
Copyright © Digital Equipment Corporation 1996. All Rights Reserved.