zoukankan      html  css  js  c++  java
  • openWrt libubox组件之uloop原理分析

     

    1.    libubox概述

      libubox是openwrt新版本中的一个基础库,有很多应用是基于libubox开发的,如uhttpd,netifd,ubusd等。

    •   libubox主要提供以下两种功能:

      提供一套基于事件驱动的机制;

      提供多种开发支持接口,如链表、kv链表、平衡查找二叉树、md5、json等。

    •  使用libubox开发的好处有如下几点:

      可以使程序基于事件驱动,从而可实现在单线程中处理多个任务;

      基于libubox提供的API可以加快开发进度,提高程序的稳定性;

      能更好的将程序融入openwrt架构中,因为新的openwrt的很多应用和库都基于libubox开发,当前分析使用的libubox版本为libubox-2014-08-04。

    2.    uloop

    uloop是libubox下的一个模块,有三个功能:文件描述符触发事件的监控,timeout定时器处理, 当前进程的子进程的维护。

    2.1   整体框架

    2.1.1     主框架接口

    • 初始化事件循环

      int uloop_init(void)

      创建一个epoll的句柄,最多监控32个文件描述符。

      设置文件描述符属性,如FD_CLOEXEC。

    • 事件循环主处理入口

      void uloop_run(void)

    • 销毁事件循环

      void uloop_done(void)

      关闭epoll句柄。

      清空定时器链表中的所有的定时器。

      清空进程处理事件链表中删除所有的进程事件节点。

    2.1.2     主框架流程

     

      uloop_run轮询处理定时器、进程、描述符事件。

    • 遍历定时器timeouts链表判断是否有定时器超时,如果有则进行相应的回调处理,没有跳过。
    • 判断是否有子进程退出SIGCHLD信号,有就会遍历processes进程处理的链表,调勇相应的回调函数,没有跳过。
    • 计算出距离下一个最近的定时器的时间,作为文件描述符事件epoll的超时时间。然后epoll进行事件监听,如果有文件描述符准备就绪(可读写时间)则调用相应的回调函数,或者有信号进行中断epoll返回停止监听,否则epoll阻塞直到超时时间完成。

    2.2   描述符事件

    2.2.1     文件描述符uloop结构

    struct uloop_fd

    {

           uloop_fd_handler cb; /*文件描述符对应的处理函数 */

           int fd;              /*文件描述符*/

           bool eof;            /*EOF*/

           bool error;          /*出错*/

           bool registered;     /*是否已经添加到epoll的监控队列*/

           uint8_t flags;       /*ULOOP_READ | ULOOP_WRITE | ULOOP_BLOCKING等*/ 

    };

    2.2.2     描述符uloop使用接口

    • 注册一个新描述符到事件处理循环

      int uloop_fd_add(struct uloop_fd *sock, unsigned int flags)

      uloop最多支持10个描述符事件。

    • 从事件处理循环中销毁指定描述符

      int uloop_fd_delete(struct uloop_fd *sock)

    2.2.3     描述符事件流程

     

    2.3   定时器事件

    2.3.1     定时器timeout结构

    struct uloop_timeout

    {

        struct list_head list;  //链表节点

         bool pending;           //添加一个新的timeout pending是true, false删除该节点timeout

           uloop_timeout_handler cb; //超时处理函数

           struct timeval time;      //超时时间

    };

    2.3.2     定时器使用接口

    • 注册一个新定时器

      int uloop_timeout_add(struct uloop_timeout *timeout)

      用户不直接使用,内部接口,被接口uloop_timeout_set调用。

      将定时器插入到timeouts链表中,该链表成员根据超时时间从小到大排列。

     

    • 设置定时器超时时间(毫秒),并添加

      int uloop_timeout_set(struct uloop_timeout *timeout, int msecs)

      如果pending为true,则从定时器链表中删除原先已存在的定时器。

      设置定时器的超时时间点。

      调用uloop_timeout_add接口将该定时器加入到定时器链表中。

    • 销毁指定定时器

      int uloop_timeout_cancel(struct uloop_timeout *timeout)

      从定时器链表中删除指定定时器。

    • 获取定时器还剩多长时间超时

      int uloop_timeout_remaining(struct uloop_timeout *timeout)

      这里pending标记可判断定时器是否处于生命周期,如果尚处在生命周期内,则返回离定时器超时还有多少时间,单位为毫秒。

    2.3.3     定时器的使用

      用户使用定时器非常简单

           struct uloop_timeout *t;    //第一步定义一个定时器并申请内存空间

           t = malloc(sizeof(*t));

           t->cb = light_ctl_check_cb; //第二步指定回调函数

           t->pending = false;

           uloop_timeout_set(t, 2000); //第三步设置定时器超时时间

    2.3.4     定时器功能流程

    遍历定时器链表,如果有定时器已经超时,执行该定时器的回调函数。

    2.4   进程事件

    2.4.1     进程事件处理结构

    struct uloop_process {

           struct list_head list;             

           bool pending;                  

           uloop_process_handler cb;  /** 文件描述符, 调用者初始化 */

           pid_t pid;                 /** 文件描述符, 调用者初始化 */

    };

    2.4.2     进程事件使用接口

    • 注册新进程到事件处理循环

      int uloop_process_add(struct uloop_process *p)

      将进程事件插入到进程事件链表中,链表根据PID从小到大排序。

      其中p->proc.pid为注册到uloop监控的进程ID。

      P->cb为进程退出的回调函数,类型为:

      typedef void (*uloop_process_handler)(struct uloop_process *c, int ret)

    • 从事件处理循环中销毁指定进程

      int uloop_process_delete(struct uloop_process *p)

      从进程事件处理链表中删除该进程事件。

    2.4.3     进程事件处理流程

     

  • 相关阅读:
    好的开源项目汇总
    强制SVN上传代码时添加日志
    微信开发-回调模式
    Struct2中自定义的Filter无效
    Ajax 传包含集合的JSON
    PostgreSQL数据库PL/PGSQL学习使用
    单用户对比PG 9.5.4和SYBASE 15.7对超大表的操作性能
    一场一波三折的SQL优化经历
    聚簇索引对数据插入的影响
    磁盘IO初探
  • 原文地址:https://www.cnblogs.com/laoxiaobaiup/p/9366880.html
Copyright © 2011-2022 走看看