libevent源码深度剖析八
libevent源碼深度剖析八
——集成信號(hào)處理
張亮
????? 現(xiàn)在我們已經(jīng)了解了libevent的基本框架:事件管理框架和事件主循環(huán)。上節(jié)提到了libevent中I/O事件和Signal以及Timer事件的集成,這一節(jié)將分析如何將Signal集成到事件主循環(huán)的框架中。
1 集成策略——使用socket pair
?? ?? 前一節(jié)已經(jīng)做了足夠多的介紹了,基本方法就是采用“消息機(jī)制”。在libevent中這是通過socket pair完成的,下面就來詳細(xì)分析一下。
????? Socket pair就是一個(gè)socket對,包含兩個(gè)socket,一個(gè)讀socket,一個(gè)寫socket。工作方式如下圖所示:
???????????????????????????????
??? 創(chuàng)建一個(gè)socket pair并不是復(fù)雜的操作,可以參見下面的流程圖,清晰起見,其中忽略了一些錯(cuò)誤處理和檢查。
???????????????????????????
? ? ? ? ? ? ??
Libevent提供了輔助函數(shù)evutil_socketpair()來創(chuàng)建一個(gè)socket pair,可以結(jié)合上面的創(chuàng)建流程來分析該函數(shù)。
2 集成到事件主循環(huán)——通知event_base
?? ?? Socket pair創(chuàng)建好了,可是libevent的事件主循環(huán)還是不知道Signal是否發(fā)生了啊,看來我們還差了最后一步,那就是:為socket pair的讀socket在libevent的event_base實(shí)例上注冊一個(gè)persist的讀事件。
??? ? 這樣當(dāng)向?qū)憇ocket寫入數(shù)據(jù)時(shí),讀socket就會(huì)得到通知,觸發(fā)讀事件,從而event_base就能相應(yīng)的得到通知了。
前面提到過,Libevent會(huì)在事件主循環(huán)中檢查標(biāo)記,來確定是否有觸發(fā)的signal,如果標(biāo)記被設(shè)置就處理這些signal,這段代碼在各個(gè)具體的I/O機(jī)制中,以Epoll為例,在epoll_dispatch()函數(shù)中,代碼片段如下:
完整的處理框架如下所示:
??? ? ? ?
注1:libevent中,初始化階段并不注冊讀socket的讀事件,而是在注冊信號(hào)階段才會(huì)測試并注冊;
注2:libevent中,檢查I/O事件是在各系統(tǒng)I/O機(jī)制的dispatch()函數(shù)中完成的,該dispatch()函數(shù)在event_base_loop()函數(shù)中被調(diào)用;
3 evsignal_info結(jié)構(gòu)體
????? Libevent中Signal事件的管理是通過結(jié)構(gòu)體evsignal_info完成的,結(jié)構(gòu)體位于evsignal.h文件中,定義如下:
下面詳細(xì)介紹一下個(gè)字段的含義和作用:
1)ev_signal, 為socket pair的讀socket向event_base注冊讀事件時(shí)使用的event結(jié)構(gòu)體;
2)ev_signal_pair,socket pair對,作用見第一節(jié)的介紹;
3)ev_signal_added,記錄ev_signal事件是否已經(jīng)注冊了;
4)evsignal_caught,是否有信號(hào)發(fā)生的標(biāo)記;是volatile類型,因?yàn)樗鼤?huì)在另外的線程中被修改;
5)evsigvents[NSIG],數(shù)組,evsigevents[signo]表示注冊到信號(hào)signo的事件鏈表;
6)evsigcaught[NSIG],具體記錄每個(gè)信號(hào)觸發(fā)的次數(shù),evsigcaught[signo]是記錄信號(hào)signo被觸發(fā)的次數(shù);
7)sh_old記錄了原來的signal處理函數(shù)指針,當(dāng)信號(hào)signo注冊的event被清空時(shí),需要重新設(shè)置其處理函數(shù);
??? evsignal_info的初始化包括,創(chuàng)建socket pair,設(shè)置ev_signal事件(但并沒有注冊,而是等到有信號(hào)注冊時(shí)才檢查并注冊),并將所有標(biāo)記置零,初始化信號(hào)的注冊事件鏈表指針等。
4 注冊、注銷signal事件
????? 注冊signal事件是通過evsignal_add(struct event *ev)函數(shù)完成的,libevent對所有的信號(hào)注冊同一個(gè)處理函數(shù)evsignal_handler(),該函數(shù)將在下一段介紹,注冊過程如下:
1 取得ev要注冊到的信號(hào)signo;
2 如果信號(hào)signo未被注冊,那么就為signo注冊信號(hào)處理函數(shù)evsignal_handler();
3 如果事件ev_signal還沒喲注冊,就注冊ev_signal事件;
4 將事件ev添加到signo的event鏈表中;
從signo上注銷一個(gè)已注冊的signal事件就更簡單了,直接從其已注冊事件的鏈表中移除即可。如果事件鏈表已空,那么就恢復(fù)舊的處理函數(shù);
下面的講解都以signal()函數(shù)為例,sigaction()函數(shù)的處理和signal()相似。
處理函數(shù)evsignal_handler()函數(shù)做的事情很簡單,就是記錄信號(hào)的發(fā)生次數(shù),并通知event_base有信號(hào)觸發(fā),需要處理:
5 小節(jié)
本節(jié)介紹了libevent對signal事件的具體處理框架,包括事件注冊、刪除和socket pair通知機(jī)制,以及是如何將Signal事件集成到事件主循環(huán)之中的。
總結(jié)
以上是生活随笔為你收集整理的libevent源码深度剖析八的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 处理大并发之四 libevent dem
- 下一篇: 结构体与位域的对齐