1. libubox概述 libubox是openwrt新版本中的一個基礎庫,有很多應用是基於libubox開發的,如uhttpd,netifd,ubusd等。 libubox主要提供以下兩種功能: 提供一套基於事件驅動的機制; 提供多種開發支持介面,如鏈表、kv鏈表、平衡查找二叉樹、md5、jso ...
1. libubox概述
libubox是openwrt新版本中的一個基礎庫,有很多應用是基於libubox開發的,如uhttpd,netifd,ubusd等。
- libubox主要提供以下兩種功能:
提供一套基於事件驅動的機制;
提供多種開發支持介面,如鏈表、kv鏈表、平衡查找二叉樹、md5、json等。
- 使用libubox開發的好處有如下幾點:
可以使程式基於事件驅動,從而可實現在單線程中處理多個任務;
基於libubox提供的API可以加快開發進度,提高程式的穩定性;
能更好的將程式融入openwrt架構中,因為新的openwrt的很多應用和庫都基於libubox開發,當前K2T使用的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)
從進程事件處理鏈表中刪除該進程事件。