$ 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
Overview of IPC
Pipe
3. Message Queue
Shared memory
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
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
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)
$ 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
Overview of IPC
Pipe
Message Queue
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