libubox-uloop


參考:libubox組件(3)——uloop

uloop是提供事件驅動機制接口,類似libevent事件框架,基於epoll接口來實現的。

uloop三大功能:事件管理(uloop_fd)、超時管理(uloop_timeout)和進程管理(uloop_process),定義在uloop.h中。

1. 整體框架

   1:  /**

   2:   * 初始化事件循環

   3:   *主要工作是poll_fd = epoll_create(32);/* 創建一個epoll的文件描述符監控句柄。最多監控32個文件描述符 

   4:   **/

   5:  int uloop_init(void)

   6:  {

   7:      if (poll_fd >= 0)

   8:          return 0;

   9:   

  10:      poll_fd = epoll_create(32);/* 創建一個epoll的句柄。最多監控32個文件描述符 */

  11:      if (poll_fd < 0)

  12:          return -1;

  13:   

  14:      fcntl(poll_fd, F_SETFD, fcntl(poll_fd, F_GETFD) | FD_CLOEXEC); /* fd_cloexecs */

  15:      return 0;

  16:  }

  17:   

  18:   

  19:  /**

  20:   * 事件循環主處理入口

  21:   *1.當某一個進程第一次調用uloop_run時,注冊sigchld和sigint信號

  22:   *2.循環獲取當前時間,把超時的timeout處理掉,有一條timeout鏈表在維護

  23:   *3.循環檢測是否收到一個sigchld信號,如果收到,刪除對應的子進程,有一條process子進程鏈表在維護

  24:   *4.循環調用epoll_wait 監相應的觸發事件文件描述符fd 

  25:   **/

  26:  void uloop_run(void)

  27:  {

  28:      static int recursive_calls = 0; /* static value */

  29:      struct timeval tv;

  30:   

  31:      /*

  32:       * Handlers are only updated for the first call to uloop_run() (and restored

  33:       * when this call is done).

  34:       */

  35:      if (!recursive_calls++) /* 第一次運行uloop_run時調用, 注冊信號處理函數 */

  36:          uloop_setup_signals(true);

  37:   

  38:      uloop_cancelled = false;

  39:      while(!uloop_cancelled)

  40:      {

  41:          uloop_gettime(&tv); /* 獲取當前時間 */

  42:          uloop_process_timeouts(&tv); /* 把超時的timeout清理掉 */

  43:          if (uloop_cancelled)

  44:              break;

  45:   

  46:          if (do_sigchld) /*  收到一個sigchld的信號 */

  47:              uloop_handle_processes(); /* 銷毀該進程的uloop_process */

  48:          uloop_gettime(&tv);

  49:          uloop_run_events(uloop_get_next_timeout(&tv));/* 處理相應的觸發事件fd */

  50:      }

  51:   

  52:      if (!--recursive_calls)

  53:          uloop_setup_signals(false);

  54:  }

  55:   

  56:   

  57:  /**

  58:   * 銷毀事件循環

  59:   * 關閉epoll描述符

  60:   * 銷毀子進程鏈表

  61:   * 銷毀timeout鏈表

  62:  **/

  63:  void uloop_done(void)

  64:  {

  65:      if (poll_fd < 0)

  66:          return;

  67:   

  68:      close(poll_fd);

  69:      poll_fd = -1;

  70:   

  71:      uloop_clear_timeouts();

  72:      uloop_clear_processes();

  73:  }
// 設置uloop內部結束循環標志
static inline void uloop_end(void)
{
    uloop_cancelled = true;
}
int uloop_init(void);
void uloop_run(void);
void uloop_done(void);

2. uloop_fd

uloop是一個I/O循環調度,將不同文件描述符添加到輪詢中。

文件描述符fd的管理由uloop_fd結構來設置。僅需設置fd和事件發生時的回調函數,數據結構的其他部分供內部使用。

默認采用非阻塞和水平觸發。

#define ULOOP_READ      (1 << 0)
#define ULOOP_WRITE     (1 << 1)
#define ULOOP_EDGE_TRIGGER  (1 << 2)
#define ULOOP_BLOCKING      (1 << 3)

#define ULOOP_EVENT_MASK    (ULOOP_READ | ULOOP_WRITE)

/* internal flags */
#define ULOOP_EVENT_BUFFERED    (1 << 4)
#ifdef USE_KQUEUE
#define ULOOP_EDGE_DEFER    (1 << 5)
#endif

#define ULOOP_ERROR_CB      (1 << 6)

struct uloop_fd
{
    uloop_fd_handler cb;
    int fd;
    bool eof;
    bool error;
    bool registered;
    uint8_t flags;
};

int uloop_fd_add(struct uloop_fd *sock, unsigned int flags);
int uloop_fd_delete(struct uloop_fd *sock);
typedef void (*uloop_fd_handler)(struct uloop_fd *u, unsigned int events);

 

3. uloop_timeout

超時管理部分由uloop_timeout結構來管理,在定時時間到了之后調用回調函數,定時時間單位為毫秒。

uloop定時器是一次性定時器,超時后會自動刪除。

libubox使用一個全局排序鏈表(按照超時時間升序排列)存儲定時器節點。

注:uloop將定時器節點按照絕對時間升序排,每次uloop循環先處理已超時的定時器,然后取定時器隊列首節點(即最近一個將要超時的定時器節點),減去當前時間得到下次將要超時的相對時間;

然后用這個相對時間作為超時時間調用epoll_wait。

struct uloop_timeout
{
    struct list_head list;
    bool pending;        //是否已經加入超時鏈表等待調度
  uloop_timeout_handler cb; 
  struct timeval time;
};
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);

typedef void (*uloop_timeout_handler)(struct uloop_timeout *t)

uloop_timeout_add()添加定時器,要求已初始化timeout結構,應避免直接使用uloop_timeout_add()。

uloop_timeout_set()設定定時器超時事件為當前時間+指定超時時間(msecs)。內部封裝了uloop_timeout_add(),應調用本函數添加定時器。

4. uloop_process

當前進程的子進程管理。建立一個鏈表,按進程號升序方式管理所有進程id。

uloop進程管理是一次性任務,觸發后會自動刪除。

struct uloop_process
{
    struct list_head list;
    bool pending;      //是否已經加入任務鏈表等待調度

    uloop_process_handler cb;
    pid_t pid;
};

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

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

 


免責聲明!

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



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