Krishanu Konar

9 minute read


IPC (Inter Process Communication) refers to the mechanisms by which processes in an operating system communicate with each other. This involves synchronizing their actions and managing shared data. This can be done between related processes (parent/child) and between unrelated processes. These mechanisms are implemented as part of the kernel module. The Linux kernel has many IPC mechanisms that allow processes to communicate and collaborate. Here are some of the main ones:

Pipes

  • Unnamed Pipes, also known as anonymous pipe. These are Half duplex in nature, i.e they can do reads or writes but only in one direction. It is typically used to communicate between a parent process and a child process. This type of pipe is always one way.
  • Named Pipe, also called FIFO pipe. These are also half duplex. This type of pipe can handle one-way or two-way communication between two unrelated processes. The output from one process is the input of the other. In case of a FIFO, an intermediary file is created, and it hangs until the other side process has read the data, then exits. A named pipe can be created using mkfifo p command. ls -l p lists the file with p flag for type FIFO.

Shared Memory

Shared memory is a memory shared between two or more processes. It is Full duplex in nature and is the most efficient type of IPC as it doesn not require any kernel intervention once the memory is allocated/deallocated. The processes using shared memory must protect and sync the shared memory, or race conditions will happen. The ipcs command writes to the standard output information about active interprocess communication facilities, i.e. allows querying shared memory.

Message Queues

A message queue is a linked list of messages stored within the kernel and identified by a message queue identifier. A new queue is created or an existing queue opened by msgget(). Once msg is read, kernel deletes it from queue. Each read and write creates a syscall to kernel. This eliminates race condition occurances, but comes at the expense of system performance due to syscall interrups.

Semaphore

Semaphores are used to protect critical/common regions of memory shared between different processes. These atomic structures of OS. There are 2 types of semaphores:

  • Binary Semaphore: This has 2 states; locked or unlocked.
  • Counting semaphores: This allow arbitrary resource counters.

Signal

Signals are the notification of event occurances. These are also known as “traps” or “software interrupts”.

  • kill -l -> lists all signal present on kernel
  • signals 9-15 cannot be handled by process, will immediately terminate. called process crash-outs.
  • POSIX standardizes the use and definition of IPC construct.

Interrupts

  • Interrupts are the hardware calling the cpu. Interrupts essentially consist of “hardware needs attention”.

  • Interrupts can be viewed as a mean of communication between the CPU and the OS kernel. Signals can be viewed as a mean of communication between the OS kernel and OS processes.

  • Interrupts may be initiated by the CPU (exceptions; e.g.: divide by zero, page fault), devices (hardware interrupts - e.g: input available), or by a CPU instruction (traps; e.g: syscalls, breakpoints). They are eventually managed by the CPU, which “interrupts” the current task, and invokes an OS-kernel provided ISR/interrupt handler.

  • Hardware interrupts are always handled in kernel space.

  • In I/O devices one of the bus control lines is dedicated for this purpose and is called the Interrupt Service Routine (ISR).

  • On the x86 architecture, the Interrupt Vector Table (IVT) is a table that specifies the addresses of all the 256 interrupt handlers used in real mode

  • The Interrupt Descriptor Table (IDT) is specific to the I386 architecture. It is the Protected mode counterpart to the Real Mode Interrupt Vector Table (IVT) telling where the Interrupt Service Routines (ISR) are located.

  • In real mode, the lower 1K of memory holds a data structure known as the Interrupt Vector Table (IVT). There are nominally 256 entries in this table.

  • When a device raises an interrupt at let’s say process i, the processor first completes the execution of instruction i. Then it loads the “Program Counter” (PC) with the address of the first instruction of the ISR. Before loading the Program Counter with the address, the address of the interrupted instruction is moved to a temporary location. Therefore, after handling the interrupt the processor can continue with process i+1.

Software Interrupts

  • A software interrupt is produced by software or a system as opposed to hardware. They serve as a signal for the operating system or a system service to carry out a certain function or respond to an error condition.
  • Traps and exceptions are other names for software interruptions.
  • Software interrupts often occur when system calls are made.
  • A particular instruction known as an “interrupt instruction” is used to create software interrupts. When the interrupt instruction is used, the processor stops what it is doing and switches over to a particular interrupt handler code. The interrupt handler routine completes the required work or handles any errors before handing back control to the interrupted application.

