Previous | Contents | Index |
In 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.
5.8.1 Referencing the Caught Exception
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.
Because of the way that the exceptions package propagates exception objects, the address contained in THIS_CATCH might not be the actual address of an address exception. To match THIS_CATCH against known exceptions, use the pthread_exc_matches_np() routine, as described in Section 5.8.5. Furthermore, the value of THIS_CATCH may become invalid when control leaves the CATCH or CATCH_ALL block. |
Use 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.
Example 5-10 Setting an Error Status in an Exception Object |
---|
static EXCEPTION an_error; unsigned long status_code = ENOMEM; EXCEPTION_INIT (an_error); /* Import status code into an existing, initialized, address exception object */ pthread_exc_set_status_np (&an_error, status_code); |
On OpenVMS systems: Threads Library exception status values are OpenVMS condition codes with a SEVERE severity level. If necessary, the pthread_exc_set_status_np() routine will modify the severity level of the status code to SEVERE. |
In a program that uses status exceptions, use the
pthread_exc_get_status_np()
routine to obtain the status value from a status exception object, such
as after an exception is caught. If the routine's exception
argument is a status exception object, it sets the status code
argument and returns 0 (zero); otherwise, it returns [EINVAL] and does
not set the status value argument.
Example 5-11 demonstrates using the pthread_exc_get_status_np() routine to obtain the status value associated with a caught status exception object.
Example 5-11 Obtaining the Error Status Value from a Status Exception Object |
---|
#include <pthread_exception.h> . . . TRY { operation (); } CATCH_ALL { unsigned long status_code; if (pthread_exc_get_status_np (THIS_CATCH, &status_code) == 0 && status_code == SOME_ERROR) fprintf (stderr, "Exception %ld caught from system.\n", SOME_ERROR); else pthread_exc_report_np (THIS_CATCH); } ENDTRY |
Use 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.
5.8.5 Determining Whether Two Exceptions Match
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.
Example 5-12 Comparing Two Exception Objects |
---|
#include <pthread_exception.h> . . . EXCEPTION my_status; EXCEPTION_INIT (my_status); pthread_exc_set_status_np (&my_status, status_code); . . . TRY { . . . } . . . CATCH_ALL { if (pthread_exc_matches_np (THIS_CATCH, &my_status)) fprintf (stderr, "This is my exception\n"); RERAISE; } ENDTRY |
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.
5.9.1 Develop Naming Conventions for 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:
facility-prefix_error-name_e |
Example:
pthread_cancel_e
5.9.2 Enclose Appropriate Actions in an Exception Scope
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.
Example 5-13 Incorrect Placement of Statements That Might Raise an Exception |
---|
TRY { handle = open_file (file_name); /* Statements that might raise an exception here */ } FINALLY { close (handle); } ENDTRY |
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.
Example 5-14 Correct Placement of Statements That Might Raise an Exception |
---|
handle = open_file (file_name); TRY { /* Statements that might raise an exception here */ } FINALLY { close (handle); } ENDTRY |
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.
5.9.3 Raise Exceptions Prior to Performing Side-Effects
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.
5.9.4 Exiting an Exception Scope
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.
5.9.5 Declare Variables Within Handler Code as Volatile
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.
Example 5-15 Use of the Volatile Type Qualifier Within an Exception Scope |
---|
void demonstrate_volatile_in_exception_scope (void ) { int updated_before_try; int updated; static int updated_static; volatile int updated_volatile; updated_before_try = 1; updated = 2; updated_static = 3; updated_volatile = 4; TRY { updated = 6; updated_static = 7; updated_volatile = 8; something_that_might_result_in_an_exception(); } CATCH (fully_handled_exception) { /* Fully handle the exception here. Execute the code after ENDTRY next. */ } CATCH_ALL { (1) if (updated > updated_static) printf ("%d, %d", updated, updated_before_try); if (updated > updated_volatile) printf ("%d, %d", updated, updated_before_try); RERAISE; } ENDTRY (2) /* The following two statements use invalid references to the variables updated and updated_static.** */ if (updated > updated_static) printf ("%d, %d", updated, updated_before_try); if (updated > updated_volatile) printf ("%d, %d", updated, updated_before_try); } /* end demonstrate_volatile_in_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.
5.9.6 Reraise Caught Exceptions That Are Not Fully Handled
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.
5.9.7 Avoid Dynamically Allocated Exception Objects
Avoid dynamically allocated exception objects. Local exception objects
should be declared (explicitly or implicitly) as
static
, and
extern
exception objects are acceptable.
5.10 Exceptions Defined by the POSIX Threads Library
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.
Exception | Definition |
---|---|
pthread_cancel_e | Thread cancelation in progress |
pthread_exc_aritherr_e | Unhandled floating-point exception signal ("arithmetic error") |
pthread_exc_decovf_e | Unhandled decimal overflow exception |
pthread_exc_excpu_e | "CPU-time limit exceeded" |
pthread_exc_exfilsiz_e | "File size limit exceeded" |
pthread_exc_exquota_e | Operation failed due to insufficient quota |
pthread_exc_fltdiv_e | Unhandled floating-point/decimal divide by zero exception |
pthread_exc_fltovf_e | Unhandled floating-point overflow exception |
pthread_exc_fltund_e | Unhandled floating-point underflow exception |
pthread_exc_illaddr_e | Data or object could not be referenced |
pthread_exc_illinstr_e | Unhandled illegal instruction signal ("illegal instruction") |
pthread_exc_insfmem_e | Insufficient virtual memory for requested operation |
pthread_exc_intdiv_e | Unhandled integer divide by zero exception |
pthread_exc_intovf_e | Unhandled integer overflow exception |
pthread_exc_noexcmem_e | Out of memory while processing an exception |
pthread_exc_nopriv_e | Insufficient privilege for requested operation |
pthread_exc_privinst_e | Unhandled privileged instruction fault exception |
pthread_exc_resaddr_e | Unhandled reserved addressing fault exception |
pthread_exc_resoper_e | Unhandled reserved operand fault exception |
pthread_exc_SIGABRT_e | Unhandled signal ABORT |
pthread_exc_SIGBUS_e | Unhandled bus error signal |
pthread_exc_SIGEMT_e | Unhandled EMT signal |
pthread_exc_SIGFPE_e | Unhandled floating-point exception signal |
pthread_exc_SIGILL_e | Unhandled illegal instruction signal |
pthread_exc_SIGIOT_e | Unhandled IOT signal |
pthread_exc_SIGPIPE_e | Unhandled broken pipe signal |
pthread_exc_SIGSEGV_e | Unhandled segmentation violation signal |
pthread_exc_SIGSYS_e | Unhandled bad system call signal |
pthread_exc_SIGTRAP_e | Unhandled trace or breakpoint trap signal |
pthread_exc_subrng_e | Unhandled subscript out of range exception |
pthread_exc_uninitexc_e | Uninitialized exception raised |
pthread_exit_e | Thread exiting using pthread_exit() |
pthread_stackovf_e | Attempted stack overflow was detected |
Previous | Next | Contents | Index |