编程语言
首页 > 编程语言> > 鸿蒙内核源码分析(管道文件篇) | 如何降低数据流动成本 | 百篇博客分析OpenHarmony源码 | v70.01

鸿蒙内核源码分析(管道文件篇) | 如何降低数据流动成本 | 百篇博客分析OpenHarmony源码 | v70.01

作者:互联网

在这里插入图片描述

百篇博客系列篇.本篇为:

v70.xx 鸿蒙内核源码分析(管道文件篇) | 如何降低数据流动成本 | 51 .c .h .o

文件系统相关篇为:

什么是管道

管道符号 |

管道符号是两个命令直接的一道竖杠 |,简单而优雅,例如,ls用于显示某个目录中文件,wc用于统计行数.
ls | wc 则代表统计某个目录下的文件数量
再看个复杂的:

$ < colors.txt sort | uniq -c | sort -r | head -3 > favcolors.txt

pipefinal-1

经典管道案例

以下是linux官方对管道的经典案例. 查看 pipe

#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
    int pipefd[2];
    pid_t cpid;
    char buf;

    if (argc != 2) {
        fprintf(stderr, "Usage: %s <string>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    if (pipe(pipefd) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    cpid = fork();
    if (cpid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (cpid == 0) {    /* Child reads from pipe */
        close(pipefd[1]);          /* Close unused write end */

        while (read(pipefd[0], &buf, 1) > 0)
            write(STDOUT_FILENO, &buf, 1);

        write(STDOUT_FILENO, "\n", 1);
        close(pipefd[0]);
        _exit(EXIT_SUCCESS);

    } else {            /* Parent writes argv[1] to pipe */
        close(pipefd[0]);          /* Close unused read end */
        write(pipefd[1], argv[1], strlen(argv[1]));
        close(pipefd[1]);          /* Reader will see EOF */
        wait(NULL);                /* Wait for child */
        exit(EXIT_SUCCESS);
    }
}

解读

鸿蒙实现

管道的实现函数级调用关系如下:

SysPipe //系统调用
    AllocProcessFd  //分配两个进程描述符
    pipe    //底层管道的真正实现
        pipe_allocate   //分配管道
        "/dev/pipe%d"   //生成创建管道文件路径,用于创建两个系统文件句柄
        pipecommon_allocdev //分配管道共用的空间
        register_driver //注册管道设备驱动程序
        open    //打开两个系统文件句柄
        fs_getfilep //获取两个系统文件句柄的实体对象 `file`
    AssociateSystemFd //进程和系统文件句柄的绑定

其中最关键的是pipe,它才是真正实现管道思想的落地代码,代码稍微有点多,但看明白了这个函数就彻底明白了管道是怎么回事了,看之前先建议看文件系统相关篇幅,有了铺垫再看代码和解读就很容易明白.

int pipe(int fd[2])
{
  struct pipe_dev_s *dev = NULL;
  char devname[16];
  int pipeno;
  int errcode;
  int ret;
  struct file *filep = NULL;
  size_t bufsize = 1024;

  /* Get exclusive access to the pipe allocation data */

  ret = sem_wait(&g_pipesem);
  if (ret < 0)
    {
      errcode = -ret;
      goto errout;
    }

  /* Allocate a minor number for the pipe device */

  pipeno = pipe_allocate();
  if (pipeno < 0)
    {
      (void)sem_post(&g_pipesem);
      errcode = -pipeno;
      goto errout;
    }

  /* Create a pathname to the pipe device */

  snprintf_s(devname, sizeof(devname), sizeof(devname) - 1, "/dev/pipe%d", pipeno);

  /* No.. Allocate and initialize a new device structure instance */

  dev = pipecommon_allocdev(bufsize, devname);
  if (!dev)
    {
      (void)sem_post(&g_pipesem);
      errcode = ENOMEM;
      goto errout_with_pipe;
    }

  dev->d_pipeno = pipeno;

  /* Check if the pipe device has already been created */

  if ((g_pipecreated & (1 << pipeno)) == 0)
    {
      /* Register the pipe device */

      ret = register_driver(devname, &pipe_fops, 0660, (void *)dev);
      if (ret != 0)
        {
          (void)sem_post(&g_pipesem);
          errcode = -ret;
          goto errout_with_dev;
        }

      /* Remember that we created this device */

       g_pipecreated |= (1 << pipeno);
    }
  else
    {
       UpdateDev(dev);
    }
  (void)sem_post(&g_pipesem);

  /* Get a write file descriptor */

  fd[1] = open(devname, O_WRONLY);
  if (fd[1] < 0)
    {
      errcode = -fd[1];
      goto errout_with_driver;
    }

  /* Get a read file descriptor */

  fd[0] = open(devname, O_RDONLY);
  if (fd[0] < 0)
    {
      errcode = -fd[0];
      goto errout_with_wrfd;
    }

  ret = fs_getfilep(fd[0], &filep);
  filep->ops = &pipe_fops;

  ret = fs_getfilep(fd[1], &filep);
  filep->ops = &pipe_fops;

  return OK;

errout_with_wrfd:
  close(fd[1]);

errout_with_driver:
  unregister_driver(devname);

errout_with_dev:
  if (dev)
    {
      pipecommon_freedev(dev);
    }

errout_with_pipe:
  pipe_free(pipeno);

errout:
  set_errno(errcode);
  return VFS_ERROR;
}

解读

鸿蒙内核源码分析.总目录

v08.xx 鸿蒙内核源码分析(总目录) | 百万汉字注解 百篇博客分析 | 51 .c .h .o

百万汉字注解.百篇博客分析

百万汉字注解 >> 精读鸿蒙源码,中文注解分析, 深挖地基工程,大脑永久记忆,四大码仓每日同步更新< gitee | github | csdn | coding >

百篇博客分析 >> 故事说内核,问答式导读,生活式比喻,表格化说明,图形化展示,主流站点定期更新中< 51cto | csdn | harmony | osc >

关注不迷路.代码即人生

鸿蒙内核源码分析

QQ群:790015635 | 入群密码: 666

原创不易,欢迎转载,但请注明出处.

标签:OpenHarmony,鸿蒙,文件,pipefd,pipe,管道,源码,v70.01
来源: https://www.cnblogs.com/weharmony/p/15257441.html