日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

libevent源码深度剖析八

發(fā)布時(shí)間:2025/3/21 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 libevent源码深度剖析八 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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中這是通過(guò)socket pair完成的,下面就來(lái)詳細(xì)分析一下。
????? Socket pair就是一個(gè)socket對(duì),包含兩個(gè)socket,一個(gè)讀socket,一個(gè)寫(xiě)socket。工作方式如下圖所示:
???????????????????????????????

??? 創(chuàng)建一個(gè)socket pair并不是復(fù)雜的操作,可以參見(jiàn)下面的流程圖,清晰起見(jiàn),其中忽略了一些錯(cuò)誤處理和檢查。

???????????????????????????
? ? ? ? ? ? ??
Libevent提供了輔助函數(shù)evutil_socketpair()來(lái)創(chuàng)建一個(gè)socket pair,可以結(jié)合上面的創(chuàng)建流程來(lái)分析該函數(shù)。

2 集成到事件主循環(huán)——通知event_base

?? ?? Socket pair創(chuàng)建好了,可是libevent的事件主循環(huán)還是不知道Signal是否發(fā)生了啊,看來(lái)我們還差了最后一步,那就是:為socket pair的讀socket在libevent的event_base實(shí)例上注冊(cè)一個(gè)persist的讀事件。
??? ? 這樣當(dāng)向?qū)憇ocket寫(xiě)入數(shù)據(jù)時(shí),讀socket就會(huì)得到通知,觸發(fā)讀事件,從而event_base就能相應(yīng)的得到通知了。
前面提到過(guò),Libevent會(huì)在事件主循環(huán)中檢查標(biāo)記,來(lái)確定是否有觸發(fā)的signal,如果標(biāo)記被設(shè)置就處理這些signal,這段代碼在各個(gè)具體的I/O機(jī)制中,以Epoll為例,在epoll_dispatch()函數(shù)中,代碼片段如下:

