Libev學習筆記4

2022-02-13 03:23:04 字數 2937 閱讀 7758

這一節首先分析libev的定時器部分,然後分析signal部分。

對定時器的使用主要有兩個函式:

ev_timer_init (&timeout_watcher, timeout_cb, 5.5, 0

.);ev_timer_start (loop, &timeout_watcher);

和ev_io型別的watcher類似,timeout_watcher是乙個型別為ev_timer的watcher,上面的ev_timer_init函式將它設定為5.5秒之後呼叫**函式timeout_cb,最後乙個引數0表示定時器不重複超時,執行完一次**函式後就停止計時,如果最後乙個引數為非0,那麼**函式第一次執行完之後,每個指定秒後**函式會被重複執行。將ev_timer結構體展開:

typedef struct

ev_timer

ev_timer;

其中at成員對應倒數第二個引數,表示多少秒後第一次觸發超時;repeat成員對應最後乙個引數,表示第一次超時觸發之後每個多少秒重複觸發。ev_timer_init函式實質上就是設定上面這些成員。ev_timer_start主要工作是將timer放入最小堆中,由最小堆統一管理所有的timer,**如下:

/*

計算定時器的絕對觸發事件並放入堆中

*/void

noinline

ev_timer_start (ev_p_ ev_timer *w) ev_throw

**首先根據當前時間計算timer超時時刻的絕對時間,然後增加loop管理的timer個數timercnt,修改一些標誌變數,最後把timer放入最小堆timers中,timers使用陣列實現的乙個最小堆,堆頂為離當前最近的乙個timer。

timer定製完畢後就可以呼叫ev_run函式開始event loop了。在ev_run函式中,關於timer的**流程大致如下:

int

ev_run (ev_p_

intflags)

....

/*queue pending timers and reschedule them

*//*

調整堆,取出所有超時的timer

*/timers_reify (ev_a);

/*relative timers called last

*//*

呼叫pendings陣列中watcher的**函式

*/ev_invoke_pending;

}}

根據最小堆timers計算事件驅動機制的阻塞等待時間,阻塞返回後timers_reify函式記錄所有超時的timer,最後由ev_invoke_pending執行這些timer對應的超時**函式。在timers_reify函式中,如果timer是單次觸發型別,那麼會把該timer從最小堆中刪除,如果timer是重複觸發型別,那麼會把該timer重新放入最小堆中,等待下次觸發。

接下來分析訊號部分。libev將對訊號的處理融入到了i/o事件的處理當中。官方文件給出了乙個關於使用signal的例子:

static

void

sigint_cb (

struct ev_loop *loop, ev_signal *w, int

revents)

ev_signal signal_watcher;

ev_signal_init (&signal_watcher, sigint_cb, sigint);

ev_signal_start (loop, &signal_watcher);

ev_signal是專門監控是否有指定訊號發生的watcher。在上面的例子中,當有sigint訊號發生時,執行**函式sigint_cb。ev_signal_init就是初始化ev_signal結構體,包括儲存**函式,儲存需要等待的訊號等。之後呼叫ev_signal_start函式,該函式是理解libev中訊號處理機制的關鍵,它的關鍵**如下:

void

noinline

ev_signal_start (ev_p_ ev_signal *w) ev_throw

}

其中,signals是乙個陣列,陣列元素型別為ansig,它代表訊號,陣列中的乙個元素代表libev需要監控的乙個訊號。在linux中,訊號值是乙個整數,那麼用訊號值作為下標,就能很快找到對應的ansig結構體了。ansig結構體定義如下:

/*

乙個訊號對應乙個ansig

*/typedef

struct

ansig;

所以,ev_signal_start函式主要做了如下幾件事:

在signals陣列中建立乙個新的需要監控的ansig,並設定ansig中的成員;

設定ev_signal這個watcher中的一些成員變數;

呼叫evpipe_init函式,該函式中會生成乙個pipe,evpipe[0]用作讀,evpipe[1]用作寫,然後用ev_io監控evpipe[0];

使用sigaction系統呼叫設定linux中標準的訊號處理函式為ev_sighandler,訊號處理函式中往evpipe[1]寫入乙個位元組。

捕捉訊號

訊號處理函式ev_sighandler被呼叫

在訊號處理函式中向evpipe[1]寫資料

evpipe[0]變為可讀

觸發包裹它的pipe_w事件

pipe_w事件對應的可讀**函式pipecb被呼叫

pipecb函式首先會讀取evpipe[0],然後根據訊號值獲得對應的ansig進而獲得watcher,最後將該watcher放入loop->pendings陣列中

該watcher對應的使用者**函式會在稍後被呼叫

以上就是libev處理訊號的大致流程。可以看出,對訊號的監控最後都同一到了對檔案描述符的監控,也就是最終使用到了ev_io型別的watcher。

參考:

Libev學習筆記3

設定完需要監聽的事件之後,就開始event loop了。在libev中,該工作由ev run函式完成。它的大致流程如下 int ev run ev p intflags return activecnt inline size void fd reify ev p if o reify ev iof...

學習筆記4

第五單元 使用者 使用者組和許可權 1.使用者 a.每乙個使用者建立都會有乙個uid和gid b.所有使用者的資訊儲存在 etc passwd檔案中 c.每乙個能登陸系統的使用者都有乙個可以使用的shell,用cat etc shells命令可以看到可以使用的所有shell 注 其中 bin sh,...

學習筆記 4

結構體定義 typedef struct sqlist sqlist struct sqlist 刪除函式 第一版 bool listdelete sqlist list,int index for int j index j l.length 1 j l.length return true 第二...