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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

libevent源码深度剖析八

發(fā)布時(shí)間:2025/3/21 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 libevent源码深度剖析八 小編覺得挺不錯(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中這是通過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ù)中,代碼片段如下:

[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中,初始化階段并不注冊讀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文件中,定義如下:

    [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注冊讀事件時(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ā),需要處理:

    [cpp] view plain copy
  • static?void?evsignal_handler(int?sig)??
  • {??
  • ????int?save_errno?=?errno;?//?不覆蓋原來的錯(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);?//?重新注冊信號(hào)??
  • #endif??
  • ????//?向?qū)憇ocket寫一個(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對signal事件的具體處理框架,包括事件注冊、刪除和socket pair通知機(jī)制,以及是如何將Signal事件集成到事件主循環(huán)之中的。


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

    總結(jié)

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

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