[cpp] view plain copy
  • res?=?epoll_wait(epollop->epfd,?events,?epollop->nevents,?timeout);??
  • if?(res?==?-1)?{??
  • ????if?(errno?!=?EINTR)?{??
  • ????????event_warn("epoll_wait");??
  • ????????return?(-1);??
  • ????}??
  • ????evsignal_process(base);//?處理signal事件??
  • ????return?(0);??
  • }?else?if?(base->sig.evsignal_caught)?{??
  • ????evsignal_process(base);//?處理signal事件??
  • }??


  • 完整的處理框架如下所示:
    ??? ? ? ?
    注1:libevent中,初始化階段并不注冊(cè)讀socket的讀事件,而是在注冊(cè)信號(hào)階段才會(huì)測(cè)試并注冊(cè);
    注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事件的管理是通過(guò)結(jié)構(gòu)體evsignal_info完成的,結(jié)構(gòu)體位于evsignal.h文件中,定義如下:

    [cpp] view plain copy
  • struct?evsignal_info?{??
  • ????struct?event?ev_signal;??
  • ????int?ev_signal_pair[2];??
  • ????int?ev_signal_added;??
  • ????volatile?sig_atomic_t?evsignal_caught;??
  • ????struct?event_list?evsigevents[NSIG];??
  • ????sig_atomic_t?evsigcaught[NSIG];??
  • #ifdef?HAVE_SIGACTION??
  • ????struct?sigaction?**sh_old;??
  • #else??
  • ????ev_sighandler_t?**sh_old;??
  • #endif??
  • ????int?sh_old_max;??
  • };??

  • 下面詳細(xì)介紹一下個(gè)字段的含義和作用:
    1)ev_signal, 為socket pair的讀socket向event_base注冊(cè)讀事件時(shí)使用的event結(jié)構(gòu)體;
    2)ev_signal_pair,socket pair對(duì),作用見(jiàn)第一節(jié)的介紹;
    3)ev_signal_added,記錄ev_signal事件是否已經(jīng)注冊(cè)了;
    4)evsignal_caught,是否有信號(hào)發(fā)生的標(biāo)記;是volatile類型,因?yàn)樗鼤?huì)在另外的線程中被修改;
    5)evsigvents[NSIG],數(shù)組,evsigevents[signo]表示注冊(cè)到信號(hào)signo的事件鏈表;
    6)evsigcaught[NSIG],具體記錄每個(gè)信號(hào)觸發(fā)的次數(shù),evsigcaught[signo]是記錄信號(hào)signo被觸發(fā)的次數(shù);
    7)sh_old記錄了原來(lái)的signal處理函數(shù)指針,當(dāng)信號(hào)signo注冊(cè)的event被清空時(shí),需要重新設(shè)置其處理函數(shù);
    ??? evsignal_info的初始化包括,創(chuàng)建socket pair,設(shè)置ev_signal事件(但并沒(méi)有注冊(cè),而是等到有信號(hào)注冊(cè)時(shí)才檢查并注冊(cè)),并將所有標(biāo)記置零,初始化信號(hào)的注冊(cè)事件鏈表指針等。

    4 注冊(cè)、注銷signal事件

    ????? 注冊(cè)signal事件是通過(guò)evsignal_add(struct event *ev)函數(shù)完成的,libevent對(duì)所有的信號(hào)注冊(cè)同一個(gè)處理函數(shù)evsignal_handler(),該函數(shù)將在下一段介紹,注冊(cè)過(guò)程如下:
    1 取得ev要注冊(cè)到的信號(hào)signo;
    2 如果信號(hào)signo未被注冊(cè),那么就為signo注冊(cè)信號(hào)處理函數(shù)evsignal_handler();
    3 如果事件ev_signal還沒(méi)喲注冊(cè),就注冊(cè)ev_signal事件;
    4 將事件ev添加到signo的event鏈表中;
    從signo上注銷一個(gè)已注冊(cè)的signal事件就更簡(jiǎn)單了,直接從其已注冊(cè)事件的鏈表中移除即可。如果事件鏈表已空,那么就恢復(fù)舊的處理函數(shù);
    下面的講解都以signal()函數(shù)為例,sigaction()函數(shù)的處理和signal()相似。
    處理函數(shù)evsignal_handler()函數(shù)做的事情很簡(jiǎn)單,就是記錄信號(hào)的發(fā)生次數(shù),并通知event_base有信號(hào)觸發(fā),需要處理:

    [cpp] view plain copy
  • static?void?evsignal_handler(int?sig)??
  • {??
  • ????int?save_errno?=?errno;?//?不覆蓋原來(lái)的錯(cuò)誤代碼??
  • ????if?(evsignal_base?==?NULL)?{??
  • ????????event_warn("%s:?received?signal?%d,?but?have?no?base?configured",?__func__,?sig);??
  • ????????return;??
  • ????}??
  • ????//?記錄信號(hào)sig的觸發(fā)次數(shù),并設(shè)置event觸發(fā)標(biāo)記??
  • ????evsignal_base->sig.evsigcaught[sig]++;??
  • ????evsignal_base->sig.evsignal_caught?=?1;??
  • #ifndef?HAVE_SIGACTION??
  • ????signal(sig,?evsignal_handler);?//?重新注冊(cè)信號(hào)??
  • #endif??
  • ????//?向?qū)憇ocket寫(xiě)一個(gè)字節(jié)數(shù)據(jù),觸發(fā)event_base的I/O事件,從而通知其有信號(hào)觸發(fā),需要處理??
  • ????send(evsignal_base->sig.ev_signal_pair[0],?"a",?1,?0);??
  • ????errno?=?save_errno;?//?錯(cuò)誤代碼??
  • }??


  • 5 小節(jié)
    本節(jié)介紹了libevent對(duì)signal事件的具體處理框架,包括事件注冊(cè)、刪除和socket pair通知機(jī)制,以及是如何將Signal事件集成到事件主循環(huán)之中的。


    《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀

    總結(jié)

    以上是生活随笔為你收集整理的libevent源码深度剖析八的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。