This chapter deals with the concepts of local access points that are native to ChorusOS systems. It also demonstrates the use of the application programming interfaces for handling LAPs.
After implementing the examples provided in this chapter, you should understand how these APIs can be used in an application.
Local Access Points (LAPs) are a low overhead mechanism for calling service routines in supervisor actors on the local site by both user and supervisor actor calls.
A LAP is designated and invoked via its LAP descriptor. A LAP descriptor can be directly transmitted by a server to one or more specific client actors via shared memory or as an argument to another invocation.
For more information, refer to the lapInvoke(2K), lapResolve(2K), svLapBind(2K), svLapCreate(2K) and svLapDelete(2K) man pages.
The LAPBIND feature provides a nameserver from
which a LAP descriptor may be requested and obtained indirectly, using a static
symbolic name. This symbolic name may be an arbitrary character string, whose
size is limited to K_LAPNAMEMAX (currently set
to 7 characters) . Otherwise, svLapBind returns K_ENOMEM. Using the nameserver, a LAP may be exported to any potential
client that knows the symbolic name of the LAP (or of the service exported
by the LAP).
A server may optionally establish a name binding using svLapBind(2K). The binding can be removed using svLapUnbind(2K). A client uses lapResolve(2K) to obtain a LAP descriptor, given its symbolic name, and optionally waiting if the name is not yet available.
If the LAPSAFE feature has been configured
in the system, a LAP frame descriptor is allocated to
register the calling thread as a temporary resource of the invoked actor.
Each LAP frame has an associated level (LAP frame level)
which represents the number of LAP frames for the considered
thread.
LAPSAFE enforces stronger checking during LAP invocation. This ensures that the microkernel will synchronize
the svLapDelete() operation with concurrent lap invocations.
The full context of the calling thread is saved prior to the LAP invocation. This ensures that the calling thread can return from
its invocation even if a failure occurs during the execution of the LAP handler. This option is mandatory if a LAP
is called from user mode.
The svLapCreate() system call creates a new local
access point for the actor designated by the actor capability (KnCap).
The svLapBind() system call binds the LAP descriptor pointed to by lapdesc with the symbolic name pointed to by name.
The svLapDelete() system call deletes the local access point whose descriptor is pointed to by lapdesc.
The following example demonstrates a POSIX application that uses these restricted microkernel calls. To launch the example, type:
rsh <target_name> lap <lapserver>
This example applies to supervisor actors only. It is a POSIX application, running in privileged mode.
(file: progov/lap.c)
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <chorus.h>
#include <spawn.h>
#include <lap/chLap.h>
#include <exec/chExec.h>
KnCap actorCap;
KnLapDesc lapDesc;
char* lapArgument;
KnTimeVal timeval;
void
lapHandler(char* message, char* cookie)
{
int res;
res = actorSelf(&actorCap);
if (res != K_OK) {
printf("actorSelf failed, returns %d\n",res);
exit(1);
}
printf("LAP handler is running \n");
printf(" thread LI = %d, actor UI = 0x%x 0x%x\n",
threadSelf(), actorCap.ui.uiHead, actorCap.ui.uiTail);
printf(" Argument = %s, cookie = %s\n",message, cookie);
}
int main(int argc, char** argv, char** envp)
{
int res;
KnActorPrivilege actorP;
char* cookie = "Chorus";
char* spawn_args[4];
res = actorPrivilege(K_MYACTOR, &actorP, NULL);
if (res != K_OK) {
printf("Cannot get actor privilege, error %d\n", res);
exit(1);
}
if (argc == 1) {
printf("Must be run with one argument: LAP name\n");
exit(1);
}
if (argc == 2) {
/*
* This is the Server process.
* connect a LAP handler,
* bind a symbolic name to the LAP (name given as argv[1])
* spawn a client actor (give LAP symbolic name in argument)
* wait one minute for Lap invocation
*/
/*
* Spawn the client process
*/
if (actorP != K_SUPACTOR) {
printf("This program must be run in supervisor mode\n");
exit(1);
}
spawn_args[0] = argv[0];
spawn_args[1] = argv[1];
spawn_args[2] = "ARGH";
spawn_args[3] = NULL;
res = posix_spawnp(NULL, spawn_args[0], NULL,
NULL, spawn_args, NULL);
if (res < 0) {
printf("Cannot spawn client actor, error %d\n", res);
exit(1);
}
/*
* Create the LAP
*/
res = svLapCreate(K_MYACTOR, (KnLapHdl) lapHandler,
cookie, K_LAP_SETJMP, &lapDesc);
if (res != K_OK) {
printf("svLapCreate failed, returns %d\n",res);
exit(1);
}
/*
* Bind a symbolic name
*/
res = svLapBind(&lapDesc, argv[1], 0);
if (res != K_OK) {
printf("svLapBind failed, returns %d\n",res);
exit(1);
}
/*
* Wait one minute
* Other client processes can be run from the console:
* rsh target lap lap-name lap-argument
*
*/
timeval.tmSec = 60;
timeval.tmNSec = 0;
(void) threadDelay(&timeVal);
/*
* Unbind the LAP name and Delete the LAP
*/
res = svLapUnbind(argv[1]);
if (res != K_OK) {
printf("svLapUnBind failed, returns %d\n",res);
exit(1);
}
res = svLapDelete(&lapDesc);
if (res != K_OK) {
printf("svLapDelete failed, returns %d\n",res);
exit(1);
}
printf("Server actor is leaving ...\n");
} else {
/*
* This is the Client Actor:
* argv[1] is the LAP name, argv[2] is the LAP argument.
* Get the LAP descriptor and invoke the LAP handler.
*/
res = actorSelf(&actorCap);
if (res != K_OK) {
printf("actorSelf failed ! Return code = %d\n",res);
exit(1);
}
printf("Client actor is running, thread li = %d, "
"actor UI = 0x%x 0x%x\n",
threadSelf(), actorCap.ui.uiHead, actorCap.ui.uiTail);
/*
* Get the LAP descriptor knowing its name
*/
res = lapResolve(&lapDesc, argv[1], 0);
if (res != K_OK) {
printf("lapResolve failed, returns %d\n", res);
exit(1);
}
/*
* Invoke the LAP handler
*/
res = lapInvoke(&lapDesc, argv[2]);
if (res != K_OK) {
printf("lapInvoke failed, returns %d\n", res);
exit(1);
}
printf("Client actor is leaving ...\n");
}
return 0;
}
In the previous example, the main thread:
Checks if it is running as a supervisor process.
Spawns another copy of itself using posix_spawn().
Creates a Local Access Point and connects a LAP handler, which prints the unique identifier of the current thread (Actor UI + thread LI), the LAP argument and the LAP cookie.
Binds a symbolic name received as the first argument.
Waits one minute for LAP invocations.
Frees the LAP and its name.
Terminates.
The spawned actor:
Receives two arguments: the symbolic LAP name and the argument to be passed to the LAP handler.
Retrieves the LAP descriptor.
Invokes the LAP handler.
Terminates.