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