Lecture 10 Inter Process Communication(IPC)

Section 1 Overview of IPC



Xiang Yong, Chen Yu, Li Guoliang, Ren Ju

Spring 2023

Outline

1. Overview of IPC

  1. Pipe
  2. Message Queue
  3. Shared memory
  4. Signal

Requirements for IPC

  • Challenge: The functionality of a single program is limited.
  • The objective of IPC: Multiple processes collaborate to meet complex requirements
    • Modularization of functionality
    • Isolation between programs
    • Collaboration among multiple programs to accomplish complex tasks

Definition of Inter process communication(IPC): the behavior of exchanging data (sharing or passing) between processes for interaction with each other.

Interaction between processes

  • Independent process: no interaction with other processes
  • Collaborative Process: Interaction between two or more processes
    • Sender Receiver / Client Server
❯ cat README.md | grep rcore
$ git clone https://github.com/rcore-os/rCore-Tutorial-v3.git
...
* [x] expand the fs image size generated by `rcore-fs-fuse` to 128MiB
  • grep depends on cat
    • The output produced by cat such as grep is used as its input for string matching

Ways of Inter-Process Communication

  • Direct communication: Two processes can transfer information to each other without the need for the kernel to replay it
  • Indirect communication: Two processes pass messages to each other through system calls and the kernel

IPC Mechanisms

IPC refers to the ability of processes to share or transfer data.

IPC机制 含义 通信方式
管道 (Pipe) 单方向传输字节流 间接通信
消息队列 (Message Queue) 通过队列中收/发消息 间接通信
信号 (Signal) 异步发送信号给进程处理 间接通信
套接字 (Socket) 多/单机进程间网络通信 间接通信
共享内存 (Shared Memory) 多个进程共享一块物理内存 直接通信
文件 (File) 多个进程可访问同一文件 间接通信

Typical IPC mechanism in UNIX

IPC refers to the ability of processes to share or pass data.

Basic Interfaces for message passing

  • Send messages
  • Receive messages
  • Remote Procedure Call (RPC)
  • Reply messages

Remote Procedure Call, RPC = send + recv

Blocking or Non-blocking Communication

  • Blocking communication:
    • Blocked send, blocked receive
  • Non-blocking communication:
    • Non-blocked send, non-blocked receive

IPC buffer modes

  • Unbounded Capacity: The sender does not need to wait
  • Bounded Capacity: The sender must wait when the communication link buffer queue is full.
  • Zero capacity: The sender must wait for the receiver.

Outline

  1. Overview of IPC

2. Pipe

  1. Message Queue
  2. Shared memory
  3. Signal

Pipe

A pipe is a mechanism for IPC, also known as an anonymous pipe.

  • A fixed-size byte queue with reading and writing ends.
  • The reading end is only used to read from the pipe.
  • The writing end is only used to write data into the pipe.
  • The reading/writing end is represented by different file descriptors

Create a pipe

int pipe(int pipefd[2])

  • A pipe can be represented as two file descriptors plus a section of kernel memory.
  • When creating a pipe, two file descriptors are returned
    • Read end of the pipe
    • Write end of the pipe

Application Scenarios of Pipe

  • Support communication between related processes
    • Parent-child processes, sibling processes, etc.
  • The parent process creates a pipe (two file descriptors)
    • The child process will inherit the file descriptor and read/write the pipe

Application Scenarios of Pipe

  • Usually, the two processes at both ends of the pipe will each close one file descriptor of the pipe, such as
    • The parent process closes the read descriptor and can only write data to the pipe
    • The child process closes the write descriptor and can only read data from the pipe.

Pipe Implementation Mechanism

Pipe example

$ gcc -o ex1 ex1.c
$ ./ex1
parents
write: the 0 message.
write: the 1 message.
...
children
read: the 0 message.
read: the 1 message.
...

Suggestion: You can practice in your own development environment after class

Pipes in the Shell

Just use a vertical bar "|" to connect two commands:

rCore-Tutorial-v3 on ch7
❯ cat README.md | grep rcore
$ git clone https://github.com/rcore-os/rCore-Tutorial-v3.git
...
* [x] expand the fs image size generated by `rcore-fs-fuse` to 128MiB
  • Very convenient for writing flexible command line scripts
  • Does not support communication between any two processes

Named pipe

A named pipe, also known as a FIFO, can be created using the mkfifo command in a shell.

Both anonymous pipes and named pipes belong to the category of unidirectional communication mechanisms. The difference between the two is that:

  • A named pipe can support communication between any two processes.
  • Anonymous pipes only support communication between between a parent process and its child processes or between sibling processes.

