openWrt libubox組件之uloop原理分析

 

1.    libubox概述

  libubox是openwrt新版本中的一個基礎庫,有不少應用是基於libubox開發的,如uhttpd,netifd,ubusd等。json

  •   libubox主要提供如下兩種功能:

  提供一套基於事件驅動的機制;架構

  提供多種開發支持接口,如鏈表、kv鏈表、平衡查找二叉樹、md五、json等。框架

  •  使用libubox開發的好處有以下幾點:

  可使程序基於事件驅動,從而可實如今單線程中處理多個任務;函數

  基於libubox提供的API能夠加快開發進度,提升程序的穩定性;oop

  能更好的將程序融入openwrt架構中,由於新的openwrt的不少應用和庫都基於libubox開發,當前分析使用的libubox版本爲libubox-2014-08-04。ui

2.    uloop

uloop是libubox下的一個模塊,有三個功能:文件描述符觸發事件的監控,timeout定時器處理, 當前進程的子進程的維護。線程

2.1   總體框架

2.1.1     主框架接口

  • 初始化事件循環

  int uloop_init(void)blog

  建立一個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     進程事件處理流程

 

相關文章
相關標籤/搜索