ChorusOS 5.0 Application Developer's Guide

Chapter 13 Exceptions

This chapter demonstrates the use of the ChorusOS native application programming interfaces for handling thread exceptions, aborts, faults, traps, timeouts, and so forth. The APIs covered here include those related to each type of handler.

After implementing the examples provided in this chapter, you will understand how these APIs might be used in an application.

Exception Handlers

The ChorusOS operating system provides three kinds of exceptions:

Traps

Generated voluntarily by the current thread -- traps are used to change the thread privilege level to execute system code.

Software exceptions

Generated involuntarily by the current thread -- usually due to errors such as division by 0.

Panics

Explicitly generated by specific microkernel modules or supervisor actors -- panics correspond to software/hardware faults which are not recoverable at the application level.

The core executive API provides basic services for subsystems to handle these three kinds of exceptions. For this purpose, the core executive exports an interface for subsystems to declare trap, exception, and panic handlers. Exception handlers are declared on a per actor basis, while trap handlers and panic handlers are declared on a site-wide basis.

The core executive API includes a number of exception handler system calls, described in the following table.

Table 13-1 Exception Handler System Calls

System Call 

Purpose 

svExcHandler()

Sets an actor's exception handler (compatible with the ChorusOS 4.x API) 

svActorExcHandlerConnect()

Connects an actor's exception handler 

svActorExcHandlerDisconnect()

Disconnects an actor's exception handler 

svActorExcHandlerGetConnected()

Gets an actor's exception handler 

Abort Handlers

A variety of microkernel system calls can be used to block a current thread when a request cannot be satisfied immediately or has to await a particular event. Thread blocking and wakeup operations are performed by microkernel features through the invocation of a microkernel internal interface.

A thread can be forced to exit the blocked state. Subsystem managers might need to awaken blocked threads prematurely to enable them to perform their function (to process asynchronous signals, for example). When a thread is blocked, it may be ABORTABLE, depending on the blocking primitive invoked and/or the arguments of this invocation.

The threadAbort() primitive forces a thread which is blocked in an ABORTABLE state to be awakened. Generally, a corresponding blocking call returns a specific error code, indicating an abort.

Because the invoker of threadAbort() may not know whether the thread is currently blocked or not, the microkernel will define the behavior of the threadAbort() call if the thread is active.

Therefore, the effect of threadAbort() depends on the state of the thread.

When a thread is in an ABORTED state, it handles the abort if either of the following situations occurs:

After the abort handler has been executed, the abort is considered to have been handled:

Asynchronous execution control operations (threadAbort()) take effect immediately only if the target thread is currently running in internal mode, that is, if its current execution actor matches its home actor. In the case, where the thread has changed its execution actor (through a microkernel call, trap, or other) , the operation is deferred until the execution actor is reset to the home actor, on return from the microkernel call or trap, for example. Deletion of a thread is also considered an asynchronous control operation in this sense. Thus, a thread is immune from deletion (except if it deletes itself) when its execution actor is changed for a trap or other cross-actor invocation. It is deleted only when it returns to its home actor.

Using Abort Handlers

The following examples illustrate the abort handling capabilities of the ChorusOS operating system.

This example enables an application to abort a thread whose identication is given as an argument. The first four parameters correspond to the capability of the thread home actor, and the fifth argument is the local identication of the thread in the home actor.


Example 13-1 Aborting a Specified Thread

#include <utilities.h>
KnCap 	actorCap;
int 	result;

int main(int argc, char *argv[ ])
{
    if (argc != 6) {
        fprintf(stderr, "bad call\n");
        exit(1);
        }
    readCap(argv+1, &actorCap);
    result = threadAbort(&actorCap, atoi(argv[5]));
    if (result < 0)
        fprintf(stderr, "error on threadAbort: %d\n", strSysError(result));
}


In the following example, a thread requests an abort of itself before it enters a loop and commits to an infinite abortable delay.


Example 13-2 Using the Auto-Abort Feature

#include <chorus.h>
int main( )
{
		int i, result;
		threadAbort(K_MYACTOR, K_MYSELF);
		printf("Before looping\n");
		for (i = 0; i < 50000000; i++);
		printf("After looping\n");
		result = threadDelay(K_NOTIMEOUT);
		if(result == K_EABORT)
			printf("threadDelay aborted\n")
		else
			printf("result = %d\n", result);
}

The output of this example is:


neon abortableDelay_u
started aid = 23
Before looping
After looping
threadDelay aborted

In the previous example the abort request immediately awakens the thread when the abort request calls the threadDelay() primitive. It has no effect on the previously executed loop.


The following example modifies the code used in the previous example to produce a non-abortable application (notAbortDel). The code has been modified as follows:

The notAbortDel application is then executed using the following:


neon-n notAbortDel_u &
[1]   16123
started aid = 23
Before looping
After looping


Example 13-3 Using a Non-abortable Call

