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     進程事件處理流程

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM