zoukankan      html  css  js  c++  java
  • libubox-uloop

    参考:libubox组件(3)——uloop

    uloop是提供事件驱动机制接口,类似libevent事件框架,基于epoll接口来实现的。

    uloop三大功能:事件管理(uloop_fd)、超时管理(uloop_timeout)和进程管理(uloop_process),定义在uloop.h中。

    1. 整体框架

       1:  /**
    
       2:   * 初始化事件循环
    
       3:   *主要工作是poll_fd = epoll_create(32);/* 创建一个epoll的文件描述符监控句柄。最多监控32个文件描述符 
    
       4:   **/
    
       5:  int uloop_init(void)
    
       6:  {
    
       7:      if (poll_fd >= 0)
    
       8:          return 0;
    
       9:   
    
      10:      poll_fd = epoll_create(32);/* 创建一个epoll的句柄。最多监控32个文件描述符 */
    
      11:      if (poll_fd < 0)
    
      12:          return -1;
    
      13:   
    
      14:      fcntl(poll_fd, F_SETFD, fcntl(poll_fd, F_GETFD) | FD_CLOEXEC); /* fd_cloexecs */
    
      15:      return 0;
    
      16:  }
    
      17:   
    
      18:   
    
      19:  /**
    
      20:   * 事件循环主处理入口
    
      21:   *1.当某一个进程第一次调用uloop_run时,注册sigchld和sigint信号
    
      22:   *2.循环获取当前时间,把超时的timeout处理掉,有一条timeout链表在维护
    
      23:   *3.循环检测是否收到一个sigchld信号,如果收到,删除对应的子进程,有一条process子进程链表在维护
    
      24:   *4.循环调用epoll_wait 监相应的触发事件文件描述符fd 
    
      25:   **/
    
      26:  void uloop_run(void)
    
      27:  {
    
      28:      static int recursive_calls = 0; /* static value */
    
      29:      struct timeval tv;
    
      30:   
    
      31:      /*
    
      32:       * Handlers are only updated for the first call to uloop_run() (and restored
    
      33:       * when this call is done).
    
      34:       */
    
      35:      if (!recursive_calls++) /* 第一次运行uloop_run时调用, 注册信号处理函数 */
    
      36:          uloop_setup_signals(true);
    
      37:   
    
      38:      uloop_cancelled = false;
    
      39:      while(!uloop_cancelled)
    
      40:      {
    
      41:          uloop_gettime(&tv); /* 获取当前时间 */
    
      42:          uloop_process_timeouts(&tv); /* 把超时的timeout清理掉 */
    
      43:          if (uloop_cancelled)
    
      44:              break;
    
      45:   
    
      46:          if (do_sigchld) /*  收到一个sigchld的信号 */
    
      47:              uloop_handle_processes(); /* 销毁该进程的uloop_process */
    
      48:          uloop_gettime(&tv);
    
      49:          uloop_run_events(uloop_get_next_timeout(&tv));/* 处理相应的触发事件fd */
    
      50:      }
    
      51:   
    
      52:      if (!--recursive_calls)
    
      53:          uloop_setup_signals(false);
    
      54:  }
    
      55:   
    
      56:   
    
      57:  /**
    
      58:   * 销毁事件循环
    
      59:   * 关闭epoll描述符
    
      60:   * 销毁子进程链表
    
      61:   * 销毁timeout链表
    
      62:  **/
    
      63:  void uloop_done(void)
    
      64:  {
    
      65:      if (poll_fd < 0)
    
      66:          return;
    
      67:   
    
      68:      close(poll_fd);
    
      69:      poll_fd = -1;
    
      70:   
    
      71:      uloop_clear_timeouts();
    
      72:      uloop_clear_processes();
    
      73:  }
    // 设置uloop内部结束循环标志
    static inline void uloop_end(void)
    {
        uloop_cancelled = true;
    }
    int uloop_init(void);
    void uloop_run(void);
    void uloop_done(void);

    2. uloop_fd

    uloop是一个I/O循环调度,将不同文件描述符添加到轮询中。

    文件描述符fd的管理由uloop_fd结构来设置。仅需设置fd和事件发生时的回调函数,数据结构的其他部分供内部使用。

    默认采用非阻塞和水平触发。

    #define ULOOP_READ      (1 << 0)
    #define ULOOP_WRITE     (1 << 1)
    #define ULOOP_EDGE_TRIGGER  (1 << 2)
    #define ULOOP_BLOCKING      (1 << 3)
    
    #define ULOOP_EVENT_MASK    (ULOOP_READ | ULOOP_WRITE)
    
    /* internal flags */
    #define ULOOP_EVENT_BUFFERED    (1 << 4)
    #ifdef USE_KQUEUE
    #define ULOOP_EDGE_DEFER    (1 << 5)
    #endif
    
    #define ULOOP_ERROR_CB      (1 << 6)
    
    struct uloop_fd
    {
        uloop_fd_handler cb;
        int fd;
        bool eof;
        bool error;
        bool registered;
        uint8_t flags;
    };
    
    int uloop_fd_add(struct uloop_fd *sock, unsigned int flags);
    int uloop_fd_delete(struct uloop_fd *sock);
    typedef void (*uloop_fd_handler)(struct uloop_fd *u, unsigned int events);

    3. uloop_timeout

    超时管理部分由uloop_timeout结构来管理,在定时时间到了之后调用回调函数,定时时间单位为毫秒。

    uloop定时器是一次性定时器,超时后会自动删除。

    libubox使用一个全局排序链表(按照超时时间升序排列)存储定时器节点。

    注:uloop将定时器节点按照绝对时间升序排,每次uloop循环先处理已超时的定时器,然后取定时器队列首节点(即最近一个将要超时的定时器节点),减去当前时间得到下次将要超时的相对时间;

    然后用这个相对时间作为超时时间调用epoll_wait。

    struct uloop_timeout
    {
        struct list_head list;
        bool pending;        //是否已经加入超时链表等待调度
      uloop_timeout_handler cb; 
      struct timeval time;
    };
    int uloop_timeout_add(struct uloop_timeout *timeout);
    int uloop_timeout_set(struct uloop_timeout *timeout, int msecs);
    int uloop_timeout_cancel(struct uloop_timeout *timeout);
    int uloop_timeout_remaining(struct uloop_timeout *timeout);

    typedef void (*uloop_timeout_handler)(struct uloop_timeout *t)

    uloop_timeout_add()添加定时器,要求已初始化timeout结构,应避免直接使用uloop_timeout_add()。

    uloop_timeout_set()设定定时器超时事件为当前时间+指定超时时间(msecs)。内部封装了uloop_timeout_add(),应调用本函数添加定时器。

    4. uloop_process

    当前进程的子进程管理。建立一个链表,按进程号升序方式管理所有进程id。

    uloop进程管理是一次性任务,触发后会自动删除。

    struct uloop_process
    {
        struct list_head list;
        bool pending;      //是否已经加入任务链表等待调度
    
        uloop_process_handler cb;
        pid_t pid;
    };
    
    int uloop_process_add(struct uloop_process *p);
    int uloop_process_delete(struct uloop_process *p);

    typedef void (*uloop_process_handler)(struct uloop_process *c, int ret)
  • 相关阅读:
    (转)使用vsphere client 克隆虚拟机
    【转】VIM高级用法笔记
    Oracle RAC的Failover
    /dev/shm过小导致ORA00845错误解决方法
    (转)How to use udev for Oracle ASM in Oracle Linux 6
    ORACLE十进制与十六进制的转换
    解决Oracle RAC不能自动启动的问题
    RAC集群时间同步服务
    db link hang的解决方法
    【转载】Oracle数据恢复 Linux / Unix 误删除的文件恢复
  • 原文地址:https://www.cnblogs.com/embedded-linux/p/6792679.html
Copyright © 2011-2022 走看看