[Return to Bookshelf] [Contents] [Previous Section] [Next Section] [Index] [Help]


5.3 C Language Syntax

The following example shows the syntax for handling exceptions:

TRY
    try_block
[CATCH (exception_name)
    handler_block]...
[CATCH_ALL
    handler_block]
ENDTRY

A try_block or a handler_block is a sequence of statements, the first of which may be declarations, as in a normal block. If an exception is raised in the try_block, the catch clauses are evaluated to see if any one matches the current exception.

The CATCH or CATCH_ALL clauses absorb an exception-they can catch an exception propagating out of the try_block and direct execution into the associated handler_block. Propagation of the exception, by default, then ends. Within the lexical scope of a handler, it is possible to cause propagation of the same exception to resume (this is called reraising the exception), or it is possible to raise some new exception.

The RERAISE statement is allowed in any handler statements and causes the current exception to be reraised. Propagation of the caught exception resumes.

The RAISE (exception_name) statement is allowed anywhere and causes a particular exception to start propagating. For example:

TRY
    sort(); /* Call a function that may raise an exception.
             * An exception propagates by transferring control
             * out of some nested routine back to the TRY
             * clause.  Any output parameters or return values
             * of the called routine are therefore indeterminate.
             */

CATCH (pthread_cancel_e)
    printf("Canceled while sorting\n");
    RERAISE;

CATCH_ALL
    printf("Some other exception while sorting\n");
    RERAISE;

ENDTRY

In the previous example, if the pthread_cancel_e exception propagates out of the function call, the first printf is executed. If any other exception propagates out of sort, the second printf is executed. In either situation, propagation of the exception resumes because of the RERAISE statement. (If the code is unable to fully recover from the error, or does not understand the error, it needs to further propagate the error to its callers, as in the previous example.)

The following example shows the syntax for an epilogue:

TRY
    try_block
FINALLY
    final_block
ENDTRY

The final_block is executed regardless of whether the try_block executes to completion without raising an exception or if an exception is raised in the try_block. If an exception is raised in the try_block, propagation of the exception is resumed after executing the final_block.

Note that a CATCH_ALL handler and RERAISE could be used to do this, but the epilogue code would then have to be duplicated in two places, as follows:

TRY
    try_block
CATCH_ALL
    final_block
    RERAISE;
ENDTRY
{ final_block }

A FINALLY statement has exactly this meaning but avoids code duplication.


Note
The behavior of FINALLY along with CATCH or CATCH_ALL clauses is unpredictable. Do not combine them for the same try_block.

Another example of the FINALLY statement is as follows:

pthread_mutex_lock (some_object.mutex);
some_object.num_waiters = some_object.num_waiters + 1;
TRY
    while (! some_object.data_available)
        pthread_cond_wait (some_object.condition);
    /* The code to act on the data_available goes here */
FINALLY
    some_object.num_waiters = some_object.num_waiters - 1;
    pthread_mutex_unlock (some_object.mutex);
ENDTRY

In the previous example, the call to pthread_cond_wait could raise the pthread_cancel_e exception if the thread was canceled while it was waiting. The final_block ensures that the shared data associated with the lock is correct for the next thread that acquires the mutex.



[Return to Bookshelf] [Contents] [Previous Section] [Next Section] [Index] [Help]