Hardware Interrupts

  • A hardware interrupt is produced by devices/hardware.

  • In a hardware interrupt, all the devices are connected to the Interrupt Request Line. A single request line is used for all the devices.

  • To request an interrupt, a device closes its associated switch. When a device requests an interrupt, the value of INTR is the logical OR of the requests from individual devices.

  • Hardware interrupts are further divided into two types of interrupt

    • Maskable Interrupt: Hardware interrupts can be selectively enabled and disabled thanks to an inbuilt interrupt mask register that is commonly found in processors. A bit in the mask register corresponds to each interrupt signal; on some systems, the interrupt is enabled when the bit is set and disabled when the bit is clear, but on other systems, the interrupt is deactivated when the bit is set.
    • Spurious Interrupt: A hardware interrupt for which there is no source is known as a spurious interrupt. This phenomenon might also be referred to as phantom or ghost interrupts. When a wired-OR interrupt circuit is connected to a level-sensitive processor input, spurious interruptions are typically an issue. When a system performs badly, it could be challenging to locate these interruptions.
  • Sequences of Events Involved in Handling an IRQ(Interrupt Request)

    • Devices raise an IRQ.
    • The processor interrupts the program currently being executed.
    • The device is informed that its request has been recognized and the device deactivates the request signal.
    • The requested action is performed.
    • An interrupt is enabled and the interrupted program is resumed.

Signals

  • Signal (also called software interrupts) are sent by the operating system (or a process) to a process, which then should somehow deal with the signal.

  • Signals may be initiated by the OS kernel (e.g: SIGFPE, SIGSEGV, SIGIO), or by a process(kill()). They are eventually managed by the OS kernel, which delivers them to the target thread/process, invoking either a generic action (ignore, terminate, terminate and dump core) or a process-provided signal handler.

  • Signals are a type of IPC. The default signal in Linux is SIGTERM.

  • kill command is used to send signals to a process.

  • Some popular signals include:

    • SIGHUP 1 : Hang up controlling terminal or process
    • SIGINT 2 : Interrupt from keyboard (Ctrl + C)
    • SIGQUIT 3 : Quit from keyboard (Ctrl + \)
    • SIGILL 4 : Illegal Instruction
    • SIGTRAP 5: Breakpoint for debugging
    • SIGFPE 8 : Floating point exception
    • SIGKILL 9 : Kill signal
    • SIGSEGV 11: Invalid memory reference
    • SIGPIPE 13 Broken pipe: write to pipe with no readers
    • SIGALRM 14: Timer signal from alarm(2)
    • SIGTERM 15: Termination signal (Default)
    • SIGUSR1: User-defined signal 1
    • SIGUSR2: User-defined signal 2
    • SIGCHLD: Child stopped or terminated
    • SIGCONT: Cont Continue if stopped
    • SIGSTOP: Stop Stop process
  • SIGSTOP and SIGCONT: Used by processes to block and unblock processes.

  • signal: set handler for signal to be handled.

    • signal(func, SIGFPE): func() would be run once SIGFPE is recieved.
  • Processes can only send signal to other processes owned bny same user (or superuser can send any signal to any process).

  • What happens when a signal occurs?

    • When the signal occurs, the process has to handle it. There are three cases:
      • Ignore it. Many signals can be and are ignored, but not all. Hardware exceptions such as “divide by 0” (with integers) cannot be ignored successfully and some signals such as SIGKILL cannot be ignored at all.
      • Catch and handle the exception. The process has a function to be executed if and when the exception occurs. The function may terminate the program gracefully or it may handle it without terminating the program.
      • Let the default action apply. Every signal has a default action.
  • What is the signal mask?

    • A signal may be “blocked” so it will not be delivered until it is is “unblocked”. While the signal is waiting between being generated and being delivered, it is “pending”.
    • Each thread in a process has its own signal mask which lists the signals that thread is currently blocking. A thread can modify its signal mask using pthread_sigmask(), and a (single-threaded) process can do so using sigprocmask().
    • Since there are 32 (really 31, since 0 doesn’t count) different signals, we can store information about 32 signals in a single 32-bit integer (unsigned int).
    • If a process creates a child using fork(), the child inherits a copy of its parent’s signal mask, and this is preserved even if one of the exec() functions is then called.

Trapping Signals

  • trap is useful in running some code when a signal is recieved. There are two common uses for trap in shell scripts − Clean up temporary files or ignore signals. Trap follows the following syntax: trap <commands> <signals> .

  • Examples

    $ trap "rm -f $WORKDIR/work1$$ $WORKDIR/dataout$$; exit" 2
    

    If the user interrupts the execution of the program after this trap is executed, you can be assured that these two files will be cleaned up. The exit command that follows the rm is necessary because without it, the execution would continue in the program at the point that it left off when the signal was received.

  • $ trap '' 2: This specifies that the interrupt signal is to be ignored.

Example for handling a signal

#include<signal.h>
#include<unistd.h>

void sig_handler(int signo)
{
  if (signo == SIGINT)
    printf("received SIGINT\n");
}

int main(void)
{
  if (signal(SIGINT, sig_handler) == SIG_ERR)
    printf("\ncan't catch SIGINT\n");
  
  while(1) 
    sleep(1);
  return 0;
}
  • A function sig_handler() is used as a signal handler. This function is “registered” to the kernel by passing it as the second argument of the system call signal in the main() function. The first argument to the function signal is the signal we intend the signal handler to handle which is SIGINT in this case.
  • After the signal handler executes, the program continues inside the loop, that is, where it was before the signal. This is what should happen if the signal handler does not end the program.

References

comments powered by Disqus