Updated: 11 December 1998 |
Guide to DECthreads
Previous | Contents | Index |
All event flags are shared by all threads in the process. Therefore, it is possible for different threads' use of the same event flag to cause interference.
If two threads use the same event flag in calls to different system services, whichever service completes first will cause both threads to awaken, even though the other service has not completed. This situation can be resolved by specifying an I/O status block (IOSB) for those system services that use them. When an IOSB is present, the blocked thread will not be awakened when the event flag is set, unless the IOSB has also been written.
A DECthreads process is rarely in LEF state. In general, instead of blocking for an event flag wait, DECthreads schedules another thread to be run. However, if no threads are available, DECthreads schedules a "null" thread, which places the virtual processor in HIB state until it is needed to execute a thread.
If a thread calls a system service that uses a common event flag, the calling thread's virtual processor blocks until the wait is satisfied. (That is, no upcall is made to the OpenVMS kernel to schedule another thread.) On a uniprocessor, such a system service call will most likely cause all threads in the process to block. |
There are several interactions with the OpenVMS operating system that should be noted:
In multithreaded processes, image exit occurs as follows: $EXIT does not immediately invoke exit handler routines. Instead, it results in an upcall that causes DECthreads to schedule a special thread to execute the exit-handler routines. $EXIT then calls pthread_exit() to terminate the calling thread. This allows the calling thread to release any resources that it might be holding.
To avoid possible deadlocks, the exit-handler routines are executed in a separate thread. For example, if a thread calls $EXIT while holding a mutex that is required by an exit-handler routine, then that routine causes the thread to block forever, as it waits for a mutex that it already holds. Because the exit-handler routine executes in a separate thread, it can block while the thread holding the mutex cleans up.
$FORCEX works in an analogous fashion. Instead of invoking $EXIT directly, it causes an upcall that allows DECthreads to release the exit-handler thread.
DCL Ctrl/Y continues to work as it always has on multithreaded applications. However, typing EXIT or issuing any other command that invokes a new image causes the $FORCEX upcall. While this is an improvement in many cases over the behavior prior to OpenVMS Version 7.0, it does not guarantee that the multithreaded application will exit.
For example, if the application is deadlocked, holding a resource
required by one of the exit handler's routines, the application will
continue to hang, even after typing Ctrl/Y and EXIT. In these cases,
type Ctrl/Y and STOP to terminate the application without running exit
handlers. Note that doing so causes the application to be unable to
clean up, and it may leave data files and the terminal in an
inconsistent state.
B.12.11 SYSGEN Parameter MULTITHREAD
The SYSGEN parameter MULTITHREAD limits the maximum number of kernel
threads per process. It is set by AUTOGEN to the number of CPUs on the
system. If MULTITHREAD is set to zero (0), two-level scheduling support
is disabled, and DECthreads reverts to its behavior prior to OpenVMS
Version 7.0---that is, no upcalls can occur, and DECthreads does not
use all processors in multiprocessor systems.
B.12.12 Process Control System Services and DCL Commands
OpenVMS system services and DCL commands are either process based or
operate on a per-thread basis. This section identifies several system
services on this basis.
B.12.12.1 Process-Level System Services
The following system services continue to be process based: $SUSPEND, $RESUME, and $DELPRC. These services will operate on an entire process; they are not thread based. For example, $SUSPEND issued by a thread will suspend all of the virtual processors in process, not just the calling thread.
Under OpenVMS Version 7.0 or later, it is possible to see all but one
of your kernel threads in SUSP state, such as when at a breakpoint in
the debugger. This effect is a part of the debugging support and is not
the result of calling $SUSPND.
B.12.12.2 Kernel-Level System Services
The following system services now operate on a per-thread basis:
$HIBER, $SCHDWK, and $SYNCH. These services will not operate on an
entire process; they are thread based. For example, $HIBER will cause
the calling thread to become inactive but will not affect other threads
in the process.
B.12.12.3 DCL Commands
The following DCL commands operate as indicated:
Previous releases of the POSIX for OpenVMS layered product had very limited interoperability with DECthreads. Under OpenVMS Version 7.0 and later, using DECthreads with the POSIX for OpenVMS layered product is not supported.
This appendix discusses DECthreads issues and restrictions specific to
its implementation under the Windows NT operating system.
C.1 DECthreads Interfaces on Windows NT Systems
The Win32 subsystem provides support for multithreading through the Win32 Application Programming Interface (API). The Win32 API allows for thread creation, termination, synchronization, and other thread functions.
The DECthreads and Win32 threads libraries are interoperable. Threads
created using the Win32 API can use DECthreads synchronization
primitives, for example, and threads created by DECthreads can use the
Win32 synchronization primitives. See Section C.4 for more
information.
C.1.1 pthread Interface
To add value to the Win32 API, DECthreads provides its POSIX 1003.1c-1995 (pthread) interface, which is available across all Compaq platforms.
Note these differences in support for the DECthreads pthread interface routines on Windows NT systems:
In addition, the DECthreads exception package is also available to support handling of DECthreads exceptions in conjunction with use of the pthread interface. See Section C.4 for more information.
The following DECthreads pthread interface routines are not implemented for Windows NT systems, and also do not return errors or generate exceptions:
Do not use these routines. In a future DECthreads release they will be changed to return errors and generate exceptions:
The pthread_attr_setstacksize() routine does not change the stack size of newly created threads. On Windows NT a thread that DECthreads creates has a stack of the same size as for its process's primary thread. The stack size grows as needed. (See the Win32 documentation for the CreateThread() routine.) No errors or exceptions are generated as a result of using pthread_attr_setstacksize().
The corresponding pthread_attr_getstacksize() routine returns the value that was set using pthread_attr_setstacksize(), but this is not useful because a DECthreads thread is not created using the thread attributes object's stack size attribute.
An attempt to set the scheduling policy or priority attributes of an existing thread or in a thread attributes object using of the following routines produces a return value of [ENOTSUP]:
The DECthreads thread-independent services (or tis) interface is not yet available for Windows NT systems.
The DECthreads proprietary CMA (or cma) and POSIX
1003.4a/Draft 4 (or d4) interfaces are no longer
offered for Windows NT systems. See Appendix E and Appendix F for
information about migrating your applications from the DECthreads
cma and d4 interfaces, respectively,
to the DECthreads pthread interface.
C.2 Compiling DECthreads Applications
For a dynamically linked program, compile with the /MT switch. For a statically linked program, compile with the /MD switch. These switches ensure that reentrant definitions, such as errno, are used. For example:
% CL /c myprog.c /MT |
Applications that use the C run-time library should be linked against one of two C run-time libraries that support multithreading, as follows:
Multithreaded applications should not link against libc.lib
because it does not support multithreading.
C.4 Interoperability of Win32 API and DECthreads pthread Routines
Win32 threads can create, use, and operate on DECthreads primitives, such as synchronization objects, as any thread created by DECthreads can. Win32 threads can operate on both threads created by DECthreads and other Win32 threads using the DECthreads pthread interface routines---that is, Win32 threads can join with them, cancel them, and so on.
A Win32 thread can operate directly on a thread created by DECthreads using the Win32 API, provided that it can obtain a Win32 handle to that thread. A Win32 thread can synchronize with a thread created by DECthreads and with other Win32 threads using DECthreads synchronization objects, just as threads created by DECthreads synchronize with each other. A Win32 thread can synchronize with a thread created by DECthreads using Win32 synchronization objects the same way that Win32 threads synchronize with each other.
A thread created by DECthreads can use the Win32 API to obtain a Win32 handle to itself, which allows it to be operated on via Win32 API routines. It can operate on Win32 threads and threads created by DECthreads (including itself) using Win32 API routines the same way that Win32 threads operate on each other. It can synchronize with Win32 threads and other threads created by DECthreads using Win32 synchronization objects the same way that Win32 threads synchronize with each other. It can synchronize with Win32 threads using DECthreads synchronization objects. It can operate on Win32 threads, use pthread_cancel() to cancel them, use pthread_join() to join with them, and so on---but only if the Win32 thread has previously made a call into the DECthreads library, which registers the Win32 thread with the DECthreads run-time environment.
It is strongly recommended that a thread created by DECthreads not call TerminateThread(). This routine terminates a thread immediately and does not provide any means for the thread to clean up any context it might have acquired while executing. Context that is left in an inconsistent state when calling TerminateThread(), such as a locked mutex, can cause unpredictable results in your program.
Using pthread_cancel() to cancel the initial (or "primary") thread of a Win32 process causes the process to exit in the same manner as if it were terminated as the result of a call to the Win32 routine ExitThread().
DECthreads structured exception handling is interoperable with Win32 exception handling, but has a slightly different syntax. DECthreads supports a different set of tokens for defining exception blocks. The DECthreads tokens include TRY, CATCH, CATCH_ALL, FINALLY, and ENDTRY. The Microsoft tokens include __try, __except, and __finally.
The DECthreads exception semantics support multiple catch clauses and provide support for creating unique exceptions (that is, DECthreads address exceptions). For more information, see Chapter 5.
DECthreads exception blocks can be nested inside of Win32 exception
blocks, and vice versa. The DECthreads CATCH_ALL macro will
catch all exceptions---those raised via DECthreads exception handling
macros, those raised via Win32, and system-raised exceptions.
C.5 Thread Cancelability of System Services
Win32 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 debugging information in this appendix is specific to applications
that use DECthreads.
D.1 Using PTHREAD_CONFIG
During initialization of the DECthreads run-time environment, the
PTHREAD_CONFIG environment variable (on DIGITAL UNIX and
Windows NT 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 DECthreads
application.
D.1.1 Major and Minor Keywords
As summarized in Table D-1, PTHREAD_CONFIG takes "major keywords" as arguments. Use a "minor keyword" to specify a value for each major keyword.
Major keyword | Minor keyword | Meaning |
---|---|---|
dump= | file-path | Path of DECthreads bugcheck file |
meter= |
condition
mutex stack thread all none |
Meter condition variable operations
Meter mutex operations Record thread greatest stack extent (Unused) Meter all available operations No metering |
width= | bugcheck_output_width | Width of output from DECthreads bugcheck output |
When setting PTHREAD_CONFIG, use a semicolon to separate major keyword expressions and use a comma to separate minor keyword values. For example, using the C shell under DIGITAL UNIX, you can set PTHREAD_CONFIG as follows:
% setenv PTHREAD_CONFIG meter=thread,mutex;dump=/tmp/dump-%d.dmp;width=132 |
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.
D.2 Running DECthreads in Metered Mode
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.
D.3 Using Ladebug on DIGITAL UNIX Systems
The Compaq 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.
D.4 Debugging Threads on OpenVMS Systems
This section presents particular topics that relate to debugging a
multithreaded application under OpenVMS.
D.4.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 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.
D.5 Debugging Threads on Windows NT Systems
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.
Previous | Next | Contents | Index |
Copyright © Compaq Computer Corporation 1998. All rights reserved. Legal |
6101PRO_031.HTML
|