In the reactor mode of the previous blog post libevent, we know that an important component of the reactor pattern is the event multicast mechanism (the events demultiplexer). In Libevent, support for the event multiplexing mechanism relies on the multiplexing mechanisms supported by the operating system (SELECT, poll, Epoll, and so on).
Eventop
Libevent defines a top-level struct eventop (event option) to abstract multiple multiplexing mechanisms supported by different operating systems:
//<event_internal.h>
1 /** Structure to define the backend of a given event_base.*/2 structEventop {3 /** The name of this backend.*/4 Const Char*name;5 /** Function to set up a event_base to use this backend. It should6 * Create a new structure holding whatever information is needed to7 * Run the backend, and return it. The returned pointer would get8 * Stored by event_init into the Event_base.evbase field. On Failure,9 * This function should return NULL.*/Ten void* (*init) (structEvent_base *); One /** Enable reading/writing on a given FD or signal. ' Events ' would be A * The events that we ' re trying to enable:one or more of Ev_read, - * Ev_write, ev_signal, and Ev_et. ' Old ' 'll be those events - * were enabled on the this FD previously. ' Fdinfo ' would be a structure the * Associated with the FD by the Evmap; its size was defined by the - * fdinfo field below. It 'll be set to 0 the first time the FD is - * added. The function should return 0 on success and-1 on error. - */ + int(*add) (structEvent_base *, evutil_socket_t FD, ShortOld ShortEventsvoid*fdinfo); - /** as "add", except ' events ' contains the events we mean to disable.*/ + int(*del) (structEvent_base *, evutil_socket_t FD, ShortOld ShortEventsvoid*fdinfo); A /** Function to implement the core of an event loop. It must see which at added events is ready, and cause event_active to is called for each - Active event (usually via event_io_active or such). It should - return 0 on success and-1 on error. - */ - int(*dispatch) (structEvent_base *,structTimeval *); - /** Function-to- clean up and free our data from the event_base.*/ in void(*dealloc) (structEvent_base *); - /** Flag:set If we need to reinitialize the event base after we fork. to */ + intNeed_reinit; - /** Bit-array of supported event_method_features that this backend can the * provide.*/ * enumevent_method_feature features; $ /** Length of the extra information we should record for each FD thatPanax Notoginseng Have one or more active events. This information is recorded - as part of the Evmap entry for each FD, and passed as an argument the To the add and Del functions above. + */ A size_t Fdinfo_len; the};
As you can see, the struct has declared (not defined) The reactor initialization, event addition, event removal, event distribution, and reactor cleanup functions of the multi-channel distribution mechanism, and all are defined in the way of function pointers for ease of reuse.
As Epoll a reuse of the struct:
1 Static void*epoll_init (structEvent_base *);2 Static intEpoll_dispatch (structEvent_base *,structTimeval *);3 Static voidEpoll_dealloc (structEvent_base *);4 5 Static Const struct eventop Epollops_changelist = {6 "Epoll (with Changelist)",7 Epoll_init,8 Event_changelist_add,9 Event_changelist_del,Ten Epoll_dispatch, One Epoll_dealloc, A 1,/*need Reinit*/ -Ev_feature_et|Ev_feature_o1, - event_changelist_fdinfo_size the};
The multiplexing mechanism of the actual invocation
Libevent uses an array to store the multiplexing mechanisms it supports:
1 //<event.c>2 /*Array of backends in order of preference.*/3 Static Const structEventop *eventops[] = {4 #ifdef _event_have_event_ports5&Evportops,6 #endif7 #ifdef _event_have_working_kqueue8&Kqops,9 #endifTen #ifdef _event_have_epoll One&Epollops, A #endif - #ifdef _event_have_devpoll -&Devpollops, the #endif - #ifdef _event_have_poll -&Pollops, - #endif + #ifdef _event_have_select -&Selectops, + #endif A #ifdef WIN32 at&Win32ops, - #endif - NULL -};
Through this program, we can know that libevent is defined by the macro to determine whether the current operating system supports a medium multiplexing mechanism, and in order to select the system support mechanism.
In addition, if we want to know the multiplexing mechanism currently supported by the program, we can call the function Event_get_supported_methods:
1 //<event.c>2 Const Char**3Event_get_supported_methods (void)4 {5 Static Const Char**methods =NULL;6 Const structEventop * *method;7 Const Char**tmp;8 inti =0, K;9 Ten /*count All Methods*/ One for(method = &eventops[0]; *method! = NULL; ++method) { A++i; - } - the /*allocate one more than we need for the NULL pointer*/ -TMP = Mm_calloc ((i +1),sizeof(Char*)); - if(TMP = =NULL) - return(NULL); + - /*populate the array with the supported methods*/ + for(k =0, i =0; EVENTOPS[K]! = NULL; ++k) { Atmp[i++] = eventops[k]->name; at } -Tmp[i] =NULL; - - if(Methods! =NULL) -Mm_free ((Char**) methods); - inMethods =tmp; - to return(methods); +}
To know what kind of multiplexing mechanism the program actually calls, we can call the function Event_get_method to get:
1 // <event.c> 2 Const Char *3 event_get_method (void)4{5 Return (current_base->evsel->name); 6 }
The Eventop of Libevent