In the traditional networking stacks, asynchronous notification is accomplished by using signal driven I/O. Upon arrival of a message, the OS can deliver a previously defined signal to designated process. In the AM implementation, this process will register an active message dispatch handler. This handler will first check whether data is waiting to be read, since anyone could have delivered the signal. Next, it will look up the address of the corresponding request handler, using the address identifier as an offset into the array of request handler addresses. If the tag is not bound to a request handler function, a ``sink'' function should be executed that simply removes the packet from the network. If the tag is bound, the dispatcher invokes the request handler with any arguments optionally packed into the message and a pointer to the message itself. The user's handler is then allowed to run to completion, optionally sending a reply AM to the originator.
It is conceivable
that the user would wish to have option of declaring critical
sections. This is especially important to consider when the user's
process is performing system calls, most of which can be interrupted
by a signal. Guarding against this situation usually requires watching
for a special return code. If this code is returned, the call must be
invoked until a different code returned. Systems conforming to the 4.2
BSD release of Unix do this automatically. However, given the wide
variety of platforms we wish to support, this cannot be relied
upon. If the user does choose to make system calls while communication
is taking place, those calls must not reference any buffer whose
contents are suspect. Aside from the nuisance to the user,
repeated system calls can cause unnecessary process suspension and
context switching delays. Two solutions to this problem are
available. The first is a true lockout, where the kernel actually
prevents the signal from being delivered until the user indicates that
it is ok to do so. The second solution, recommended for debugging and
I/O-intensive applications, is to do away with asynchronous
notification completely and poll for all messages. Currently, all
active messaging implementations used polled I/O, mainly because
the polling function also performs the check for stale requests.
Where polling is chosen over interrupts, the request and reply calls
should automatically poll the network at the beginning and end of every call. However, the user must be
careful not to ignore the network in computation-only loops.
Hence, an explicit call to poll the interface is provided.
To achieve widespread acceptance, the burden on the user of AMs
must be minimal. Thus, a function could be provided that can
register an alarm handler that performs this polling on a regular interval.
Theoretically, active messages are executed immediately upon arrival. As mentioned before, these messages simply remove the data from the network and integrate it into the ongoing computation. An arbitrary time limit could be imposed on the handlers to prevent deadlock and aid in debugging. However, this should be available only as a compile time switch to the library, since the management of many alarms is quite expensive.