William J. Freda is a senior consultant with Automated Concepts Inc. Specializing in UNIX/C applications in a relational database environment, William has had a variety of assignments throughout AT&T and Bell Laboratories. You can reach him at 90 Woodbridge Center Drive, Woodbridge, N.J. 07095, (201) 602-0200
Interprocess Communication (IPC) enables two or more processes to exchange information, share data, and synchronize execution. The basic interprocess communications facilities are signals, pipes, and named pipes. The more advanced facilities are semaphores, shared memory, and message queues. In this article, I describe each with corresponding advantages and disadvantages.
Signals
Signals are sent to processes when a particular event occurs or when some type of unrecoverable error occurs. Typically, user processes will trap most of these signals to perform some clean-up work before exiting the program. User processes can also send signals to each other via the kill (2) system call, but this is limited to descendants, or children, of the original proccess and to the superuser.
Pipes
A pipe is a unidirectional communication channel open between a parent and child process. A process can open a pipe to another process for reading or writing but not both. This limitation makes pipes unsuitable for processes that need to communicate bidirectionally.
Named Pipes
A named pipe is a FIFO (first in, first out) file. One process writes into the named pipe and the second process reads it. Since a named pipe is a regular file, its access permission can be set to allow all to use it. Thus, a named pipe is not limited to parent and child processes. One disadvantage of named pipes is that user processes can't be selective about what type of information they want to read from the pipe. In other words, if you were looking for a particular record in a named pipe, you would have to sequentially read the pipe until you found the record. Once information is read from a named pipe it is lost. In adddition, only one process should have a named pipe open ffor reading at a time. If more than one process has a named pipe open, the kernel will effectively toggle between the processes, giving one process one record, the second process the next record and so on.
Semaphores
Semaphores enable processes to synchronize execution. A semaphore is a positive integer that supports two possible operations: P and V. The P operation decrements the value of a semaphore, the V operation increments it. The semaphore's value must always be greater than or equal to 0. If a process attempts to decrement the semaphore's value with a P operation when its value is 0, the kernel puts the process to sleep until the operation can complete successfully. Semaphores have the following advantages over signals:
- Any process can use a semaphore as long as the permissions are set accordingly.
- A process can postpone execution until a semaphore reaches a certain value.
- Processes can perform operations on more than one semaphore at a time. If all operations cannot be performed simultaneously, none are performed.
Shared Memory
Shared memory enables processes to attach a common data area to share information. Once attached, the shared memory segment can be accessed the same way you access a memory block obtained from malloc(3C). Typically, you use a semaphore to ensure that only one proccess at a time writes to shared memory.
Message Queues
A message queue enables two or more processes to exchange information. Message queues have some advantages over pipes and named pipes:
These IPC facilities are beneficial because they enable you to split tasks among multiple processes. Say, for example, that you have an application that reads records from a tape, validates them, then updates several tables in the database. Using the IPC facilities, you can split the application into two separate processes: one that reads and validates records from the tape and one that updates the database. With this scheme, the second process updates the database while the first process reads and validates the next record. If this could cut processing time by 1 percent with 100,000 records on a tape (10ms per record), the net reduction in processing time would be 1,000 seconds, or 16 minutes and 40 seconds.
- Any process can use a message queue as long as the permissions are set accordingly.
- A message queue is a bidirectional communication channel. Processes can send and receive messages over the same message queue.
- Processes can select a particular message type without having to sequentially read each message.
A message queue enables two or moe processes to exchange information, ranging from a simple character string to an array of C structures.
Before a process can send or receive messages, it must obtain a message queue identifier (msqid) from the UNIX kernel. The msqid, which is similar to a file descriptor, is basically an index into a set of kernel tables. The msgget (2) system call is used for this purpose (see Listing 1) .
Synopsis
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <errno.h> int msgget(key, msgflg) key_t key; int msgflg;Argument Description
key is a user-chosen name for a message queue. If key is set equal to IPC_PRIVATE, it informs the kernel that this is a private message queue. Private message queues are known only to the calling process and any child processes. This is roughly equivalent to opening a bidirectional pipe between two processes.msgflg is an integer value that contains the access permissions of the message queue ORed with the control flags IPC_CREAT and/or IPC_EXCL. The access permissions for a message queue are similar to the access permission for a regular file. The IPC_CREAT control flag instructs msgget() to create a message queue if one doesn't already exist. The IPC_EXCL control flag is used with IPC_CREAT to ensure that a new message queue is created and to return an error if one already exists.
Upon successful completion, msgget() returns a message queue identifier. Otherwise, msgget() returns -1 and places the error number in the external integer errno.
Possible Errors
EACCES A message queue identifier already exists for key, but access permission is denied to this process.ENOENT The message queue needs to be created but msgflg did not contain IPC_CREAT.
ENOSPC The maximum number of message queues system wide has been reached. This error rarely occurs.
EEXIST A message queue identifier already exists for key. This occurs when msgflg contained IPC_CREAT IPC_EXCL.
The example in Listing 1 creates a (possible existing) message queue with owner and group read/write permission. The example in Listing 2 creates a new message queue with owner and group read/write permission. It also notifies the user with an appropriate error message if the message queue already exists.
Message Queue Operations
Sending Messages
Sending messages is accomplished using the msgsnd(2) system call.
Synopsis
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <errno.h> int msgsnd(msqid, msgp, msgsz, msglf) int msqid; struct mssg *msgp; int msgsz, msgflg;Argument Description
msqid is a message queue identifier obtained from a previous call to msgget(2). msgp is a pointer to a user-defined structure:
struct mssg { long mtype; /* Message type */ char mtext[LENGTH]; /* Message text */ }mtype Can be used to assisn the message a particular type or classification. The receiving process uses mtype to select a particular message on queue without having to sequentially read each message.mtext The text of the message. LENGTH is any size your application requires up to a system-defined maximum.
msgsz The length of the message contained in mtext.
msgflg A control flag that contains either 0 or IPC_NOWAIT. If the message queue is full, the kernel will normally put the process to sleep until the message queue has sufficient room to place the message.
The IPC_NOWAIT control flag disables this feature, and msgsnd() returns immediately if the message queue is full.
Upon successful completion, msgsnd() returns 0. Otherwise, msgsnd() returns -1 and places the error number in the external integer errno. See the example in Listing 3.
Possible Errors
EINVAL1) Msqid is an invalid message queue identifier
2) Mtype is less than 1
3) Msgsz is less than 0 or greater than the system limit
EACCESS Access permission denied.
EAGAIN The message queue is full. this only happens when msgflg contains IPC_NOWAIT.
EFAULT Only a program bug can cause this error. Msgp points to an illegal address.
EINTR The process was asleep waiting to send a message and an interrupt occurred.
EIDRM The process was asleep waiting to send a message and someone removed the message queue from the system.
Receiving Messages
Receiving messages is accomplished using the msgrcv(2) system call. See the example in Listing 4.
Synopsis
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <errno.h> int msgrcv(mspid, msgp, msgsz, msgtyp, msgflg) int msqid; struct mssg *msgp; int msgsz; long msgtyp; int msgflg;Argument Description
msqid A message queue identifier obtained from a previous call to msgget (2) .msgp A pointer to the user-defined structure described above.
msgsz The length of the message buffer mtext. This prevents the kernel from inadvertently overwriting the buffer.
msgtyp A particular message type you wish to receive. If it contains 0 the first message on the message queue is returned regardless of the message type.
msgflg A control flag that contains either 0, IPCC_NOWAIT, MSG_NOERROR , o r IPC_NOWAIT ORed with MSG_NOERROR. The kernel will normally put the process to sleep if the message queue is empty or there is no message of msgtyp currently on queue. The IPC_NOWAIT control flag disables this feature and causes msgrcv() to return immediately. If the message is too long, msgrcv() will normally return an error. The MSG_NOERROR control flag disables this feature and msgrcv() will silently truncate any message that is too long.
Upon successful completion, msgrcv() returns the number of bytes places in mtext. Otherwise, msgrcv() returns -1 and places the error number in the external integer errno.
Possible Errors
EINVAL1) Msqid is an invalid message queue identifier
2) Msgsz is less than 0
EACCESS Access permission denied.
E2BIG The message on queue is longer than msgsz. This error is not returned if msgflg contains MSG_NOERROR.
ENOMSG There is no message of the desired type on queue. This only happens when msgflag contains IPC_NOWAIT.
EFAULT Only a program bug can cause this error. Msgp points to an illegal address.
EINTR The process was asleep waiting to receive a message and an interrupt occurred.
EIDRM The process was asleep waiting to receive a message and someone removed the message queue from the system.
Controlling Message Queues
In addition to sending and receiving messages, your application may need to exercise some degree of control over a message queue. The msgctl(2) system call is used for this purpose. It performs the following functions:
- It enables the owner of the message queue to cchange the access permissions or remove the message queue from the system.
- It also enables anyone with read permission to gather statistics that detail:
1) The process id of the last process that sent a message.
2) The date and time the last message was sent.
3) The process id of the last process that received a message.
4) The date and time the last message was received.
5) The number of messages currently on queue.
6) The total number of bytes on queue.Synopsis
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <errno.h> int msgctl (msqid, cmd, buf) int msqid, cmd; struct msqid_)ds *buf;Argument Description
msqid A message queue identifier obtained from a previous call to msgget (2).cmd One of the following commands:
IPC_STAT Gather statistics as detailed above.
IPC_SET Change the access permissions.
IPC_RMID Remove the message queue from the system.
Upon successful completion, msgctl() returns 0. Otherwise msgctl() returns -1 and places the error number in the external integer errno.
Possible Errors
EINVAL1) Msqid is an invalid message queue identifier
2) Cmd is an invalid command
EACCESS Access permissions denied.
EPERM This error occurs whenever cmd is IPC_SET or IPC_RMID and someone other than the owner or the super-user is attempting to change the access permissions or remove the message queue.
EFAULT Only a program bug can cause this error. Buf points to an illegal address.
Quite frankly, the only facility of msgctl() that I have found useful is IPC_RMID, whicch removes a message queue from the system (see Listing 5) . If I want detailed information about a message queue or any other IPC facility, I use the UNIX ipcs command, which dumps out the statistics described above.
The sample program in Listing 6 could easily fit into a number of different applications. With this program, users can send one-line messages to each other. The sen_mssg() function prompts the user to enter the login name of the user to which he or she wants to send a message. send_mssg() then extracts the UNIX userid by querying the password file using the library function getpwent (3C). The message is then inserted into the message queue via msgsnd(2) with the message type set equal to the userid.
Placing calls to recv_mssg() in different areas of the application gives the users the illusion that the message has been received in near realtime. The call to msgrcv(2) uses the IPCC_NOWAIT control flag and will return immediately to the caller if no message is on queue.
Summary
Message queues allow multiple processes to exchange information bidirectionally. Since a message queue is a UNIX kernel data structure and thus part of the operating system, this information is passed between processes without the need for any disk I/O. In addition, processes can select a particular message type without having to sequentially read each message. message queues eliminate the need for consuming processor cycles polling for a particilar message to arrive. The UNIX kernel takes care of this for you by putting your process to sleep and waking it when the message arrives.By recognizing areas in an application where tasks could be performed concurrently, IPC facilities such as message queues allow you to perform the most work in the least amount of time.