-
Notifications
You must be signed in to change notification settings - Fork 2
handler
Run-time exceptions in HS result from parsing and execution errors, timeouts, alarms, interrupts, and messages. HS provides a set of handler statements that can be used to catch these exceptions and deal with the problem or condition that occurred. While some exceptions are caused by errors, many result from conditions that arise during normal program execution. For example, when an message is received it might need to be handled immediately.
The HS variable, STATUS, is set whenever an exception occurs. The value of STATUS indicates what condition triggered the exception. A handler method is any statement, or statement block, that follows the handler statement; it implicitly returns the value of STATUS. A handler method can examine the value of STATUS, and can alter the value of STATUS to control what happens after the handler completes.
The following table lists the condition values that STATUS can have, the type of exception that caused the condition, and the handler statement used to catch the exception. STATUS Condition Handler
$ACKNOWLEDGE Success N/A
%TIMEOUT Timed out while blocking on query on_timeout
%ALARM Alarm has been triggered on_alarm
%DEATH Lifetime has expired on_death
%MESSAGE Message has been received on_message
%INTERRUPT An interrupt signal has occurred on_interrupt
%PIPE Connection (socket) error on_pipe
%PARSE Parse error on_error
%EXPRESSION Error in evaluating an expression on_error
%BRANCH Undefined label on_error
%IDENTIFIER Undefined identifier on_error
%ARGUMENT Invalid argument on_error
%METHOD Undefined method on_error
%BOUNDS Array bounds error, or divide-by-zero on_error
%FILE File open error on_error
%IO File I/O error on_error
%EOF End-of-file condition on_error
%TARGET Message target not found on_error
%UNDEFINED Undefined variable on_error
%UNSUPPORTED Unsupported message type on_error
%REJECTED Message rejected by target on_error
%SQL Error in SQL method on_error
%SECS Error in SECS message on_error
Note that the error condition codes all start with the character "%". These will, by convention, all test false. For example:
STATUS = "%TIMEOUT";
if ( !STATUS ) {
put ( "Timeout condition occurred" );
exit();
}
_
When an exception occurs, HS will be in one of four states:
- IDLE - Waiting to receive messages after calling idle
- QUERY - Waiting for a reply from query (sent message)
- PARSE - Parsing a program statement
- EXECUTE - Executing a method
The actions taken by the handler sometimes depend on the state (see specific handler statements below). The handler can change the state to control what happens after the handler completes.
The on_error statement has the form:
on_error statement ;
_
When an unrecoverable error occurs, control is transferred unconditionally to the statement following on_error. This statement is typically a handler method. When the statement completes, control returns back to the statement following the point where the error occurred.
Once an error handler is used, it must be reestablished with the on_error statement to use it again. Typically, the on_error statement is called in the handler before returning.
on_error HANDLE_ERROR();
/* .
.
. */
HANDLE_ERROR() {
/* Handle an error
.
.
. */
/* Reestablish handler before returning. */
on_error HANDLE_ERROR();
return;
}
_
The on_timeout statement has the form:
on_timeout statement;
_
A timeout condition can only occur when blocking on the query function. When a timeout condition occurs, control is transferred unconditionally to the statement following on_timeout. This statement is typically a handler method.
Once a timeout handler is used, it must be reestablished with the on_timeout statement to use it again. Typically, the on_timeout statement is called in the handler before returning.
When a timeout condition occurs, the value of STATUS becomes "%TIMEOUT". If the handler changes the value of STATUS to a success value such as "$ACKNOWLEDGE", then upon returning from the handler query will continue waiting for the reply message, using the previously specified timeout. If the STATUS value remains as "%TIMEOUT", or is changed to any other non-success value, query will fail and return the value of STATUS.
The timeout value is set using the timeout function. For example:
timeout ( 20 ); /* Set query timeout to 20 seconds */
on_timeout HANDLE_TIMEOUT ();
query ( "target", "method" ); /* Execute method on the target */
if ( STATUS == "%TIMEOUT" ) {
/* query timed out
.
.
. */
}
HANDLE_TIMEOUT() {
/* Handle the query timeout condition
.
.
. */
/* Reestablish handler before returning. */
on_timeout HANDLE_TIMEOUT ();
/* .
.
. */
/* Maybe let query continue waiting for reply */
if ( retryQuery ) STATUS = "$ACKNOWLEDGE";
return;
}
_
The on_alarm statement has the form:
on_alarm statement ;
_
When an alarm condition occurs, control is transferred unconditionally to the statement following on_alarm. This statement is typically a handler method. When the statement completes, control returns back to the statement following the point where the alarm occurred. An alarm is set using the alarm function.
Once an alarm handler is used, it must be reestablished with the on_alarm statement to use it again. Typically, the on_alarm statement is called in the handler before returning.
When an alarm condition occurs, the value of STATUS becomes "%ALARM". If the HS program was in the IDLE state when the alarm occurred, a return from the alarm handler continues in the IDLE state. If the HS program was in the EXECUTE state, control returns to the point where the alarm occurred, with no net effect. If the HS program was in the QUERY state, control returns to the query function. The query function either fails and returns the value of STATUS (i.e. "%ALARM"), or continues to wait for a reply message if STATUS was changed to a success value such as "$ACKNOWLEDGE".
The on_interrupt statement has the form:
on_interrupt statement ;
_
When an interrupt condition occurs, for example, a ^C signal, control is transferred unconditionally to the statement following on_interrupt. This statement is typically a handler method.
Once an interrupt handler is used, it must be reestablished with the on_interrupt statement to use it again. Typically, the on_interrupt statement is called in the handler before returning.
When the handler statement completes, control returns to the statement following the point where the interrupt occurred. If the HS program was in the IDLE state, control returns to the IDLE state. If the HS program was in the EXECUTE state, control returns to the point that was interrupted, with no net effect. If the HS program was in the QUERY state, control returns to the query function. The query function either fails and returns the value of STATUS (i.e.: "%INTERRUPT"), or continues to wait for a reply message if STATUS was changed to a success value such as "$ACKNOWLEDGE".
The on_pipe statement has the form:
on_pipe statement ;
_
When a socket (pipe) error occurs...
The on_death statement has the form:
on_death statement ;
_
A death condition occurs when the program's lifetime expires (specified by the lifetime function). Control is transferred unconditionally to the statement following on_death. This statement is typically a handler method.
Once a death handler is used, it must be reestablished with the on_death statement to use it again. Typically, the on_death statement is called in the handler before returning.
When the handler statement completes the instance will exit. To prevent death, the handler must reinstate a new lifetime interval using the lifetime function before returning. If the HS program was in the IDLE state, control returns to the IDLE state. If the HS program was in the EXECUTE state, control returns to the point that was interrupted by the death condition, with no net effect.
If the HS program was in the QUERY state, then control returns to the query function. The query function either fails and returns the value of STATUS (i.e.: "%DEATH") or continues to wait for a reply message if STATUS was changed to a success value such as "$ACKNOWLEDGE".
The on_message statement has the form:
on_message statement ;
_
When an incoming message specifies a defined and enabled method in the HS program, control is transferred unconditionally to the statement following on_message. This statement is typically a handler method.
Once a message handler is used, it must be reestablished with the on_message statement to use it again. Typically, the on_message statement is called in the handler before returning.
The HS program must return to the IDLE state to execute the message. If the HS program was already in the IDLE state, the handler can simply return. To prevent the message from executing, the method can be disabled using the disable statement before returning to the IDLE state.
When a message interrupts a HS program in the QUERY state, the handler can do one of three things:
- It can return to the query function, which will fail with a return value of "%TIMEOUT".
- It can ignore the incoming message by changing the value of STATUS from "%MESSAGE" to "$ACKNOWLEDGE" and returning. The query function will continue to wait for a reply. If another message arrives it overrides the previous one and another message exception occurs.
- It can execute the idle function, which will abort the query function and put the HS program into the IDLE state, where it will execute the incoming message.
- It can examine the method, mode, and sender of the incoming message using the method, mode, and sender functions. This is useful when more than one method is enabled for incoming messages; the handler can look at the message before responding.
The following example illustrates a typical message handling situation:
enable ABORT; /* Enable a method to handle ABORT */
enable DISCONNECT; /* Enable a method to handle DISCONNECT */
enable SETUP; /* Enable a method to handle SETUP */
on_message HANDLE_MESSAGE();
query ( "target", "method" ); /* Execute method on the target */
if ( STATUS == "%MESSAGE" ) ABORT();
/* Successful query
.
.
. */
HANDLE_MESSAGE()
{
/* Handle an incoming message condition. */
if ( method() == "DISCONNECT" || method() == "ABORT" )
/* Execute these methods immediately */
idle();
else if ( method() == "SETUP" )
/* Not accepting SETUP right now, resume the query */
STATUS = "$ACKNOWLEDGE";
else {
/* Some other method requested. Let the query fail */
put ( "Received unexpected method " + method() );
return;
}
_
Note:
An incoming message will not interrupt a HS program in the EXECUTE state. The HS program must be in the IDLE or QUERY state before the interrupting method is actually received.