The following example illustrates the use of the IPC mechanisms provided in the ChorusOS operating system.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <chorus.h>
#include <spawn.h>
#include "ipc/chIpc.h"
#define ABORT_DELAY 1000 /* Delay for ipcReceive */
static KnUniqueId thePortUi; /* Our port unique identifier */
static int thePortLi; /* ....... local identifier */
static KnCap groupCap; /* Our group capability */
/* The outgoing annex and body */
static char sndAnnex[] = "Hello world from Chorus ...\n";
static char sndBody[] = "The sea is calm, the tide is full ...\n";
/* The received annex and body */
static char rcvAnnex[K_CMSGANNEXSIZE];
static char rcvBody[1000];
/* Argumentf for the spawnd process */
static char* spawn_args[3];
/* Port group stamp */
char* stamp;
#define MYSTAMP 100
#define STAMPSIZE 10
int main(int argc, char** argv, char** envp)
{
int rslt; /* Work */
KnMsgDesc smsg; /* Descriptor for message being sent */
KnMsgDesc rmsg; /* Descriptor for message being received */
KnIpcDest ipcDest; /* IPC address */
if (argc == 1) {
/*
* Server actor
* Create the destination port
*/
thePortLi = portCreate(K_MYACTOR, &thePortUi);
if (thePortLi < 0) {
printf("portCreate failed, returns %d\n", thePortLi);
exit(1);
}
/*
* Allocate a port group and insert the port into it
*/
rslt = grpAllocate(K_STATUSER, &groupCap, MYSTAMP);
if (rslt < 0) {
printf("grpAllocate failed, returns %d\n", rslt);
exit(1);
}
rslt = grpPortInsert(&groupCap, &thePortUi);
if (rslt < 0) {
printf("grpPortInsert failed, returns %d\n", rslt);
exit(1);
}
/*
* Spawn the client actor
* The group stamp is given in argument
* Exit in case of malloc failure
*/
stamp = malloc(STAMPSIZE);
if (stamp == NULL) {
printf("Can't allocate %d bytes\n", STAMPSIZE);
exit(1);
}
sprintf(stamp, "%d", MYSTAMP);
spawn_args[0] = argv[0];
spawn_args[1] = stamp;
spawn_args[2] = NULL;
rslt = posix_spawnp(NULL, spawn_args[0], NULL,
NULL, spawn_args, NULL);
if (rslt < 0) {
printf("Cannot spawn client actor, error %d\n", rslt);
exit(1);
}
/*
* Receive the message
*/
rmsg.flags = 0;
rmsg.bodySize = sizeof(rcvBody);
rmsg.bodyAddr = (VmAddr)rcvBody;
rmsg.annexAddr = (VmAddr)rcvAnnex;
rslt = ipcReceive(&rmsg, &thePortLi, ABORT_DELAY);
if (rslt < 0) {
printf("ipcReceive failed, returns %d\n", rslt);
exit(1);
}
printf ("%s\n%s\n", rcvAnnex, rcvBody);
rslt = portDelete(K_MYACTOR, thePortLi);
if (rslt < 0) {
printf("portDelete failed, returns %d\n", rslt);
exit(1);
}
} else {
/*
* Get the port group capability giving the stamp.
* Stamp has been received in argv[1]
*/
rslt = grpAllocate(K_STATUSER, &groupCap, (int) atoi(argv[1]));
if (rslt < 0) {
printf("grpAllocate failed, returns %d\n", rslt);
exit(1);
}
/*
* Prepare the message descriptor for the message to send
*/
smsg.flags = 0;
smsg.bodySize = sizeof(sndBody);
smsg.bodyAddr = (VmAddr)sndBody;
smsg.annexAddr = (VmAddr)sndAnnex;
/*
* Prepare the IPC address for the message destination.
* Send the message in broadcast mode.
*/
ipcDest.target = groupCap.ui;
rslt = ipcTarget(&ipcDest.target, K_BROADMODE);
if (rslt < 0) {
printf("ipcTarget failed, returns %d\n", rslt);
exit(1);
}
/* Send from our DEFAULT port */
rslt = ipcSend(&smsg, K_DEFAULTPORT, &ipcDest);
if (rslt < 0) {
printf("ipcSend failed, returns %d\n", rslt);
exit(1);
}
}
return 0;
}
In this example, the main thread (which is implicitly created):
Creates a port
Creates a port group and inserts the port into it
Spawns another copy of itself, using posix_spawn(), and passes the port group stamp as an argument
Waits for a message on the created port
Prints the contents of the body and the annex
Frees all used resources and terminates
The spawned actor:
Retrieves the port group capability, passing the stamp received as an argument
Prepares and sends a message to this group in broadcast mode (the annex and body of the message are initialized with strings)
Terminates