狠狠撸

狠狠撸Share a Scribd company logo
.

.
    給 GLib 使用者的 libev 簡介



          April 17, 2013




                           . .. .. . . .. .. .. . . .. .. .. . . .. .. .. . . .. . . .. .. .
Event Loop Library




 ? libev 是 event loop library,跟 GLib 的 main event loop 一樣
 ? 支援多種 monitor 機制,如 select, poll, epoll, kqueue
 ? 但是只提供基本的功能,建議依需求再包一層




                                                    .    .    .      . . . . . . . . . . . .               .    .        .    .    .
                                               ..   ..   ..       .. .. .. .. .. .. .. .. .. .. .. .. ..   ..       ..   ..   ..
                        給 GLib 使用者的 libev 簡介                                          April 17, 2013                 2 / 16
常用的 data type


 ? Event loop
     ? ev_loop
       相當於 GMainContext 與 GMainLoop 的合體
 ? Event watcher
     ? ev_io
       相當於 GIOUnixWatch,但要自己處理 EINTR, EAGAIN
     ? ev_timer
       相當於 GTimeoutSource,但時間單位是秒
     ? ev_async
       用於 thread 之間的溝通。跟 GLib 不同,libev 不能在 thread 控制另
       一個 thread 的 ev_loop,要用 ev_async 去溝通



                                                  .    .    .      . . . . . . . . . . . .               .    .        .    .    .
                                             ..   ..   ..       .. .. .. .. .. .. .. .. .. .. .. .. ..   ..       ..   ..   ..
                      給 GLib 使用者的 libev 簡介                                          April 17, 2013                 3 / 16
使用流程



                                   建立 event loop
int main(void) {
    struct ev_loop *loop = .ev_default_loop ( EVBACKEND_EPOLL ) ;
    struct ev_io stdin_w ;
.   ev_io_init (& stdin_w , stdin_cb , STDIN_FILENO , EV_READ );
.   ev_io_start (loop , & stdin_w );
.   ev_run (loop , 0);                     初始化 watcher
    return 0;               註冊 watcher
}        開始 event loop
.




                                                      .    .    .      . . . . . . . . . . . .               .    .        .    .    .
                                                 ..   ..   ..       .. .. .. .. .. .. .. .. .. .. .. .. ..   ..       ..   ..   ..
                          給 GLib 使用者的 libev 簡介                                          April 17, 2013                 4 / 16
Callback function



                               註冊的 watcher,type 依 event 而定
void callback ( struct ev_loop *lo ,
.               struct ev_watcher *w ,
.               int revents );

.                        收到的 event 的 type


    ? 如果要傳入 user data,可以繼承 watcher 的 structure 或是用
      offsetof   計算 data 的位置




                                                       .    .    .      . . . . . . . . . . . .               .    .        .    .    .
                                                  ..   ..   ..       .. .. .. .. .. .. .. .. .. .. .. .. ..   ..       ..   ..   ..
                           給 GLib 使用者的 libev 簡介                                          April 17, 2013                 5 / 16
範例




? 用 ev_timer 實作 GLib timeout
? 建一個 thread 專門處理 timeout event
? 使用 ev_async 與 GAsyncQueue 處理 thread 之間的溝通




                                                  .    .    .      . . . . . . . . . . . .               .    .        .    .    .
                                             ..   ..   ..       .. .. .. .. .. .. .. .. .. .. .. .. ..   ..       ..   ..   ..
                      給 GLib 使用者的 libev 簡介                                          April 17, 2013                 6 / 16
Data types

                                繼承 ev_timer
struct Timeout {
.    struct ev_timer watcher ;
     guint intval ;
     GSourceFunc func;
     gpointer data;
     GDestroyNotify dtor;
};              送給 timeout thread 的訊息
.struct Msg {
     enum {
         MSG_TYPE_ADD ,
         MSG_TYPE_REMOVE ,
         MSG_TYPE_CLEANUP
     } type;
     struct Timeout * timeout ;
};

.
                                                       .    .    .      . . . . . . . . . . . .               .    .        .    .    .
                                                  ..   ..   ..       .. .. .. .. .. .. .. .. .. .. .. .. ..   ..       ..   ..   ..
                           給 GLib 使用者的 libev 簡介                                          April 17, 2013                 7 / 16
Initialization




static ev_loop *loop;
static GAsyncQueue * msg_queue ;
static GThread * timeout_th ;

void timeout_init (void) {
    msg_queue = g_async_queue_new ();
    timeout_th = g_thread_new (" timeout ", main_loop , NULL );
}




                                                       .    .    .      . . . . . . . . . . . .               .    .        .    .    .
                                                  ..   ..   ..       .. .. .. .. .. .. .. .. .. .. .. .. ..   ..       ..   ..   ..
                           給 GLib 使用者的 libev 簡介                                          April 17, 2013                 8 / 16