A named pipe is a blocking unidirectional communication pip:

  • Either party can read and write
  • Data is only written and read when both the reading and writing ends of the named pipe are opened simultaneously.

Named Pipes

shell A

$ mkfifo name.fifo
$ echo README > name.fifo #The file type is p, and writing to the named pipe is blocking

shell B

$ cat name.fifo

However, named pipes only support unidirectional communication in byte stream form, and do not support bidirectional communication between any two processes.
Named Pipes Example

Outline

  1. Overview of IPC
  2. Pipe

3. Message Queue

  1. Shared memory
  2. Signal

Message Queue

Message queues are an indirect communication mechanism based on structured data maintained by the OS.

  • Each Message is a sequence of bytes with its own type identifier
  • Messages with the same type identifier form a message queue in first in, first out order

Message Queue Implementation Mechanism

Message Queue Implementation Mechanism

Message Queue System Calls

  • System calls for message queues
    • msgget ( key, flags) //Get the message queue ID
    • msgsnd ( QID, buf, size, flags ) //send a message
    • msgrcv ( QID, buf, size, type, flags ) //Receive a message
    • msgctl( ... ) // message queue control

Message structure

struct msgbuf {
long mtype; /* message type */
char mtext[1]; /* message body */
};

Create a Message Queue

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflg);

Arguments:

  • key: the name of a message queue
  • msgflg: A set of nine permission flags, used in the same way as the mode flags used when creating a file, such as IPC_CREAT or IPC_EXCL.

Create a Message Queue

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflg);

Return value:

  • Success: msgget returns a non-negative integer, which is the identification code of the message queue.
  • Failure: Returns "-1"

Create a Message Queue

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflg);

So how to get the key value?

  • Define the key value by macro
  • Generate key value through ftok function

Send Messages

int msgsnd(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);

Parameter:

  • msgid: message queue identifier returned by msgget function
  • msg_ptr: pointer to the data to be sent
  • msg_sz: length of the data pointed to by msg_ptr
  • msgflg: controls the behavior when the message queue is full or reaches the system limit, such as IPC_NOWAIT which indicates not to wait when the queue is full and returns EAGAIN error.

Send Messages

int msgsnd(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);
  • Returns 0 on success
  • Returns -1 on failure

Receive Messages

int msgrcv(int msgid, void *msg_ptr, size_t msgsz, long int msgtype, int msgflg);
  • msgid: message queue identifier returned by msgget function
  • msg_ptr: pointer to the buffer where the received message will be stored
  • msgsz: size in bytes of the buffer pointed to by msg_ptr
  • msgtype: used to select which message to receive based on the type of the message
    • msgtype=0 returns the first message in the queue
    • msgtype>0 returns the first message in the queue with type equal to msgtype
    • msgtype<0 returns the first message in the queue with type less than or equal to the absolute value of msgtype

Receive messages

int msgrcv(int msgid, void *msg_ptr, size_t msgsz, long int msgtype, int msgflg);
  • msgflg: controls the behavior when there is no message available to receive with the specified type
    • IPC_NOWAIT: returns ENOMSG error if no message of the specified type is available
    • MSG_NOERROR: truncates the message if its size is greater than msgsz

return value:

  • On success, the number of bytes placed in the buffer is returned
  • On failure, -1 is returned

Message queue sample program

$ gcc ex1.c
$ ./a.out
Parent: input message type:
1
Parent: input message to be sent:
test
Parent: input message type:
Child: read msg:test
0

Suggestion: You can practice in your own development environment after class

Outline

  1. Overview of IPC
  2. Pipe
  3. Message Queue

4. Shared memory

  1. Signal

Shared memory (Shmem)

Shared memory is a communication mechanism that maps the same physical memory area to the memory address space of multiple processes simultaneously.

  • Each process's memory address space needs to explicitly set the shared memory segment.
  • Advantages: Quick and convenient data sharing
  • Disadvantages: Require synchronization mechanism to coordinate data access.

System calls for shared memory

  • shmget( key, size, flags) // Create shared memory segment
  • shmat( shmid, *shmaddr, flags) //map the shared segment to the process address space
  • shmdt(*shmaddr)//Unmap the shared memory to process address space
  • shmctl(...) //control shared memory

Note: Synchronization mechanisms such as semaphores are required to coordinate access conflicts to shared memory

Shared Memory Implementation Mechanism

Create shared memory

