![]() |
![]() HP OpenVMS Systems Documentation |
![]() |
Guide to the POSIX Threads Library
5.8 Operations on ExceptionsIn addition to raising, catching, and reraising exception objects, the exceptions package supports the following API-level operations on exception objects:
The following sections discuss these operations.
Within a CATCH or CATCH_ALL code block the caught exception object can be referenced by using the THIS_CATCH symbol. You cannot use THIS_CATCH in a FINALLY code block because there might not be an exception. The THIS_CATCH definition has a type of EXCEPTION * . This value can be passed to the pthread_exc_get_status_np() , pthread_exc_report_np() , or pthread_exc_matches_np() routines, as described in Section 5.8.3, Section 5.8.4, and Section 5.8.5.
5.8.2 Setting a System-Defined Error StatusUse the pthread_exc_set_status_np() routine to set a status value in an existing address exception object. This converts an address exception object into a status exception object. This routine's exception object argument must already have been initialized with the exceptions package's EXCEPTION_INIT macro, as described in Section 5.3.1. In a program that uses status exceptions, use this routine to associate a system-specific status value with the specified exception object. Note that any exception objects set to the same status value are considered equivalent by the Threads Library. Example 5-10 demonstrates setting an error status in an address exception object.
5.8.3 Obtaining a System-Defined Error Status
In a program that uses status exceptions, use the
Example 5-11 demonstrates using the pthread_exc_get_status_np() routine to obtain the status value associated with a caught status exception object.
5.8.4 Reporting a Caught ExceptionUse the pthread_exc_report_np() routine to produce a message that reports what a given exception object represents. Your program calls this routine within a CATCH or CATCH_ALL code block to report on a caught exception. An exception in your program that has not been handled by a CATCH or CATCH_ALL causes the unhandled exception handler to report the exception and immediately terminate the process. However, you might prefer to report a caught exception as part of your program's error recovery. The pthread_exc_report_np() routine prints a message to stderr (on Tru64 UNIX systems) or SYS$ERROR (on OpenVMS systems) that describes the exception. Each defined exception has an associated message that describes the given error condition. Typically, external status values can also be reported. When an address exception is reported, the Threads Library can only report the fact that an exception has occurred and the address of the exception object.
See Example 5-11 for an example using the
pthread_exc_report_np()
routine to report an error.
The pthread_exc_matches_np() routine compares two exception objects, taking into consideration whether each is an address exception or a status exception. Whenever you must compare two exception objects, use this routine. Example 5-12 demonstrates how to use the pthread_exc_matches_np() routine to test for the equivalence of two exception objects.
5.9 Using Exceptions
This section presents guidelines for using exceptions in a modular way,
so that independent software components can be written without
requiring knowledge of each other, and includes tips on writing code
using exceptions.
Develop naming conventions for exception objects. A naming convention ensures that the names for exceptions that are declared extern in different modules do not conflict. The following convention is recommended:
Example:
pthread_cancel_e
In a TRY code block avoid including code that more appropriately belongs outside it (in particular, before it). That is, the TRY macro should guard only operations for which there are appropriate handler operations in the scope's FINALLY , CATCH , or CATCH_ALL code blocks. A common misuse of a TRY code block is to include code that should be executed before the TRY macro is invoked. Example 5-13 demonstrates this misuse.
In this example, the FINALLY code block assumes that no exception is raised by calling the open_file() routine. If calling open_file() results in raising an exception, the FINALLY code block's close() operation will use an invalid identifier. Thus, the code in Example 5-13 should be rewritten as shown in Example 5-14.
Notice that the initialization code belongs prior to the invoking of the
TRY
macro, and the matching cleanup code belongs in the
FINALLY
code block. In this example, the
open_file()
call is moved to before the
TRY
macro, and the
close()
call is kept in the
FINALLY
block.
Raise exceptions prior to performing side-effects. That is, write routines that propagate exceptions to their callers, so that the routine does not modify any persistent process state before raising the exception. A matching close() call is required only if the open_file() operation is successful. (If an exception is raised, the caller cannot access the output parameters of the function, because the compiler may not have copied temporary values back to their home locations from registers.)
If the
open_file()
routine raises an exception, the identifier will not have been written,
so this open operation must not require that a corresponding
close()
routine is called when
open_file()
raises an exception.
Do not place a
return
or
goto
statement between
TRY
and
ENDTRY
. It is invalid to return from, branch from, or leave by other means a
TRY
,
CATCH
,
CATCH_ALL
, or
FINALLY
block, such as by using a
continue
or
break
in an exception scope contained inside a loop or
switch
statement. After a given
TRY
macro is executed, the exceptions package requires that the
corresponding
ENDTRY
macro is also executed unless an exception is raised or reraised.
When declaring certain variables that are used within an exception scope, you must use the ANSI C volatile type attribute. The volatile attribute prevents the compiler from producing certain optimizations about such variables that would be unsafe if an exception were raised. This ensures that such a variable's value is reliable in an exception handler after an exception is raised. Use the volatile type attribute for a variable whose value is written after the TRY macro is invoked and before the first CATCH/CATCH_ALL/FINALLY macro is invoked and whose value must be used when an exception is caught within a CATCH/CATCH_ALL/FINALLY block or (if the exception is caught and not reraised) after the ENDTRY macro is invoked. Example 5-15 demonstrates the significance of using the volatile type qualifier for variables that are referenced within an exception scope.
The code in Example 5-15 demonstrates:
Test your program after compiling it with the "optimize"
compiler option, to ensure that your program contains the appropriate
exception handler code.
Reraise exceptions that are not fully handled. That is, reraise any exception that you catch, unless your handler has performed the complete recovery action for the error. This rule permits an unhandled exception to propagate to some final default handler that knows how to recover fully. A corollary of this rule is that CATCH_ALL handlers must always reraise the exceptions they catch because they can catch any exception, including those not explicitly known to your code.
It is important to follow this convention, so that your program does
not stop the propagation of a thread cancelation exception or
thread-exit request exception. The Threads Library maps these requests
into exceptions, so that exception handler code can have the
opportunity to handle all exceptional conditions---from access
violations to thread-exit. In some applications it is important to be
able to catch these to preserve an external invariant, such as an
on-disk database, but they must always be reraised so that the thread
will terminate properly.
Avoid dynamically allocated exception objects. Local exception objects
should be declared (explicitly or implicitly) as
static
, and
extern
exception objects are acceptable.
Table 5-1 lists the names of exception objects that are defined by the Threads Library and the meaning of each exception. Exception object names that begin with the prefix pthread_ are raised within the runtime environment itself and are not meant to be raised by your program code. Names of exception objects that begin with pthread_exc_ are generic and belong to the exceptions package or represent exceptions raised by the underlying system.
|