Timeout thread


                                          event loop 使用 epoll
static gpointer main_loop ( gpointer _) {
.   loop = ev_loop_new ( EVBACKEND_EPOLL );

.   ev_async_init (& msg_watcher , msg_handler );
.   ev_async_start (loop , & msg_watcher );

.   ev_run (loop , 0);            註冊 watcher 處理 thread 之間的溝通
    ev_loop_destroy (loop );
    return NULL;
}                    開始 event loop

.



                                                      .    .    .      . . . . . . . . . . . .               .    .        .    .    .
                                                 ..   ..   ..       .. .. .. .. .. .. .. .. .. .. .. .. ..   ..       ..   ..   ..
                          給 GLib 使用者的 libev 簡介                                          April 17, 2013                 9 / 16
接收及處理訊息



static void msg_handler ( struct ev_loop *lo ,
                          struct ev_async *w, int ev) {
    struct Msg *m;
    while ((m = g_async_queue_try_pop ( msg_queue ))) {
        struct Timeout *t = m-> timeout ;

        // handle message

        g_free (m);
    }
}




                                                        .    .    .      . . . . . . . . . . . .               .    .        .    .    .
                                                   ..   ..   ..       .. .. .. .. .. .. .. .. .. .. .. .. ..   ..       ..   ..   ..
                            給 GLib 使用者的 libev 簡介                                        April 17, 2013              10 / 16
處理訊息
// handle message

switch (m->type) {
case MSG_TYPE_ADD :
.   ev_timer_init (&t->watcher , timeout_cb ,
.                   0., t-> intval / 1000.);
.   ev_timer_again (lo , &t-> watcher );
    break ;                                開始新的 timer
case MSG_TYPE_REMOVE :
.   ev_timer_stop (lo , &t-> watcher );
    if (t->dtor) {
        t->dtor(t->data );        停止 timer
    }
    g_free (t);
    break ;
case MSG_TYPE_CLEANUP :
.   ev_break (lo , EVBREAK_ALL );
    break ;
                             停止 event loop
}
.                                               ..
                                                     .
                                                     ..
                                                          .
                                                          ..
                                                               .      . . . . . . . . . . . .
                                                                   .. .. .. .. .. .. .. .. .. .. .. .. ..
                                                                                                            .
                                                                                                            ..
                                                                                                                 .
                                                                                                                     ..
                                                                                                                          .
                                                                                                                          ..
                                                                                                                               .
                                                                                                                               ..
                                                                                                                                    .


                         給 GLib 使用者的 libev 簡介                                        April 17, 2013              11 / 16
Callback wrapper



static void timeout_cb ( struct ev_loop *lo ,
                         struct ev_timer *w, int ev) {
    struct Timeout *t = ( struct Timeout *)w;

    if (t->func(t->data )) {
.       ev_timer_again (lo , w);
    } else {
        timeout_remove (t); 繼續執行 timer
    }
}

.



                                                     .    .    .      . . . . . . . . . . . .               .    .        .    .    .
                                                ..   ..   ..       .. .. .. .. .. .. .. .. .. .. .. .. ..   ..       ..   ..   ..
                         給 GLib 使用者的 libev 簡介                                        April 17, 2013              12 / 16
Timeout add

struct Timeout * timeout_add ( guint intval ,
                               GSourceFunc func ,
                               gpointer data ,
                               GDestroyNotify dtor) {
    struct Timeout *t = g_malloc0 ( sizeof (*t));
    t-> intval = intval ; t->func = func;
    t->data = data; t->dtor = dtor;

    struct Msg *m = g_malloc0 ( sizeof (*m));
    m->type = MSG_TYPE_ADD ;
    m-> timeout = t;                通知 timeout thread

.   g_async_queue_push (msg_queue , m);
.   ev_async_send (loop , & msg_watcher );

    return t;
}

.
                                                       .    .    .      . . . . . . . . . . . .               .    .        .    .    .
                                                  ..   ..   ..       .. .. .. .. .. .. .. .. .. .. .. .. ..   ..       ..   ..   ..
                           給 GLib 使用者的 libev 簡介                                        April 17, 2013              13 / 16
Timeout remove




void timeout_remove ( struct Timeout *t) {
    struct Msg *m = g_malloc0 ( sizeof (*m));
    m->type = MSG_TYPE_REMOVE ;
    m-> timeout = t;
                                     通知 timeout thread
.   g_async_queue_push (msg_queue , m);
.   ev_async_send (loop , & msg_watcher );
}

.




                                                       .    .    .      . . . . . . . . . . . .               .    .        .    .    .
                                                  ..   ..   ..       .. .. .. .. .. .. .. .. .. .. .. .. ..   ..       ..   ..   ..
                           給 GLib 使用者的 libev 簡介                                        April 17, 2013              14 / 16
