EXC_HANDLE(3L)

NAME
exc_handle, exc_unhandle, exc_bound, exc_notify, exc_raise, exc_on_exit, exc_uniqpatt - LWP exception handling

SYNOPSIS
#include <lwp/lwp.h>

int exc_handle(pattern, func, arg)
int pattern;
caddr_t (*func)();
caddr_t arg;

int exc_raise(pattern)
int pattern;

int exc_unhandle()

caddr_t (*exc_bound(pattern, arg))()
int pattern;
caddr_t *arg;

int exc_notify(pattern)
int pattern;

int exc_on_exit(func, arg)
void (*func)();
caddr_t arg;

int exc_uniqpatt()

DESCRIPTION

These primitives can be used to manage exceptional conditions in a thread. Basically, raising an exception is a more general form of non-local goto or longjmp, but the invocation is pattern-based. It is also possible to notify an exception handler whereby a function supplied by the exception handler is invoked and control is returned to the raiser of the exception. Finally, one can establish a handler which is always invoked upon procedure exit, regardless of whether the procedure exits using a return or an exception raised to a handler established prior to the invocation of the exiting procedure.

exc_handle() is used to establish an exception handler. exc_handle() returns 0 to indicate that a handler has been established. A return of -1 indicates an error in trying to establish the exception handler. If it returns something else, an exception has occurred and any procedure calls deeper than the one containing the handler have disappeared. All exception handlers established by a procedure are automatically discarded when the procedure terminates.

exc_handle() binds a pattern to the handler, where a pattern is an integer, and two patterns match if their values are equal. When an exception is raised with exc_raise(), the most recent handler that has established a matching pattern will catch the exception. A special pattern (CATCHALL) is provided which matches any exc_raise() pattern. This is useful for handlers which know that there is no chance the resources allocated in a routine can be reclaimed by previous routines in the call chain.

The other two arguments to exc_handle() are a function and an argument to that function. exc_bound() retrieves these arguments from an exc_handle() call made by the specified thread. By using exc_bound() to retrieve and call a function bound by the exception handler, a procedure can raise a notification exception which allows control to return to the raiser of the exception after the exception is handled.

exc_raise() allows the caller to transfer control (do a non-local goto) to the matching exc_handle(). This matching exception handler is destroyed after the control transfer. At this time, it behaves as if exc_handle() returns with the pattern from exc_raise() as the return value. Note: func of exc_handle() is not called using exc_raise() — it is only there for notification exceptions. Because the exception handler returns the pattern that invoked it, it is possible for a handler that matches the CATCHALL pattern to reraise the exact exception it caught by using exc_raise() on the caught pattern. It is illegal to handle or raise the pattern 0 or the pattern -1. Handlers are searched for pattern matches in the reverse execution order that they are set (i.e., the most recently established handler is searched first).

exc_unhandle() destroys the most recently established exception handler set by the current thread. It is an error to destroy an exit-handler set up by exc_on_exit(). When a procedure exits, all handlers and exit handlers set in the procedure are automatically deallocated.

exc_notify() is a convenient way to use exc_bound. The function which is bound to pattern is retrieved. If the function is not NULL, the function is called with the associated argument and the result is returned. If the function is NULL, exc_raise(pattern) is returned.

exc_on_exit() specifies an exit procedure and argument to be passed to the exit procedure, which is called when the procedure which sets an exit handler using exc_on_exit() exits. The exit procedures (more than one may be set) will be called regardless if the setting procedure is exited using a return or an exc_raise(). Because the exit procedure is called as if the handling procedure had returned, the argument passed to it should not contain addresses on the handler's stack. However, any value returned by the procedure which established the exit procedure is preserved no matter what the exit procedure returns. This primitive is used in the MONITOR macro to enforce the monitor discipline on procedures.

Some signals can be considered to be synchronous traps. They are usually the starred (*) signals in the signal(3V) man pages. These are: SIGSYS, SIGBUS, SIGEMT, SIGFPE, SIGILL, SIGTRAP, SIGSEGV. If an event is marked as a trap using agt_trap() (see agt_create(3L)) the event will generate exceptions instead of agent messages. This mapping is per-pod, not per-thread. A thread which handles the signal number of one of these as the pattern for exc_handle() will catch such a signal as an exception. The exception will be raised as an exc_notify() so either escape or notification style exceptions can be used, depending on what the matching exc_handle() provides. If the exception is not handled, the thread will terminate. Note: it can be dangerous to supply an exception handler to treat stack overflow since the client's stack is used in raising the exception.

exc_uniqpatt() returns an exception pattern that is not any of the pre-defined patterns (any of the synchronous exceptions or -1 or CATCHALL). Each call to exc_uniqpatt() results in a different pattern. If exc_uniqpatt() cannot guarantee uniqueness, -1 is returned instead the first time this happens. Subsequent calls after this error result in patterns which may be duplicates.

RETURN VALUES

exc_uniqpatt() returns a unique pattern on success. The first time it fails, exc_uniqpatt() returns -1.

exc_handle() returns:

0   on success.

-1  on failure. When exc_handle() returns because of a matching call to exc_raise(), it returns the pattern raised by exc_raise().

On success, exc_raise() transfers control to the matching exc_handle() and does not return. On failure, it returns -1.

exc_unhandle() returns:

0   on success.

-1  on failure.

exc_bound() returns a pointer to a function on success. On failure, it returns NULL.

On success, exc_notify() returns the return value of a function, or transfers control to a matching exc_handle() and does not return. On failure, it returns -1.

exc_on_exit() returns 0.

ERRORS

exc_unhandle() will fail if one or more of the following is true:

LE_NONEXIST
    Attempt to remove a non-existent handler.

    Attempt to remove an exit handler.

exc_raise() will fail if one or more of the following is true:

LE_INVALIDARG
    Attempt to raise an illegal pattern (-1 or 0).

LE_NONEXIST
    No context found to raise an exception to.

exc_handle() will fail if one or more of the following is true:

LE_INVALIDARG
    Attempt to handle an illegal pattern (-1 or 0).

exc_uniqpatt() will fail if one or more of the following is true:

LE_REUSE
    Possible reuse of existing object. agt_create(3L), signal(3V)

BUGS

The stack may not contain useful information after an exception has been caught so post-exception debugging can be difficult. The reason for this is that a given handler may call procedures that trash the stack before reraising an exception.

The distinction between traps and interrupts can be problematical.

The environment restored on exc_raise() consists of the registers at the time of the exc_handle(). As a result, modifications to register variables between the times of exc_handle() and exc_raise() will not be seen. This problem does not occur in the sun4 implementation.

WARNINGS

exc_on_exit() passes a simple type as an argument to the exit routine. If you need to pass a complex type, such as thread_t, mon_t, or cv_t, pass a pointer to the object instead.