• 后台while收发过程


    fuse_loop_mt.c 中fuse_do_work函数使用while循环在后台不断运行,每一个while循环中,主要有两个操作。

    1. fuse_session_receive_buf(mt->se, &fbuf, &ch);  fuse_session.c 

    2. fuse_session_process_buf(mt->se, &fbuf, ch);

    操作1使用 se->receive_buf(se, buf, chp)读取buffer内容。

    操作2使用se->process_buf(se->data, buf, ch);处理buffer内容。

    receive_buf和process_buf是两个函数指针,属于fuse_i.h的struct fuse_session的成员。

    搜索整个源文件,只发现在fuse_lowlevel.c中的struct fuse_session *fuse_lowlevel_new_common有一句

        se->receive_buf = fuse_ll_receive_buf; //fuse_ll_receive_buf函数也在该源文件中。

    经过打印发现,就是这个函数在处理接受。

    //////fuse_ll_receive_buf函数有个重要的操作是创建pipe, 调用 llp = fuse_ll_get_pipe(f);

    ////static struct fuse_ll_pipe *fuse_ll_get_pipe(struct fuse_ll *f)函数使用

    ////  res = pipe(llp->pipe);

    /////创建pipe。

    这个函数会转到fallback标签,因为 !(f->conn.want & FUSE_CAP_SPLICE_READ) 为真,一个是16,一个是512,与以后为0,取反为真。

    于是调用 fuse_chan_recv(struct fuse_chan **chp, char *buf, size_t size 函数。该函数在fuse_session.c中。

    在一开始的两个操作中,都有if语句,else是进入 fuse_chan_recv函数,但是那里都没有进入else,而最终还是在这里进入了该函数。

    然后调用int res=ch->op.receive(chp, buf, size); 

    其中ch是struct fuse_chan **类型,定义在fuse_session.c中。op是struct fuse_chan_ops类型,定义在fuse_lowlevel.h中。

    但是无法得知receive函数定义在哪,这需要追中ch及op在哪里被赋值。

    追踪:

    1. ch 在fuse_chan_recv(fuse_session.c)中没有被修改,因此其值从fuse_ll_receive_buf(fuse_lowlevel.c)传递来.

    2. 在fuse_ll_receive_buf中仍然没有被修改。

        此处发现,struct fuse_session在fuse_i.h中声明,在fuse_lowlevel.c中给其成员函数指针赋值。

      因此,值从fuse_session_receive_buf(fuse_session.c )中传来。

    3.  fuse_session_receive_buf是被fuse_do_work(fuse_loop_mt.c )调用的。

    现在来看在fuse_do_work中 ch的赋值过程。

    1.  回溯 struct fuse_chan *ch = mt->prevch;

        struct fuse_mt *mt = w->mt;

          struct fuse_worker *w = (struct fuse_worker *) data;

      data是由pthread_create(thread_id, &attr, func, arg)   (fuse_loop_mt.c )传递来的。

        追溯到fuse_loop_mt.c 中的fuse_start_thread,这里也是没改变 arg的值,

    再追溯到fuse_loop_start_thread(fuse_loop_mt.c )中的 w,这个变量就是元凶。其类型为fuse_worker。以参数形式传递到fuse_do_work中的w。

    我们关心的是 w->mt->prevch.

    2. 

    struct fuse_worker {
      struct fuse_worker *prev;
      struct fuse_worker *next;
      pthread_t thread_id;
      size_t bufsize;
      char *buf;
      struct fuse_mt *mt;
    };

    这里的mt由fuse_session_loop_mt(fuse_loop_mt.c )函数中传入。在该函数中有mt.prevch = fuse_session_next_chan(se, NULL);

    struct fuse_session {//se
      struct fuse_session_ops op;

      int (*receive_buf)(struct fuse_session *se, struct fuse_buf *buf, struct fuse_chan **chp);

      void (*process_buf)(void *data, const struct fuse_buf *buf, struct fuse_chan *ch);

      void *data;

      volatile int exited;

      struct fuse_chan *ch;
    };

    struct fuse_chan *fuse_session_next_chan(struct fuse_session *se, struct fuse_chan *ch)
    {
      assert(ch == NULL || ch == se->ch);
      if (ch == NULL)
        return se->ch;
      else
        return NULL;
    }

    而se是由函数fuse_loop_mt(struct fuse *f) 中传入。res = fuse_session_loop_mt(fuse_get_session(f));

    struct fuse_session *fuse_get_session(struct fuse *f)
    {
      return f->se;
    }

    而f是由fuse_main_common(helper.c)中传入。 

    struct fuse {
      struct fuse_session *se;
      struct node_table name_table;
      struct node_table id_table;
      struct list_head lru_table;
      fuse_ino_t ctr;
      unsigned int generation;
      unsigned int hidectr;
      pthread_mutex_t lock;
      struct fuse_config conf;
      int intr_installed;
      struct fuse_fs *fs;
      int nullpath_ok;
      int utime_omit_ok;
      struct lock_queue_element *lockq;
      int pagesize;
      struct list_head partial_slabs;
      struct list_head full_slabs;
      pthread_t prune_thread;
    };

    3. fuse_main_common函数中创建struct fuse *fuse;但是由fuse_setup_common)(helper.c)赋值。又由fuse_new_common(fuse.c)赋值 。

        其中f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f);该函数在(fuse_lowlevel.c)中。

    我们要找se->ch的赋值。

      

    4. 重点来了。

        在fuse.c的fuse_new_common中,fuse_session_add_chan(f->se, ch);给se赋了值。

          那么,这里的ch是哪里来的?

      是fuse_new_common(fuse.c)传来的。并由fuse_mount_common(helper.c)构建,这里使用ch = fuse_kern_chan_new(fd);构建。

    在fuse_kern_chan.c中:

    struct fuse_chan *fuse_kern_chan_new(int fd)
    {
      struct fuse_chan_ops op = {
        .receive = fuse_kern_chan_receive,
        .send = fuse_kern_chan_send,
        .destroy = fuse_kern_chan_destroy,
      };
      size_t bufsize = getpagesize() + 0x1000;
      bufsize = bufsize < MIN_BUFSIZE ? MIN_BUFSIZE : bufsize;
      return fuse_chan_new(&op, fd, bufsize, NULL);
    }

      终于名了,最终.receive 函数指针指向的是 fuse_kern_chan_receive函数,在fuse_kern_chan.c中。

    现在的问题变为,fuse_kern_chan_receive中的read系统调用的fd,即fuse_chan_fd(ch)是从哪里打开的。

    1. 我们在回溯一下调用过程。

        fuse_kern_chan_receive

            fuse_mount_common

    原来是在fuse_mount_common中调用fuse_mount_compat25打开的。

        fuse_mount_compat25调用 fuse_kern_mount, fuse_kern_mount调用fuse_mount_sys或fuse_mount_fusermount。

    以fuse_mount_sys为例,他会打开/dev/fuse,并返回文件描述符。/dev/fuse是一个字符设备。

    至此,终于清晰了。

  • 相关阅读:
    CocoaPods的安装和使用
    HTTP协议(一)
    iOS常用设计模式之观察者模式
    git使用方法
    关于网络开发中XML的使用
    观察者模式的具体应用——通知(notification)机制和KVO(KeyValueObserving)机制
    HTTP协议(二)之HTTP请求
    iOS常用设计模式之委托模式
    x ^y mod m
    Problem A: 速算24点
  • 原文地址:https://www.cnblogs.com/bettersky/p/6763930.html
Copyright © 2020-2023  润新知