Cleanup



void timeout_cleanup (void) {
        struct Msg *m = g_malloc0 ( sizeof (*m));
        m->type = MSG_TYPE_CLEANUP ;        通知 timeout thread

.         g_async_queue_push (msg_queue , m);
.         ev_async_send (loop , & msg_watcher );

        g_thread_join ( timeout_th );
        g_async_queue_unref ( msg_queue );
}

.



                                                        .    .    .      . . . . . . . . . . . .               .    .        .    .    .
                                                   ..   ..   ..       .. .. .. .. .. .. .. .. .. .. .. .. ..   ..       ..   ..   ..
                            給 GLib 使用者的 libev 簡介                                        April 17, 2013              15 / 16
使用 timeout

static gboolean timeout ( GMainLoop *loop) {
    return ! g_main_loop_is_running (loop );
}
int main(void) {
.   timeout_init ();

    GMainLoop *loop = g_main_loop_new (NULL , FALSE );
.   struct Timeout *t = timeout_add (
.       1000 , ( GSourceFunc )timeout ,
.       loop , ( GDestroyNotify ) g_main_loop_quit
.   );

    g_main_loop_run (loop );

.   timeout_cleanup ();
    return 0;
}

                                                      .    .    .      . . . . . . . . . . . .               .    .        .    .    .
                                                 ..   ..   ..       .. .. .. .. .. .. .. .. .. .. .. .. ..   ..       ..   ..   ..
                          給 GLib 使用者的 libev 簡介                                        April 17, 2013              16 / 16

More Related Content

