1. 程式人生 > >【libevent】原始碼分析(4)--與event相關的一些函式和操作

【libevent】原始碼分析(4)--與event相關的一些函式和操作

        Libevent提供了一些與event相關的操作函式和操作。本文就重點講一下這方面的原始碼。

        在Libevent中,無論是event還是event_base,都是使用指標而不會使用變數。實際上,如果檢視Libevent不同的版本,就可以發現event和event_base這兩個結構體的成員是不同的。對比libevent-2.0.21-stable和libevent-1.4.13-stable這兩個版本,就可以發現其具有相當大的區別。

event的引數:

        一個event結構體和很多東西相關聯,比如event_base、檔案描述符fd、回撥函式、回撥引數等等,下文把這些東西統一稱為引數

。這些引數都是在呼叫event_new建立一個event時指定的。如果在後面需要再次獲取這些引數時,可以通過一些函式來獲取,而不應該直接訪問event結構體的成員。

  1. //event.c檔案
  2. evutil_socket_t //監聽的檔案描述符fd
  3. event_get_fd(conststruct event *ev)  
  4. {  
  5.     return ev->ev_fd;  
  6. }  
  7. struct event_base * //獲取event_base
  8. event_get_base(conststruct event *ev)  
  9. {  
  10.     return
     ev->ev_base;  
  11. }  
  12. short//獲取該event監聽的事件
  13. event_get_events(conststruct event *ev)  
  14. {  
  15.     return ev->ev_events;  
  16. }  
  17. event_callback_fn //獲取回撥函式的函式指標
  18. event_get_callback(conststruct event *ev)  
  19. {  
  20.     return ev->ev_callback;  
  21. }  
  22. void * //獲取回撥函式引數
  23. event_get_callback_arg(conststruct
     event *ev)  
  24. {  
  25.     return ev->ev_arg;  
  26. }  
  27. void//一個函式獲取所有
  28. event_get_assignment(conststruct event *event, struct event_base **base_out, evutil_socket_t *fd_out,   
  29.                     short *events_out, event_callback_fn *callback_out, void **arg_out)  
  30. {  
  31.     if (base_out)  
  32.         *base_out = event->ev_base;  
  33.     if (fd_out)  
  34.         *fd_out = event->ev_fd;  
  35.     if (events_out)  
  36.         *events_out = event->ev_events;  
  37.     if (callback_out)  
  38.         *callback_out = event->ev_callback;  
  39.     if (arg_out)  
  40.         *arg_out = event->ev_arg;  
  41. }  

        前面的那些函式是獲取單個引數的,最後那個函式可以同時獲取多個引數。並且如果不想獲取某個引數,可以對應地傳入一個NULL。