In the previous example, a request for the thread to abort is made using the threadAbort() application created in Example 13-1. To verify that the request has no effect and that the thread or actor must be killed:


$ rsh neon arun cs -la 23
started aid = 22
ChorusOS r5.0.0 Site 0 Time 1d 19h 14m 22
ACTOR-UI	   KEY	    LID	          TYPE STATUS   TH#  NAME
200000d0 869da80a  00000017 00000000 0023 USER STARTED  001  notAbortDel_u
THREAD-LI   PRIORITY   TT	IT	  CTX	  SC-MS-PN
0007        140        00000430	00000430  ff6380  0- 1- 0 main
	............................
$ neon threadAbort_u 200000d0 869da80a 17 0 7
started aid = 22
$ rsh neon aps grep notAbort
0 23 notAbortDel_u 0 N/A
$ rsh neon akill 23



Example 13-4 Testing the Aborted State

In the following example, an application called abortedState is created as follows:.

#include <chorus.h>

int main()
{
		int i, result;
		threadAbort(K_MYACTOR, K_MYSELF);
		printf("Before looping \n");
		for (i=0; i<100000; i++);
		printf("After looping\n");
		threadAbort(K_MYACTOR, K_MYSELF);
		result = threadAborted( );
		if (result == 1)
			printf("Aborted state\n");
		else
			printf("Non aborted\n");
		result = threadAborted( );
		if (result == 1)
			printf("Aborted state\n");
		else
			printf("Non aborted\n");
}			

The output of this example is:


$ neon abortedState_u
started aid = 23
Before looping
After looping
Aborted state
Non aborted

Note that abort requests are not accumulated. An abort request for a thread that is already in the aborted state will be ignored.


Trap Handlers

A specific handler is associated with a given trap. It receives as an argument, the context of the calling thread when the trap occurred. Such a trap handler is defined system-wide, that is, all actors will invoke the same handler after being defined. The handler has access to the information required to identify the system call and to retrieve the arguments.

Only one handler may be attached to a given trap. After the handler is installed, it is automatically invoked. The ChorusOS operating system provides an interface that is based on the LAP mechanism for connecting and disconnecting threads. This interface can be used by supervisor threads only and enables a specific trap handler to be connected to different trap numbers.

When a trap handler is called, its argument is a pointer to a KnSysTrapDesc object, which has the following fields:

KnThreadCtx *threadContext

The thread's context that is saved when the trap occurs. The values of the processor's registers can be accessed by the trap handler. The trap handler can also modify the register values before returning.

unsigned int trapNumber

The number of the trap that was invoked.

The core executive API includes the following trap handler system calls:

Table 13-2 Trap Handler System Calls

System Call 

Purpose 

svSysTrapHandlerConnect()

Connects a trap handler 

svSysTrapHandlerDisconnect()

Disconnects a trap handler 

svSysTrapHandlerGetConnected()

Gets a trap handler 

svTrapConnect()

Connects a trap handler 

svTrapDisconnect()

Disconnects a trap handler 


Note -

svTrapConnect() and svTrapDisconnect() are implemented in the library and are provided for backward compatibility only. The new system calls svSysTrapHandlerConnect() and svSysTrapHandlerDisconnect() use a LAP handler for enhanced security.


Using Trap Handlers

The following three examples illustrate how to connect, disconnect, and get trap handlers in the ChorusOS operating system.


Example 13-5 Connecting a Trap Handler

A trap handler specified as a LAP handler can be connected to a given trap number by calling the primitive:

#include <exec/chTrap.h>
int svSysTrapHandlerConnect(
			unsigned int trapNumber,
			KnLapDesc *trapLapDesc
);						

This call returns K_OK if it is successful and returns a negative value if unsuccessful.

Value 

Error 

K_EBUSY

trapNumber is already connected

K_EINVAL

trapNumber is invalid



Example 13-6 Disconnecting a Trap Handler

A trap handler previously connected to a trap number with a call to svSysTrapHandlerConnect() can be disconnected by calling the primitive:

#include <exec/chTrap.h>
int svSysTrapHandlerDisconnect(
			unsigned int trapNumber,
			KnLapDesc *currentTrapLapDesc
);						

The value of currentTrapLapDesc can be K_CONNECTED_LAP. If this is not the case, the value must point to a LAP descriptor that is identical to the LAP desciptor currently connected to the trap number.

The function will K_OK if successful or a negative value if an error occurs.

Value 

Error 

K_EINVAL

currentTrapLapDesc is not K_CONNECTED_LAP and does not match the LAP descriptor of the current trap handler.



Example 13-7 Getting a Trap Handler

A copy of the LAP descriptor corresponding to the trap handler that is currently connected to the trap number can be obtained by calling the primitive:

#include <exec/chTrap.h>
int svSysTrapHandlerGetConnected(
			unsigned int trapNumber,
			KnLapDesc *currentTrapLapDesc
);						

The function returns K_OK on success and K_EINVAL if an error occurs.