libubox

了解openwrt libubox library
及測試範例


更新記錄

item note
20161130 第一版

目錄


openwrt libubox

libubox主要提供一下两种功能:
1、提供一套基于事件驱动的机制。
2、提供多种开发支持接口。(如:链表、kv链表、平衡查找二叉树、md5、json)

使用libubox开发的好处有如下几点:
1、可以使程序基于事件驱动,从而可实现在单线程中处理多个任务。
2、基于libubox提供的开发API可以加快开发进度的同事提高程序的稳定性。
3、能更好的将程序融入openwrt的架构中,因为新的openwrt的很多应用和库都基于libubox开发的

libubox.so提供下例工具

  • openwrt libubox
  • utils - misc libubox utility functions

    1
    2
    3
    4
     - calloc_a(size_t len, [void **addr, size_t len,...], NULL)
    allocate a block of memory big enough to hold multiple aligned objects.
    - b64_encode
    - b64_decode
  • usock - socket helper functions

    1
    usock(int type, const char *host, const char *service);
  • uloop - event loop implementation

    • Uloop is a loop runner for i/o.
    • The fd management part is set up with the uloop_fd struct, just adding the fd and the callback function you want called when an event arises.
    • The timeout management part is mostly prepared to do simple things,
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      typedef void (*uloop_fd_handler)(struct uloop_fd *u, unsigned int events);
      typedef void (*uloop_timeout_handler)(struct uloop_timeout *t);
      typedef void (*uloop_process_handler)(struct uloop_process *c, int ret);

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

      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);

      int uloop_process_add(struct uloop_process *p);
      int uloop_process_delete(struct uloop_process *p);

      int uloop_init(void);
      void uloop_run(void);
      void uloop_done(void);
  • blob ,library for generating/parsing tagged binary data


example

ustream-example 測試

  • 帶起ustream-example

    1
    2
    3
    4
    ~ # netstat -tpl
    Active Internet connections (only servers)
    Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
    tcp 0 0 127.0.0.1:10000 0.0.0.0:* LISTEN 908/ustream-example
  • 測試

    1
    2
    3
    #cat t1
    111
    #nc 127.0.0.1 10000 < t1
  • log

    1
    2
    3
    4
    /test # ./ustream-example
    New connection
    eof!, pending: 0, total: 4
    Connection closed

ustream-example 程式流程

  • run_server

    [run_server]
  • server_cb

    [server_cb]

libubox

uloop

uloop主要工能有下例3個

  • 文件描述符觸發事件的監控 (即uloop_run_events)
    循環調用epoll_wait 監相應的觸發事件文件描述符fd
  • timeout定時器處理(即uloop_process_timeouts)
  • 當前進程的子進程的維護(即uloop_handle_processes)

當某一個進程第一次調用uloop_run時,註冊sigchld和sigint信號

  • uloop_timeout
    循環獲取當前時間,把超時的timeout處理掉,
    有一條timeout鍊表在維護(即static struct list_head timeouts)

  • uloop_process
    循環檢測是否收到一個sigchld信號,如果收到,刪除對應的子進程,
    有一條process子進程鍊表在維護(即static struct list_head processes )

  • libubox function

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    uloop_fd_add
    註冊一個新描述符到事件處理循環

    uloop_fd_delete
    從事件處理循環中銷毀指定描述符

    uloop_timeout_add
    註冊一個新定時器

    uloop_timeout_set
    設置定時器超時時間(毫秒),並添加

    uloop_timeout_cancel
    銷毀指定定時器

    uloop_timeout_remaining
    獲取定時器還剩多長時間超時

    uloop_process_add
    註冊新進程到事件處理循環

    uloop_process_delete
    從事件處理循環中銷毀指定進程

uloop程序

uloop 是 libubox 的一部份,其功能包括
timeout:再多久執行指定函數
執行 child process,結束時執行指定的函數
fd 事件發生時執行指定函數。(使用 kqueue 或 epoll)

  • uloop_init
    建立poll_fd
    epoll_create(32)

  • uloop_fd_add
    註冊一個新描述符到事件處理循環

  • uloop_run
    文件描述符觸發事件的監控 (即uloop_run_events)

uloop_init

  • uloop_init

    [run_server]
  • FD_CLOEXEC

    • 如何避免fd 被多個子行程繼承
      若程式中有exec(即fork等行為)產生子程序,此時子程序開啟的fd量會多1個(即父程序)
      在父程序中設定FD_CLOEXEC,表示當exec時設定父程序的fd為close
      It sets the close-on-exec flag for the file descriptor, which causes the file descriptor to be automatically (and atomically) closed when any of the exec-family functions succeed.

uloop_fd_add

  • uloop_fd_add
    註冊一個新描述符到事件處理循環

  • uloop_fd_delete
    從事件處理循環中銷毀指定描述符

[uloop_fd_add]

uloop_run

  • uloop_run[uloop_run]

uloop_get_next_timeout

  • 取得timeout時間[uloop_get_next_timeout]

uloop_run_events

  • 設定epoll_wait及timeout
  • 確認是否有fd要執行[uloop_run_events]

ustream

  • ustream - library for stream buffer management

  • ustream_fd_init(struct ustream_fd *s, int fd);
    ustream_fd_init: create a file descriptor ustream (uses uloop)

ustream_fd_init

  • ustream_fd_init[ustream_fd_init] [ustream_st]

ustream_uloop_cb

  • ustream_fd_read_pending
    • while(1)
    • read(sf->fd.fd,
    • if (!s->eof) ustream_state_change(s) && return
    • ustream_fill_read
      • if (s->notify_read) s->notify_read(s, n);

ustream_state_change_cb

  • ustream_state_change_cb[ustream_state_change_cb]

epoll

  • epoll

    • epoll - I/O event notification facility
    • Three system calls are provided to set up and control an epoll set: epoll_create, epoll_ctl, epoll_wait

      epoll之所以高效,是因為epoll將用戶關心的文件描述符放到內核里的一個事件表中,而不是像select/poll每次調用都需要重複傳入文件描述符集或事件集。比如當一個事件發生(比如說讀事件),epoll無須遍歷整個被偵聽的描述符集,只要遍歷那些被內核IO事件異步喚醒而加入就緒隊列的描述符集合就行了

  • epoll模型的EPOLLLT模式和EPOLLET模式比較

    • epoll是linux系統最新的處理多連接的高效率模型
    • 工作在兩種方式
    • EPOLLLT方式 (level-triggered模式),EPOLLLT是系統默認
      於level-triggered模式下,epoll_wait在事件狀態未變更前將不斷被觸發
    • EPOLLET方式 (edge-triggered模式)
      epoll_wait僅會在新的事件首次被加入epoll 物件時返回
  • wiki epoll
    舉例來說,倘若有一個已經於epoll註冊之管線接獲資料,epoll_wait將返回,並發出資料讀取的信號。現假設緩衝區的資料僅有部份被讀取並處理,在level-triggered模式下,任何對epoll_wait之呼叫都將即刻返回,直到緩衝區中的資料全部被讀取;然而,在edge-triggered的情境下,epoll_wait僅會於再次接收到新資料(亦即,新資料被寫入管線)時返回。

參考

libubox說明文章