event的狀態:

        一個event是可以有多個狀態的,比如已初始化狀態(initialized)、未決狀態(pending)、啟用狀態(active)。

        可以用event_initialized函式檢測一個event是否處於已初始化狀態:

  1. //event.c檔案
  2. int
  3. event_initialized(conststruct event *ev)  
  4. {  
  5.     if (!(ev->ev_flags & EVLIST_INIT))  
  6.         return 0;  
  7.     return 1;  
  8. }  

        可以看到event_initialized只是檢查event的ev_flags是否有EVLIST_INIT標誌。從之前的博文可以知道,當用戶呼叫event_new後,就會為event加入該標誌,所以用event_new建立的even都是處於已初始化狀態的。

        當用戶呼叫event_new建立一個event後,它還沒處於未決狀態(non-pending),當用戶呼叫event_add函式,將一個event插入到event_base佇列後,就處於未決狀態(pending)。

        如果event監聽的事件發生了或者超時了,那麼該event就會被啟用,處於啟用狀態。當event的回撥函式被呼叫後,它就不再是啟用狀態了,但還是處於未決狀態。如果使用者呼叫了event_del或者event_free(該函式內部呼叫event_del),那麼該event就不再是未決狀態了。

        可以呼叫event_pending函式來檢查event處於哪種事件的未決狀態。但是該函式不僅僅會檢查event的未決狀態,還會檢查event的啟用狀態。名不副實啊!!下面就看一下這個函式吧。
  1. //event.c檔案
  2. int
  3. event_pending(conststruct event *ev, short event, struct timeval *tv)  
  4. {  
  5.     int flags = 0;  
  6.     if (EVUTIL_FAILURE_CHECK(ev->ev_base == NULL)) {  
  7.         event_warnx("%s: event has no event_base set.", __func__);  
  8.         return 0;  
  9.     }  
  10.     EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);  
  11.     //flags記錄使用者監聽了哪些事件
  12.     if (ev->ev_flags & EVLIST_INSERTED)  
  13.         flags |= (ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL));  
  14.     //flags記錄event被什麼事件激活了.使用者可以呼叫event_active
  15.     //手動啟用event,並且可以使用之前使用者沒有監聽的事件作為啟用原因
  16.     if (ev->ev_flags & EVLIST_ACTIVE)  
  17.         flags |= ev->ev_res;  
  18.     //記錄該event是否還有超時屬性
  19.     if (ev->ev_flags & EVLIST_TIMEOUT)  
  20.         flags |= EV_TIMEOUT;  
  21.     //event可以被使用者亂設值,然後作為引數。這裡為了保證
  22.     //其值只能是下面的事件。
  23.     event &= (EV_TIMEOUT|EV_READ|EV_WRITE|EV_SIGNAL);  
  24.     /* See if there is a timeout that we should report */
  25.     if (tv != NULL && (flags & event & EV_TIMEOUT)) {  
  26.         struct timeval tmp = ev->ev_timeout;  
  27.         tmp.tv_usec &= MICROSECONDS_MASK;  
  28. #if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
  29.         /* correctly remamp to real time */
  30.         evutil_timeradd(&ev->ev_base->tv_clock_diff, &tmp, tv);  
  31. #else
  32.         *tv = tmp;  
  33. #endif
  34.     }  
  35.     EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);  
  36.     return (flags & event);  
  37. }  

        該函式的作用是檢查某個事件(由第二個引數指定)是否處於未決或者啟用狀態。

        由flags的幾個 |= 操作可知,它會把event監聽的事件種類都記錄下來。並且還會把event被啟用的原因(也是一個事件)記錄下來。下面會講到手動啟用一個event。所以event可能會被一個沒有監聽的事件鎖啟用。

        如果該函式的第三個引數不為NULL,並且使用者之前也讓這個event監聽了超時事件,而且使用者在第二個引數中指明瞭要檢查超時事件,那麼將第三個引數將被賦值為該event的下次超時時間(絕對時間)。

        event_pending函式的一個作用是可以判斷一個event是否已經從event_base中刪除了。比如說,某個event監聽寫事件而加入了event_base,但可能在某個時刻被刪除。那麼可以用下面的程式碼判斷這個event是否已經被刪除了。

  1. if( event_pending(ev, EV_WRITE, NULL) == 0 )  
  2.     printf("delete\n");  
  3. else
  4.     printf("no delete\n");  


手動啟用event:

        除了執行event_base_dispatch死等外界條件把event啟用外,Libevent還提供了一個API函式event_active,可以手動地把一個event啟用。

相關推薦

libevent原始碼分析4--event相關一些函式操作

        Libevent提供了一些與event相關的操作函式和操作。本文就重點講一下這方面的原始碼。         在Libevent中,無論是event還是event_base,都是使用指標而不會使用變數。實際上,如果檢視Libeve

Java定時任務Timer排程器 原始碼分析圖文詳解版

