Linux supports a number of Interprocess Communication (IPC) mechanisms to allow processes to communicate with each other. Signals and pipes are the basic mechanisms, but Linux also supports System V IPC mechanisms.
Signals notify events to one or more processes and can be used as a primitive way of communication and synchronization between user processes. Signals can also be used for job control.
The kernel can generate a set of defined signals, or they can be generated by other processes in the system, provided that they have the correct privileges.
Processes can choose to ignore most of the signals that are generated, with two exceptions: SIGSTOP and SIGKILL. The SIGSTOP signal causes a process to halt its execution. The SIGKILL signal causes a process to exit and be ignored. With the exception of the SIGSTOP and SIGKILL signals, a process can choose how it wants to handle the various signals. Processes can block the signals, or they can either choose to handle the signals themselves or allow the kernel to handle the signals. If the kernel handles the signals, it performs the default actions required for the signal. Linux also holds information about how each process handles every possible signal.
Signals are not delivered to the process as soon as they are generated, but instead are delivered when the process resumes running. Every time a process exits a system call, if there are any unblocked signals, the signals are then delivered.
Linux is POSIX-compatible so the process can specify which signals are blocked when a particular signal-handling routine is called.
A pipe is a unidirectional, first-in first-out (FIFO), unstructured stream of data. Writers add data to one end of the pipe, and readers get the data from other end of the pipe. After the data is read, it is removed from the pipe. Pipes provide simple flow control.
For example, the following command pipes output from the ls command, which lists the directory’s files, into the standard input of the less command, which paginates the files:
$ ls | less
Linux also supports named pipes. Unlike pipes, named pipes are not temporary objects; they are entities in the file system and can be created using the mkfifo command.
System V IPC Mechanisms
Linux supports three types of interprocess communication mechanisms that first appeared in UNIX System V (1983). These mechanisms are message queues, semaphores, and shared memory. The mechanisms all share common authentication methods. Processes can access these resources only by passing a unique reference identifier to the kernel via system calls. Access to these System V IPC objects is checked using access permissions much like accesses to files are checked. The access rights to a System V IPC object are set by the creator of the object via system calls.
Message queues allow one or more processes to write messages, which will be read by one or more reading processes. In terms of functionality, message queues are equivalent to pipes, but message queues are more versatile than pipes and have several advantages over pipes. Message queues pass data in messages rather than as an unformatted stream of bytes, allowing data to be processed easily. The messages can be associated with a type, so the receiver can check for urgent messages before processing non-urgent messages. The type field can also be used to designate a recipient in case multiple processes share the same message queue.
Semaphores are objects that support two atomic operations: set and test. Semaphores can be used to implement various synchronization protocols. Semaphores can best be described as counters that control access to shared resources by multiple processes. Semaphores are most often used as a locking mechanism to prevent processes from accessing a particular resource while another process is performing operations on the resource.
A problem with semaphores, called deadlocking, occurs when one process has altered a semaphore’s value as it enters a critical region but then fails to leave the critical region because it crashed or was killed. Linux protects against this by maintaining lists of adjustments to the semaphore arrays. The idea is that when these adjustments are applied, the semaphore will be returned to the state it was in before the process’s set of semaphore operations were applied.
Shared memory allows one or more processes to communicate via memory that appears in all of their virtual address spaces. Access to shared memory areas is controlled through keys and access rights checking. When the memory is being shared, there are no checks on how the processes are using the memory. Each process that wishes to share the memory must attach to that virtual memory via a system call. The process can choose where in its virtual address space the shared memory goes, or it can let Linux choose a free area large enough. The first time that a process accesses one of the pages of the shared virtual memory, a page fault occurs. When Linux fixes that page fault, it allocates a physical page and creates a page table entry for it. Thereafter, access by the other processes causes that page to be added to their virtual address spaces.
When processes no longer wish to share the virtual memory, they detach from it. So long as other processes are still using the memory, the detach operation affects only the current process. When the last process sharing the memory detaches from it, the pages of the shared memory currently in physical memory are freed.
Further complications arise when shared virtual memory is not locked into physical memory. In this case, the pages of the shared memory may be swapped out to the system’s swap disk during periods of high memory usage.