給 GLib 使用者的 libev 簡介

  • 1. . . 給 GLib 使用者的 libev 簡介 April 17, 2013 . .. .. . . .. .. .. . . .. .. .. . . .. .. .. . . .. . . .. .. .
  • 2. Event Loop Library ? libev 是 event loop library,跟 GLib 的 main event loop 一樣 ? 支援多種 monitor 機制,如 select, poll, epoll, kqueue ? 但是只提供基本的功能,建議依需求再包一層 . . . . . . . . . . . . . . . . . . . . .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 給 GLib 使用者的 libev 簡介 April 17, 2013 2 / 16
  • 3. 常用的 data type ? Event loop ? ev_loop 相當於 GMainContext 與 GMainLoop 的合體 ? Event watcher ? ev_io 相當於 GIOUnixWatch,但要自己處理 EINTR, EAGAIN ? ev_timer 相當於 GTimeoutSource,但時間單位是秒 ? ev_async 用於 thread 之間的溝通。跟 GLib 不同,libev 不能在 thread 控制另 一個 thread 的 ev_loop,要用 ev_async 去溝通 . . . . . . . . . . . . . . . . . . . . .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 給 GLib 使用者的 libev 簡介 April 17, 2013 3 / 16
  • 4. 使用流程 建立 event loop int main(void) { struct ev_loop *loop = .ev_default_loop ( EVBACKEND_EPOLL ) ; struct ev_io stdin_w ; . ev_io_init (& stdin_w , stdin_cb , STDIN_FILENO , EV_READ ); . ev_io_start (loop , & stdin_w ); . ev_run (loop , 0); 初始化 watcher return 0; 註冊 watcher } 開始 event loop . . . . . . . . . . . . . . . . . . . . . .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 給 GLib 使用者的 libev 簡介 April 17, 2013 4 / 16
  • 5. Callback function 註冊的 watcher,type 依 event 而定 void callback ( struct ev_loop *lo , . struct ev_watcher *w , . int revents ); . 收到的 event 的 type ? 如果要傳入 user data,可以繼承 watcher 的 structure 或是用 offsetof 計算 data 的位置 . . . . . . . . . . . . . . . . . . . . .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 給 GLib 使用者的 libev 簡介 April 17, 2013 5 / 16
  • 6. 範例 ? 用 ev_timer 實作 GLib timeout ? 建一個 thread 專門處理 timeout event ? 使用 ev_async 與 GAsyncQueue 處理 thread 之間的溝通 . . . . . . . . . . . . . . . . . . . . .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 給 GLib 使用者的 libev 簡介 April 17, 2013 6 / 16
  • 7. Data types 繼承 ev_timer struct Timeout { . struct ev_timer watcher ; guint intval ; GSourceFunc func; gpointer data; GDestroyNotify dtor; }; 送給 timeout thread 的訊息 .struct Msg { enum { MSG_TYPE_ADD , MSG_TYPE_REMOVE , MSG_TYPE_CLEANUP } type; struct Timeout * timeout ; }; . . . . . . . . . . . . . . . . . . . . . .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 給 GLib 使用者的 libev 簡介 April 17, 2013 7 / 16
  • 8. Initialization static ev_loop *loop; static GAsyncQueue * msg_queue ; static GThread * timeout_th ; void timeout_init (void) { msg_queue = g_async_queue_new (); timeout_th = g_thread_new (" timeout ", main_loop , NULL ); } . . . . . . . . . . . . . . . . . . . . .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 給 GLib 使用者的 libev 簡介 April 17, 2013 8 / 16
  • 9. Timeout thread event loop 使用 epoll static gpointer main_loop ( gpointer _) { . loop = ev_loop_new ( EVBACKEND_EPOLL ); . ev_async_init (& msg_watcher , msg_handler ); . ev_async_start (loop , & msg_watcher ); . ev_run (loop , 0); 註冊 watcher 處理 thread 之間的溝通 ev_loop_destroy (loop ); return NULL; } 開始 event loop . . . . . . . . . . . . . . . . . . . . . .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 給 GLib 使用者的 libev 簡介 April 17, 2013 9 / 16
  • 10. 接收及處理訊息 static void msg_handler ( struct ev_loop *lo , struct ev_async *w, int ev) { struct Msg *m; while ((m = g_async_queue_try_pop ( msg_queue ))) { struct Timeout *t = m-> timeout ; // handle message g_free (m); } } . . . . . . . . . . . . . . . . . . . . .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 給 GLib 使用者的 libev 簡介 April 17, 2013 10 / 16
  • 11. 處理訊息 // handle message switch (m->type) { case MSG_TYPE_ADD : . ev_timer_init (&t->watcher , timeout_cb , . 0., t-> intval / 1000.); . ev_timer_again (lo , &t-> watcher ); break ; 開始新的 timer case MSG_TYPE_REMOVE : . ev_timer_stop (lo , &t-> watcher ); if (t->dtor) { t->dtor(t->data ); 停止 timer } g_free (t); break ; case MSG_TYPE_CLEANUP : . ev_break (lo , EVBREAK_ALL ); break ; 停止 event loop } . .. . .. . .. . . . . . . . . . . . . . .. .. .. .. .. .. .. .. .. .. .. .. .. . .. . .. . .. . .. . 給 GLib 使用者的 libev 簡介 April 17, 2013 11 / 16
  • 12. Callback wrapper static void timeout_cb ( struct ev_loop *lo , struct ev_timer *w, int ev) { struct Timeout *t = ( struct Timeout *)w; if (t->func(t->data )) { . ev_timer_again (lo , w); } else { timeout_remove (t); 繼續執行 timer } } . . . . . . . . . . . . . . . . . . . . . .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 給 GLib 使用者的 libev 簡介 April 17, 2013 12 / 16
  • 13. Timeout add struct Timeout * timeout_add ( guint intval , GSourceFunc func , gpointer data , GDestroyNotify dtor) { struct Timeout *t = g_malloc0 ( sizeof (*t)); t-> intval = intval ; t->func = func; t->data = data; t->dtor = dtor; struct Msg *m = g_malloc0 ( sizeof (*m)); m->type = MSG_TYPE_ADD ; m-> timeout = t; 通知 timeout thread . g_async_queue_push (msg_queue , m); . ev_async_send (loop , & msg_watcher ); return t; } . . . . . . . . . . . . . . . . . . . . . .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 給 GLib 使用者的 libev 簡介 April 17, 2013 13 / 16
  • 14. Timeout remove void timeout_remove ( struct Timeout *t) { struct Msg *m = g_malloc0 ( sizeof (*m)); m->type = MSG_TYPE_REMOVE ; m-> timeout = t; 通知 timeout thread . g_async_queue_push (msg_queue , m); . ev_async_send (loop , & msg_watcher ); } . . . . . . . . . . . . . . . . . . . . . .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 給 GLib 使用者的 libev 簡介 April 17, 2013 14 / 16
  • 15. Cleanup void timeout_cleanup (void) { struct Msg *m = g_malloc0 ( sizeof (*m)); m->type = MSG_TYPE_CLEANUP ; 通知 timeout thread . g_async_queue_push (msg_queue , m); . ev_async_send (loop , & msg_watcher ); g_thread_join ( timeout_th ); g_async_queue_unref ( msg_queue ); } . . . . . . . . . . . . . . . . . . . . . .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 給 GLib 使用者的 libev 簡介 April 17, 2013 15 / 16
  • 16. 使用 timeout static gboolean timeout ( GMainLoop *loop) { return ! g_main_loop_is_running (loop ); } int main(void) { . timeout_init (); GMainLoop *loop = g_main_loop_new (NULL , FALSE ); . struct Timeout *t = timeout_add ( . 1000 , ( GSourceFunc )timeout , . loop , ( GDestroyNotify ) g_main_loop_quit . ); g_main_loop_run (loop ); . timeout_cleanup (); return 0; } . . . . . . . . . . . . . . . . . . . . .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 給 GLib 使用者的 libev 簡介 April 17, 2013 16 / 16