c_excpt.h - Header file defining structured exception handling
keywords, intrinsics, and structures for the C language
compiler
#include <excpt.h> /* includes c_excpt.h */
The c_excpt.h header file defines the keywords, intrinsic
functions, and structures the C language compiler uses to
set up a structured exception handler or termination handler.
Structured Exception Handling [Toc] [Back]
The syntax for a structured exception handler is as follows:
try {
try-body
}
except (exception-filter) {
exception-handler
}
The try-body is the code, expressed as a compound statement,
that the exception handler protects. The try body
can be a block of statements or a set of nested blocks.
If an exception occurs while the try body is executing,
exception handling code evaluates the exception-filter to
determine whether to transfer control to the try body's
exception-handler, continue the search for a handler in
some outer-level try body, or continue normal execution.
A program can explicitly initiate an application-specific
exception by calling exc_raise_exception or exc_raise_status_exception.
These functions allow the calling procedure
to specify information that describes the exception.
A program can also install a special signal handler,
exc_raise_signal_exception, that converts a signal to an
exception, invoking the exception dispatcher to search for
any frame-based exception handlers that have been established.
In this case, the code reported to the handler
has EXC_SIGNAL in its facility field and the signal value
in its code field. See the Calling Standard for Alpha
Systems and the exception_intro(3) and its associated reference
pages for instructions on how to use exception management
routines.
The exception-filter is an expression associated with the
exception handler that guards a given try body. It can be
a simple expression or can invoke a function that evaluates
the exception. An exception filter must evaluate to
one of the following integral values: < 0 (EXCEPTION_CONTINUE_EXECUTION)
The exception dispatcher dismisses the exception and
resumes the thread of execution that was originally disrupted
by the exception. If the exception is noncontinuable,
the dispatcher raises a STATUS_NONCONTINUABLE_EXCEPTION
exception. 0 (EXCEPTION_CONTINUE_SEARCH)
The exception dispatcher continues to search for a
handler, first in any try...except blocks in which the
current one might be nested, and then in the try..except
blocks defined in the procedure frame preceding the current
frame on the runtime stack. If a filter chooses not
to handle an exception, it typically returns this value.
> 0 (EXCEPTION_EXECUTE_HANDLER)
The exception dispatcher transfers control to the exception
handler, and execution continues in the frame on the
runtime stack in which the handler is found. This process,
known as handling the exception, unwinds all procedure
frames below the current frame and causes any termination
handlers established within those frames to execute.
Note that you can use a comma to make assignments within
the filter expression. For instance:
except((e=exception_code()) == EXC_VALUE(EXC_SIGNAL,
SIGILL) ? 1 :
(printf("unexpected signal exception code 0x%lx0,
e),0))
{
/* exception handler */
} Two intrinsic functions are allowed within the
exception filter to access information about the exception
being filtered:
long exception_code();
Exception_info_ptr exception_info();
exception_code returns the exception code. The excpt.h
include file defines the exception code formats supported
by the operating system. It also provides symbolic constants
for the facility component of Tru64 UNIX-format
codes, definitions of system internal exception codes, and
a macro, EXC_VALUE, that allows the definition of application-specific
exception codes. See excpt(4) and the Calling
Standard for Alpha Systems for additional discussion
of exception codes.
exception_info returns a pointer to an EXCEPTION_POINTERS
structure. Using this pointer, you can access the machine
state at the time of the exception. The exception information
structure is defined as follows:
typedef struct _EXCEPTION_POINTERS {
system_exrec_type* ExceptionRecord;
PCONTEXT ContextRecord;
EXCEPTION_DISPOSITION Disposition;
DISPATCHER_CONTEXT *DispatcherContext;
} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS, *Exception_info_ptr;
An exception record, as defined in the
excpt.h include file, describes an exception. In addition
to an exception code, an exception record contains flags
that identify the circumstances under which a handler is
called (for instance, whether an unwind operation is in
progress or whether the exception is continuable). excpt.h
defines macros that allow a handler to test the value of
these flags.
A context record, also defined in excpt.h, provides information
about the establisher of an exception handler (such
as the PC where control left the establisher). This
information allows the exception dispatcher to properly
dispatch the exception. An exception disposition is a
value returned by an exception handler to indicate to the
exception dispatcher whether it should dismiss an exception,
continue the search for an exception handler, or
perform some special action. Both the context record and
exception disposition are discussed in greater detail in
excpt(4) and the Calling Standard for Alpha Systems. The
calling standard also discusses the circumstances under
which a handler can modify exception records and context
records.
The exception_code intrinsic function can be used within
an exception filter and exception handler. The exception_info
function can only be used within an exception
filter. However, the filter can store the information
returned by the function and make it subsequently available
to the exception handler. If you need to refer to
exception structures outside of the filter, you must copy
them as well since their storage is valid only during the
execution of the filter.
When an exception occurs, the exception dispatcher virtually
unwinds the runtime stack until it reaches a frame
for which a handler has been established. The dispatcher
initially searches for an exception handler in the stack
frame that was current when the exception occurred. If
the handler is not in this stack frame, the dispatcher
virtually unwinds the stack (in its own context), leaving
the current stack frame and any intervening stack frames
intact until it reaches a frame that has established an
exception handler. It then executes the exception filter
associated with that handler. Note that, during this
phase of exception dispatching, the dispatcher has only
virtually unwound the runtime stack; all call frames that
may have existed on the stack at the time of the exception
are still there. If it cannot find an exception handler,
or if all handlers reraise the exception, the exception
dispatcher invokes the system last-chance handler.
By treating the exception filter as if it were a Pascalstyle
nested procedure, exception handling code evaluates
the filter expression within the scope of the procedure
that includes the try...except construct. This allows the
filter expression to access the local variables of that
procedure, even though the exception may have occurred in
a different procedure.
Prior to executing an exception handler (for instance, if
an exception filter returns EXCEPTION_EXECUTE_HANDLER),
the exception dispatcher performs a real unwind of the
runtime stack, executing any termination handlers established
for try...finally blocks that terminated as a
result of the transfer of control to the exception handler.
Only then does the dispatcher calls the exception
handler.
The exception-handler is a compound statement that deals
with the exception condition. It executes within the scope
of the procedure that includes the try...except construct
and can access its local variables. A handler can respond
to an exception in several different ways, depending on
the nature of the exception. For instance, it can log an
error or correct the circumstances the led to the exception
being raised.
Either an exception filter or exception handler can take
steps to modify or augment the exception information it
has obtained and ask the C-language exception dispatcher
to deliver the new information to exception code established
in some outer try body or prior call frame. This
activity is more straightforward from within the exception
filter, which operates with the frames of the latest executing
procedures -- and the exception context -- still
intact on the runtime stack. The filter simply completes
its processing by returning a 0 to the dispatcher to
request the dispatcher to continue its search for the next
handler. For an exception handler to trigger a previously-established
handler, it must raise another exception,
from its own context, that the previously-established
handler is equipped to handle.
A procedure (or group of interrelated procedures) can contain
any number of try...except constructs, and can nest
these constructs. If an exception occurs within the
try...except block, the system invokes the exception handler
associated with that block.
Termination Handling [Toc] [Back]
The Tru64 UNIX C language compiler allows you to ensure
that whenever control is passed from a guarded body of
code, a specified block of termination code is also executed.
The termination code is executed regardless of how
the flow of control leaves the guarded code. For example,
a termination handler can guarantee that clean-up tasks
are performed even if an exception or some other error
occurs while the guarded body of code is executing.
The syntax for a termination handler is as follows:
try {
try-body
}
finally {
termination-handler
}
The try-body is the code, expressed as a compound statement,
that the termination handler protects. The try body
can be a block of statements or a set of nested blocks. It
can include the following statement, which causes an immediate
exit from the block and execution of its termination
handler:
leave;
The termination-handler is a compound statement that executes
when the flow of control leaves the guarded try
body, regardless of whether the try body terminated normally
or abnormally. The guarded body is considered to
have terminated normally when the last statement in the
block is executed (that is, when the body's closing "}" is
reached). Use of the leave statement also causes a normal
termination. The guarded body terminates abnormally when
the flow of control leaves it by any other means: for
example, due to an exception, or due to a control statement
such as return, goto, break or continue.
A termination handler can call the following intrinsic
function to determine whether the guarded body terminated
normally or abnormally.
int abnormal_termination();
The abnormal_termination function returns 0 if the try
body completed sequentially; otherwise, it returns 1.
The termination handler itself may terminate sequentially
or by a jump out of the handler. If it terminates sequentially
(by reaching the closing "}"), subsequent control
flow depends on how the try body terminated, as follows:
If the try body terminated normally, execution continues
with the statement following the complete try...finally
block. If the try body terminated abnormally with an
explicit jump out of the body, the jump is completed.
However, if the jump exits the body of one or more containing
try...finally statements, their termination handlers
are invoked before control is finally transferred to
the target of the jump. If the try body terminated abnormally
due to an unwind, a jump to an exception handler, or
by an exc_longjmp, control is returned to the runtime,
which will continue invoking termination handlers as
required before jumping to the target of the unwind.
Like exception filters, termination handlers are treated
as Pascal-style nested procedures, and are executed without
the removal of frames from the runtime stack. A termination
handler can thus access the local variables of the
procedure in which it is declared.
Note that there is a performance cost in the servicing of
abnormal terminations, inasmuch as abnormal terminations
(and exceptions) are considered to be outside the normal
flow of control for most programs. Keep in mind that
explicit jumps out of a try body are considered abnormal
termination. Normal termination is the simple case and
costs less at runtime. In some instances, you can avoid
this cost by replacing a jump out of a try body with a
leave statement (which transfers control to the end of the
innermost try body) and testing a status variable after
completion of the entire try...finally block.
A termination handler itself may terminate nonsequentially
(for instance, to abort an unwind) by means of a transfer
of control (for instance, a goto, break, continue, return,
exc_longjmp, or the occurrence of an exception). If this
transfer of control exits another try...finally block, its
termination handler will execute.
The try body, exception handler, and termination handler
are compound statements and thus must each be enclosed in
braces ({}).
You must not jump into a try body, exception handler, or
termination handler when control is outside the body or
handler.
You cannot define a procedure or function within a
try...except or try...finally block, although the sole
contents of the block might be a procedure or function.
If an exception handler within a try...except block contains
another try...except block, and the exception_code()
function is invoked within the exception filter or exception
handler for the latter block, it returns the most
recent exception code. If the original handler later
invokes the intrinsic, its effects are undefined.
The compiler will disable a number of optimizations in
order to ensure the integrity of try...except and
try...finally blocks.
Defines data structures supporting the exception handling
system. excpt.h includes c_excpt.h.
Functions: exception_intro(3), exception_dispatcher(3),
unwind(3), exc_resume(3), signal(2), sigaction(2).
Files: excpt(4), signal(4).
Calling Standard for Alpha Systems
delim off
c_excpt(4)
[ Back ] |