Event Processing Flow
The approximate process for libevent processing time is
1. Set Event_base (i.e. initialize reactor)
2. Setting event events (initializing event)
3. Associating event and Event_base (register event to Event_base)
4. Enter the loop and wait for the event
5. Events occur, handling events.
A UML sequence diagram can be expressed as:
#include <iostream>#include <sys/time.h>#include <event.h>structEvent ev;structTimeval TV;voidTIME_CB (intFd ShortEventvoid* argc) {STD::cout<<"Timer Wakeup"<<STD:: Endl; Event_add (&ev, &TV);}intMain () {structEvent_base* base=event_base_new (); Tv.tv_sec=Ten; Tv.tv_usec=0; Evtimer_set (&ev, TIME_CB, NULL);//Set Timer eventsEvent_base_set (base, &ev);//Associating event and Event_baseEvent_add (&ev, &TV);//Register eventEvent_base_dispatch (base);//Enter loop loop, wait for event return 0;}
First, Event_base was created as reactor, and timer events were set as event. The EV and base are then associated, and the EV is registered with the event dispatcher (Evsel, in event_base). Finally, enter the loop loop and wait for the event to occur.
Check out Event_base_set (base, &ev)
int event_base_set (struct event_base *base , struct event *ev) {/* only innocent events may a Ssigned to a different base */ if (ev->ev_flags! = evlist_init) //ensure that the event has been initialized return (-1 ); _event_debug_assert_is_setup (EV); Ev->ev_base = base ; //set Event_base to event reactor Ev->ev_pri = base ->nactivequeues/2 ; //event priority return (0 );}
You can see that this step simply associates the event with the Event_base, which is the reactor in the event where it is stored.
Take a look at Event_add (&ev, &TV)
int event_add(structeventconststruct timeval *tv){ int res; if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) { event_warnx("%s: event has no event_base set.", __func__); return -1; } EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock); 0);//这里才是主体部分 EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock); return (res);}
Take a look at event_add_internal (EV, TV, 0), omitting part of the code
StaticInlineintEvent_add_internal (struct Event*ev,Const structTimeval *tv,intTv_is_absolute) {structEvent_base *Base= ev->ev_base;intres =0;intnotify =0;if(TV! = NULL &&!) (Ev->ev_flags & Evlist_timeout)) {//TV is not empty and is added to the time heap for time heap expansion if(Min_heap_reserve (&Base->timeheap,1+ Min_heap_size (&Base->TIMEHEAP)) = =-1)return(-1);/ * Enomem = = errno * /}/ * If the event is an IO or signal event and the event has been added or activated, insert into the appropriate queue */ if(Ev->ev_events & (ev_read| ev_write| ev_signal)) &&! (Ev->ev_flags & (evlist_inserted| evlist_active)) {if(Ev->ev_events & (ev_read| Ev_write))//io Eventsres = Evmap_io_add (Base, EV->EV_FD, Ev);//Add to IO event queue Else if(Ev->ev_events & Ev_signal)//Signal Eventsres = Evmap_signal_add (Base, (int) ev->ev_fd, Ev);//Add to signal event queue if(Res! =-1) Event_queue_insert (Base, Ev, evlist_inserted);//Insert an event into the queue Base->eventqueue if(res = =1) {/ * Evmap says we need to notify the main thread. * /notify =1; res =0; }} gettime (Base, &now);//Update time in baseEvent_queue_insert (Base, Ev, evlist_timeout);//Add to timer small Gan / * If we are not in the right thread, we need to wake up the loop * / if(Res! =-1&& Notify && Evbase_need_notify (Base))//If the current thread is not a loop thread, wake loop threads. Evthread_notify_base (Base);return(res);}
Finally look at Event_base_dispatch (base);
int event_base_dispatch(struct event_base *event_base){ return0));}
Take a look at Event_base_loop (event_base, 0)
Intevent_base_loop (structEvent_base *Base, int flags) {conststructEventop *evsel =Base->evsel;//Events Dispatcher event Demultiplexer structTimeval TV;structTimeval *tv_p; int res, Done, retval =0;if(Base->running_loop) {the//loop loop can only be used in the event_base threadEVENT_WARNX ("%s:reentrant invocation. Only one Event_base_loop " "can run on the event_base at once.", __func__); Evbase_release_lock (Base, Th_base_lock);return-1; }Base->running_loop =1;//Indicates that Even_base is running the loop to prevent other threads from runningClear_time_cache (Base);//Position 0 Tv_cache if(Base-Sig. ev_signal_added &&Base-Sig. ev_n_signals_added)//If the signal event is setEvsig_set_base (Base);//Set signal_pair[0] bit signal source Done=0;Base->event_gotterm =Base->event_break =0; while(! Done) {//Enter loop body Base->event_continue =0; /* Terminate the LoopifWe have been asked to*/if(Base->event_gotterm) {break; }if(Base->event_break) {break; } timeout_correct (Base, &TV);//Update TimeTv_p = &tv;if(! N_active_callbacks (Base) &&! (Flags & Evloop_nonblock)) {Timeout_next (Base, &tv_p); }Else{ /* *ifWe have active events, we just pollNewEvents * without waiting. */Evutil_timerclear (&TV); }/* If We have no events, we just exit */if(!event_haveevents (Base) &&! N_active_callbacks (Base) {Event_debug ("%s:no events registered.", __func__)); retval =1; Goto Done;//Using a goto? }/* Update last Old time */gettime (Base, &Base->EVENT_TV); Clear_time_cache (Base); res = Evsel->dispatch (Base, tv_p);//epoll_wait, blocking wait events if(res = =-1) {Event_debug ("%s:dispatch returned unsuccessfully.", __func__)); retval =-1; Goto Done; } update_time_cache (Base); Timeout_process (Base);//processing to-time events if(N_active_callbacks (Base) {int n = event_process_active (Base);//Handling events with priority during processing if(Flags & evloop_once) && n_active_callbacks (Base) ==0&& n! =0) Done=1; }Else if(Flags & Evloop_nonblock) Done=1; } Done:the label used for//gotoClear_time_cache (Base);Base->running_loop =0; Evbase_release_lock (Base, Th_base_lock);return(retval);}
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
Libevent Source Analysis-event processing process