docs/en/device_dev_guide/kernel/IPC/Pipe.md

304 lines
8.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Pipe Development Guide
\[ English | [简体中文](../../../../zh-cn/device_dev_guide/kernel/IPC/Pipe.md) \]
## I. Overview
Pipes are widely used in systems for various purposes, including the following common types:
1. Pipe (Anonymous Pipe):
- Used to create a pipe that allows inter-process communication (IPC).
- The created pipe contains two file descriptors: one for reading (read end), and the other for writing (write end).
2. `popen`/`pclose` calls:
- Creates a pipe connected to another process, allowing reading from its output or sending data to its input.
3. FIFO (Named Pipe):
- Allows data exchange between unrelated processes.
- Creating a FIFO is similar to creating a file and requires specifying a path.
## II. API Interfaces
### 1、`pipe` Function Usage Instructions
#### Usage Instructions
The following are the function definitions for `pipe` and `pipe2`
```C++
#include <unistd.h>
// Returns: 0 if OK, 1 on error
int pipe(int fd[2]);
int pipe2(int fd[2], int flags);
```
- Pipe File Descriptors
- `fd[0]`The read end of the pipe.
- `fd[1]`The write end of the pipe.
- Notes
- Writing to a closed read end: When data is written to a pipe whose read end is closed, a SIGPIPE signal is generated. If the signal is ignored or returned from the signal handler, `write` returns -1 and sets `errno` to EPIPE.
- Multi-process writing: When multiple processes write to a pipe simultaneously, data may interleave.
#### Configuration Enabling
Below are the configuration options for enabling pipe functionality:
```bash
CONFIG_PIPES=y
CONFIG_DEV_PIPE_SIZE>0
```
#### Example Code
Below is an example code using pipes for inter-thread communication:
```C++
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#define BUFFER_SIZE 1024
void* write_thread(void* arg) {
int* pipefd = (int*)arg;
char buffer[] = "Hello, pipe!";
write(pipefd[1], buffer, sizeof(buffer));
return NULL;
}
void* read_thread(void* arg) {
int* pipefd = (int*)arg;
char buffer[BUFFER_SIZE];
ssize_t bytes_read = read(pipefd[0], buffer, sizeof(buffer) - 1);
if (bytes_read > 0) {
buffer[bytes_read] = '\0';
printf("Read from pipe: %s\n", buffer);
}
return NULL;
}
int main() {
int pipefd[2];
pthread_t writer, reader;
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
if (pthread_create(&writer, NULL, write_thread, (void*)pipefd) != 0) {
perror("pthread_create writer");
exit(EXIT_FAILURE);
}
if (pthread_create(&reader, NULL, read_thread, (void*)pipefd) != 0) {
perror("pthread_create reader");
exit(EXIT_FAILURE);
}
pthread_join(writer, NULL);
pthread_join(reader, NULL);
close(pipefd[0]);
close(pipefd[1]);
return 0;
}
```
### 2、`popen/pclose` Function Usage Instructions
#### Usage Instructions
```C++
#include <stdio.h>
// Returns: file pointer if OK, NULL on error
FILE *popen(const char *cmdstring, const char *type);
// Returns: termination status of cmdstring, or 1 on error
int pclose(FILE *fp);
```
The `popen` function creates a new process using `posix_spawn` to execute the specified command string (`cmdstring`) and redirects its input or output. The specific behavior depends on the value of the `type` parameter:
- If `type` is `r`, the file pointer connects to the standard output (stdout) of `cmdstring`.
- If `type` is `w`, the file pointer connects to the standard input (stdin) of `cmdstring`.
#### Configuration Enabling
```Bash
CONFIG_SYSTEM_POPEN=y
```
#### Example Code
```C++
#include <stdio.h>
#include <stdlib.h>
nt main() {
FILE *pipe;
char *command = "ls";
char buffer[128];
pipe = popen(command, "r");
if (pipe == NULL) {
fprintf(stderr, "popen failed.\n");
return -1;
}
while (fgets(buffer, sizeof(buffer), pipe) != NULL) {
/* Processing each line of output */
printf("%s", buffer);
}
if (pclose(pipe) == -1) {
fprintf(stderr, "pclose failed.\n");
return -1;
}
return 0;
}
```
### 3、FIFO Usage Instructions
#### Usage Instructions
FIFO (Named Pipe) is a special type of file used for communication between unrelated processes. Below are the function definitions for creating and using FIFOs:
```C++
#include <sys/stat.h>
// Both return: 0 if OK, 1 on error
int mkfifo(const char *path, mode_t mode);
int mkfifoat(int dirfd, const char *path, mode_t mode);
```
- `mode` Parameter: Specifies the file permissions of the FIFO, same as the `mode` parameter in the `open` function.
- `path` Parameter in `mkfifoat`:
- If specified as an absolute `path`, the dirfd parameter is ignored, and behavior is similar to `mkfifo`.
- If specified as a relative path, it is relative to the directory opened by `dirfd`.
- If specified as a relative path and `dirfd` is `AT_FDCWD`, the path is relative to the current directory.
- Notes on Opening FIFO:
- If non-blocking flag `O_NONBLOCK` is not set:
- When opened as read-only (`O_RDONLY`), the process will block until another process opens the FIFO for writing.
- When opened as write-only (`O_WRONLY`), the process will block until another process opens the FIFO for reading.
- It is not recommended to open FIFO with `O_RDWR` (read-write mode), as this may cause the read to never encounter an end-of-file (EOF). Non-blocking mode should be used to avoid blocking behavior.
#### Configuration Enabling
```bash
CONFIG_PIPES=y
CONFIG_DEV_FIFO_SIZE>0
```
#### Example Code
Below is an example code using FIFO for inter-thread communication:
```C++
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FIFO_NAME "/var/myfifo"
void* writer_thread(void* arg) {
int fd;
char buf[] = "Hello, FIFO!";
/* Open the FIFO for writing */
fd = open(FIFO_NAME, O_WRONLY);
if (fd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
/* Write data to the FIFO */
if (write(fd, buf, sizeof(buf)) == -1) {
perror("write");
exit(EXIT_FAILURE);
}
/* Close the FIFO */
close(fd);
return NULL;
}
void* reader_thread(void* arg) {
int fd;
char buf[1024];
/* Open the FIFO for reading */
fd = open(FIFO_NAME, O_RDONLY);
if (fd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
/* Read data from the FIFO */
if (read(fd, buf, sizeof(buf)) == -1) {
perror("read");
exit(EXIT_FAILURE);
}
/* Print the data read from the FIFO */
printf("Read from FIFO: %s\n", buf);
/* Close the FIFO */
close(fd);
return NULL;
}
int main() {
pthread_t writer, reader;
/* Create the FIFO */
if (mkfifo(FIFO_NAME, 0666) == -1) {
if (errno != EEXIST) {
perror("mkfifo");
exit(EXIT_FAILURE);
}
}
/* Create threads for reading and writing */
if (pthread_create(&writer, NULL, writer_thread, NULL) != 0) {
perror("pthread_create writer");
exit(EXIT_FAILURE);
}
if (pthread_create(&reader, NULL, reader_thread, NULL) != 0) {
perror("pthread_create reader");
exit(EXIT_FAILURE);
}
/* Wait for the threads to finish */
pthread_join(writer, NULL);
pthread_join(reader, NULL);
/* Remove the FIFO */
unlink(FIFO_NAME);
return 0;
}
```
## III. Inter-Process Isolation Restrictions
In the current openvela environment, due to the lack of support for inter-process isolation, all processes share the same address space. This situation may lead to the following issues:
- Cross-process use of file descriptors (fd): Due to shared address space, cross-process use of file descriptors may result in unexpected behavior or resource conflicts.
Although hardware limitations prevent address space isolation, the following features remain isolated across processes:
- File Descriptors (fd): File descriptors are independent for each process and cannot be directly shared across processes.
- Environment Variables: Environment variables are independent for each process, and modifying one processs environment variable will not affect other processes.