#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
  • key: IPC key, the return value of ftok().
  • size: the length (in bytes) of the shared memory segment.
  • shmflg: the flag that specifies the behavior of the function and the permissions of the shared memory, with the following values:
    • IPC_CREAT: Create if it does not exist.
    • IPC_EXCL: returns failure if already exists
  • Return value: success: shared memory identifier; failure: -1.

Shared memory mapping

#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);

Maps a shared memory segment into the data segment of the calling process, that is, establishes a relationship between the process and the shared memory so that a process pointer points to this shared memory.

return value:

  • Success: the mapped address of the shared memory segment (i.e., the pointer points to this shared memory).
  • Failed: -1

Shared memory mapping

void *shmat(int shmid, const void *shmaddr, int shmflg);
  • shmid: shared memory identifier, the return value of shmget().
  • shmaddr: the address where the shared memory is mapped, if NULL, the system will automatically assign it.
  • shmflg: the access permission and mapping conditions of the shared memory segment, with the following values:
    • 0: Shared memory has read and write permissions.
    • SHM_RDONLY: read-only.
    • SHM_RND: (valid only when shmaddr is not non-NULL)

Shared memory sample program

$ gcc writer.c -o w
$ gcc reader.c -o r
$ ./w
  Writer: copy data to shared-memory

Shared memory example

$ ./r
------------ Shared memory segment --------------
Key shmid Owner Permission Bytes Connections Status
0xdf20482b 1 chyyuu 666 512 0

data = [ How are you, mike: from Writer ]
deleted shared-memory

------------ Shared memory segment --------------
Key shmid Owner Permission Bytes Connections Status

Suggestion: You can practice in your own development environment after class

Outline

  1. Overview of IPC
  2. Pipe
  3. Message Queue
  4. Shared memory

5. Signal

Signal

  • A signal is an asynchronous message or event that interrupts a running process
  • Signal mechanism is a process-level asynchronous notification mechanism.

Question:

  • Why can Ctrl+C terminate the process?
  • How does the kill command end the process?

Signal Sending and Response Process

Signal Naming

  • The signal is an integer number, these integer numbers all define the corresponding macro name, and the macro name starts with SIG, such as SIGABRT, SIGKILL, SIGSTOP, SIGCONT

Signal sending

  • The process sends a signal through the kernel
    • For example, a shell can terminate a process by sending a signal through the kill command
  • The kernel can send signals directly
    • For example, if a process reads data from a pipe, but the read permission of the pipe is closed, the kernel sends a SIGPIPE signal to the process to indicate a read error.

Signal Sending

  • Peripheral issues via the core
    • For example, when the user presses the Ctrl+C key, the kernel receives an interrupt from the peripheral device that contains the Ctrl+C key and sends a SIGINT signal to the running process to terminate it abnormally.

Signal Handling in Receiving Processes

  • Ignore: the signal never happened.
  • Catch: the process calls the corresponding signal handling function to process the signal.
  • Default: if neither ignored nor caught, the process uses the kernel's default handling method for the signal.
    • The default signal handling in the kernel is usually to kill the process or ignore the signal.

Linux Signals

What are the signals for Linux? -- There are 62 signals.

Linux Signals

Why are there so many signals?

  • Each signal represents a certain event. In general, when a process receives a signal, it indicates that the event represented by the signal has occurred.
  • For the commonly used signals 1 to 34, it is required to understand rather than memorize them. If you forget the signal name, you can use the kill -l command to check it.

Common Linux Signals

  • SIGKILL
  • SIGINT
  • SIGSEGV

Signal Implementation Mechanism

Signal Implementation Mechanism

Signal Implementation Mechanism

  • Register the user-space signal handler sig_handler.
  • Before returning to user space, the kernel detects the need to handle signals.
  • The kernel pushes the sig_handler function stack information onto the user stack.
    • Simulate a user code call to the sig_handler function.
  • The kernel modifies the user-space return address while entering the context.
  • The kernel returns to user space and jumps directly to sig_handler;
  • The sig_handler function returns to the old code location to continue execution

Signal Application Programming

Summary

  • Mechanism and implementation of pipes
  • Mechanism and implementation of message queues
  • Mechanism and implementation of shared memory
  • Mechanism and implementation of signals
  • The relationship between these mechanisms and process control and management.

https://zhuanlan.zhihu.com/p/268389190 Linux Interprocess Communication——Message Queue

https://zhuanlan.zhihu.com/p/147826545 Interprocess Communication of Linux System Programming: Shared Memory

Ref: Understanding the Linux Kernel Signals and Inter-Process Communication https://compas.cs.stonybrook.edu/~nhonarmand/courses/fa14/cse506.2/slides/ipc.pdf