IPC is a set of programming interfaces that allow you to create and manage individual program processes that can run concurrently in an operating system. This allows a program to handle many user requests at the same time. Since a single user request may result in multiple processes running in the operating system on the user's behalf, the processes need to communicate with other users. The IPC interfaces make this possible. Each IPC method has its own advantages and limitations so it is not unusual for a single program to use all of the IPC methods. IPC methods include:
Pipes and named pipes
Message queueing
Semaphores
Shared memory
Sockets
The following is an example of the use of the IPC mechanisms provided in the ChorusOS operating system.
Refer to the grpAllocate(2K), grpPortInsert(2K), ipcReceive(2K), ipcSend(2K), ipcTarget(2K), portCreate(2K), and portDelete(2K) man pages.
(file: progov/ipcSend.c) #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <chorus.h> #include <am/afexec.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 */ static KnCap clientCap; /* Capability of the spawned */ /* actor */ /* 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]; /* Parameter for actor spawning */ AcParam param; /* 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 */ stamp = malloc(STAMPSIZE); sprintf(stamp, "%d", MYSTAMP); rslt = afexeclp(argv[0], &clientCap, NULL , argv[0], stamp, NULL); if (rslt == -1) { printf("Cannot spawn client actor, error %d\n", errno); 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; }
The main thread:
creates a port
creates a port group and inserts the port into it
spawns another copy of itself, using afexec(), 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 any 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 (annex and body of the message are initialized with strings)
terminates