就以鬧鐘的例子開頭吧(後續小節皆以鬧鐘為例,所有原始碼只列關鍵部分)。 public class ScheduleDemo { public static void main(String[] args) throws InterruptedException {

原創案例分享4定位分析--見證scala的強大

一 場景分析 定位分析廣泛應用,比如室外基站定位,室內藍芽beacon定位,室內wifi探針定位等,實現方式是三點定位 Trilateration 理想情況   這種理想情況要求3個基站‘同時’採集‘準確’的距離資訊, 實際情況 3個基站採集資料的時間是分開的; 採集資料的距離

Go學習之go-ethereum以太坊原始碼分析

關於Go語言環境的安裝與配置,我在《入門篇》進行了詳細講解,有需要的朋友可以前往閱讀,本文進入當下比較火熱的區塊鏈專案 - 以太坊(go-ethereum)進行原始碼解讀。本文內容純屬個人見解,有錯誤理解或者不足之處還請見諒,歡迎一起交流學習。    - 環境準備    -

Mybatis原始碼分析4—— Mapper的建立獲取

Mybatis我們一般都是和Spring一起使用的,它們是怎麼融合到一起的,又各自發揮了什麼作用? 就拿這個Mapper來說,我們定義了一個介面,聲明瞭一個方法,然後對應的xml寫了這個sql語句, 它怎麼就執行成功了?這傢伙是怎麼實現的,帶著這個好奇心,我一步步跟蹤,慢慢揭開了它的

JDK原始碼分析4HashMap

JDK版本 HashMap簡介 HashMap基於雜湊表的 Map 介面的實現。此實現提供所有可選的對映操作,並允許使用 null 值和 null 鍵。(除了不同步和允許使用 null 之外,HashMap 類與 Hashtable 大致相同。)此類不保證對映

springcloud feign原始碼分析4——來看看將@FeignClient介面構造為bean的過程以及是如何註冊到容器裡的

接著上一篇,繼續來看 registerFeignClient() 方法 這邊一看就是在構造構造一個BeanDefiniction的東西,這個東西的話,構造的過程,其實就是用了構造器模式,這個構造器模式呢,就會將@FeignClient註解的屬性以及ServiceAClien

JDK原始碼分析4HashSet

JDK版本 HashSet簡介 HashSet特點 非執行緒安全 允許null值 新增值得時候會先獲取物件的hashCode方法,如果hashCode 方法返回的值一致,則再呼叫equals方法判斷是否一致,如果不一致才add元素。 注意: 對於HashSet中儲存的物件,請注意正確重

原創演算法分享4Cardinality Estimate 基數計數概率演算法

讀過《程式設計珠璣》(<Programming Pearls>)的人應該還對開篇的Case記憶猶新,大概的場景是: 作者的一位在電話公司工作的朋友想要統計一段時間內不同的電話號碼的個數,電話號碼的數量很大,當時的記憶體很小,所以不能把所有的電話號碼全部放到記憶體來去重統計,他的朋友很苦惱。 作

Django rest framework原始碼分析4----版本

目錄 版本  新建一個工程Myproject和一個app名為api (1)api/models.py from django.db import models class UserInfo(models.Model): USER_TYPE = ( (1,'普通

Spring原始碼分析4---BeanFactoryPostProcessor看見的不一定是真的

在第二編對BeanFactory的分析中,我們老能看見BeanFactoyPostProcessor的身影,那麼在這一節中,我們來詳細的討論一下BeanFactoryPostProcessor的程式碼結構,從中學習他的優秀之處;BeanFactoryPostProcessor

Kafka原始碼分析4

四、Replication Subsystem 1、Replica Replica是kafka分發資料的最小單元,主要程式碼如下: class Replica(val brokerId: Int, val partition: Partiti

HLS學習HLSDownloader原始碼分析4解析Master PlayList

解析Master PlayList     PlayList就是m3u8檔案或者索引檔案,Master PlayList也叫一級索引檔案。 解析Master PlayList的過程如下: 1、

取模mod取余rem的區別——Matlab學習筆記

學習筆記 ear inf ace 方向 由於 返回 rem pos 昨天在學習Matlab的數學函數時,教程中提到取模(mod)與取余(rem)是不同的,今天在網上具體查了一下: 通常取模運算也叫取余運算,它們返回結果都是余數.rem和mod唯一的區別在於:

Flume NG原始碼分析使用Event介面表示資料流

Flume NG有4個主要的元件: Event表示在Flume各個Agent之間傳遞的資料流 Source表示從外部源接收Event資料流,然後傳遞給Channel Channel表示對從Source傳遞的Event資料流的臨時儲存 Sink表示從Channel中接收儲存的Event

MVC.Net實踐—建立mvc框架的專案實體模型

一、 建立MVC框架的專案 (1)像新增平常專案一樣新增一個web應用程式,檔案—>新建—>專案 (3)接著選擇MVC (4)這樣就建好一個MVC框架的專案了 二、連線資料庫 建立

Weka原始碼分析1逆向工程Eclipse外掛ObjectAidAmaterasUML的安裝方法

    為了更好的分析Weka原始碼中各個類之間的關係,需要根據.java檔案將各個類之間的關係以UML中的類圖(Class diagram)的形式展示出來。在眾多可以實現逆向工程的Eclipse UML外掛中,我覺得AmaterasUML和ObjectAid是相對比較理想

Spring原始碼分析——AOP、DI、IOCIOC容器原理

面向切面程式設計(Aspect Oriented Programming):面向切面程式設計也可以稱為面向規則程式設計,其目的是為了將多個類中具有一定規律性的程式碼在開發時將其按一定規則拆分後各自獨立編

取模mod取餘rem的區別——Matlab學習筆記

對於整數a,b來說,取模運算或者求餘運算的方法要分如下兩步: 1.求整數商:c=a/b 2.計算模或者餘數:r=a-(c*b) 求模運算和求餘運算在第一步不同 取餘運算在計算商值向0方向捨棄小數位 取模運算在計算商值向負無窮方向捨棄小數位 例如:4/(-3)約等於-1.3 在

6Mat物件的一些函式方法的使用

首先是基本的程式碼整理 1 #include<iostream> 2 #include<opencv.hpp> 3 4 using namespace std; 5 using namespace cv; 6 int main() 7 { 8 Mat