Event_add Append the event to the Ev_base in the current event, and the TV cannot be empty if it needs to be timed
Intevent_add (struct event *ev, const struct Timeval *tv) {struct Event_base *base = ev->ev_base; Event_add will add the event to his ev_base member. Const struct EVENTOP *evsel = base->evsel; Epoll related function void *evbase = base->evbase; for Linux The corresponding Linux is a struct epollop/* struct Epollop * {* struct evepoll *fds; Assign Nfiles evepoll object * int Nfds; Maximum supported soft limit number of handles (number of arrays above) * struct epoll_event* events; Assign Nfiles (soft limit number) Epoll_event object * int nevents; Nevents holds the above events number * int EPFD; Holds Epoll_create's handle *} */int res = 0;event_debug ("event_add:event:%p,%s%s%scall%p", Ev, Ev->ev_events & Amp Ev_read? "Ev_read": "", Ev->ev_events & Ev_write? " Ev_write ":" ", TV?" Ev_timeout ":", "Ev->ev_callback"); Assert (!) ( Ev->ev_flags & ~evlist_all); if (TV! = NULL &&!) ( Ev->ev_flags & EvliSt_timeout) {if (Min_heap_reserve (&base->timeheap,1 + min_heap_size (&base->timeheap)) = =-1) return (-1 ); /* Enomem = = errno */}if (ev->ev_events & (ev_read| ev_write| ev_signal)) &&! (Ev->ev_flags & (evlist_inserted| evlist_active)) {res = Evsel->add (evbase, Ev); Register or modify the event to Epoll if (res! =-1) event_queue_insert (base, Ev, evlist_inserted); Insert EV into EVENTQEUE}/* * If the Insert event is successfully set timeout time */if (res! =-1 && TV! = NULL) {struct timeval now; /* * If the time-out is already present, delete this timeout node */if (Ev->ev_flags & evlist_timeout) Event_queue_remove (base, Ev, Ev List_timeout);/* Check if it is active due to a TIMEOUT. Rescheduling * This timeout before the callback can is executed * removes it from the active list. */if ((Ev->ev_flags & evlist_active) && (Ev->ev_res & Ev_timeout)) {/* see if we are just ACTIVE Executing this * event in a loop */if (Ev->ev_ncalls && Ev->ev_pncaLLS) {/* Abort loop */*ev->ev_pncalls = 0;} Event_queue_remove (base, Ev, evlist_active);} GetTime (base, &now); Evutil_timeradd (&now, TV, &ev->ev_timeout); Event_debug (("Event_add:timeout in% LD seconds, call%p ", Tv->tv_sec, Ev->ev_callback)); Event_queue_insert (base, Ev, evlist_timeout);//Add to the minimum timeout heap} return (RES);If the newly added event is not empty and the current event is not a timeout time, allocate a free space on the minimum heap (if the smallest heap has space, it will not be reassigned)
About the minimum heap can be connected to my githup,libevent manage timed events with minimal heap, the root node is always the smallest and the algorithm time is minimal
If the event is Ev_read, Ev_write, ev_signal, and the event is not inserted or activated, then join the event
Taking Epoll as an example
Static Intepoll_add (void *arg, struct event *ev) {struct Epollop *epollop = arg;struct epoll_event Epev = {0, {0}};struct E Vepoll *evep;int FD, OP, events; /* * Signal principle * 1 Set the signal processing function, save the original signal processing function to the ev_base->sh_old of the event * 2 if it is the first time to add a signal, then you need to append a signal event source for all signals from EVENT->EV_ Base->ev_signal * Also set event->ev_base->ev_signal->ev_signal_added, indicating that the signal callback event has been set to * 3 simultaneously append the event to the Event-> Ev_base->ev_signal->evsigevents[signno] Linked list */if (ev->ev_events & ev_signal)//If the signal is added return (Evsigna L_add (EV)); fd = ev->ev_fd;if (fd >= Epollop->nfds) {/* Extent the file descriptor array as necessary */// If the current epoll has not satisfied the newly added handle if (Epoll_recalc (ev->ev_base, epollop, fd) = =-1) return (-1);} EVEP = &epollop->fds[fd];op = epoll_ctl_add;events = 0; If the event was preceded by a readable if (evep->evread! = NULL) {events |= epollin;op = Epoll_ctl_mod;} If the event is preceded by a writable if (evep->evwrite! = NULL) {events |= epollout;op = Epoll_ctl_mod;} The new join event is set to a readable event if (ev->ev_eveNTS & Ev_read) events |= Epollin; The new join event setting is writable event if (Ev->ev_events & ev_write) events |= epollout;epev.data.ptr = evep;epev.events = Events;if ( Epoll_ctl (EPOLLOP->EPFD, op, ev->ev_fd, &epev) = =-1) return ( -1);/* Update Events Responsible */if (ev->ev_e Vents & ev_read) Evep->evread = Ev;if (ev->ev_events & ev_write) evep->evwrite = Ev;return (0);}
signal addition, libevent to signal using Sockpair create two interconnect sockets, signal excitation write writable sock, can be read into the event loop
According to the signal Ev_base->sig.evsigcaught[signumber] to determine whether the signal occurs, the following is the signal addition function
Intevsignal_add (struct event *ev) {int evsignal;struct event_base *base = ev->ev_base; Signal Event basestruct Evsignal_info *sig = &ev->ev_base->sig; Signal in EV_BASE management structure if (Ev->ev_events & (ev_read| Ev_write)//signal events do not support readable writable events Event_errx (1, "%s:ev_signal incompatible use", __func__); evsignal = Event_signal (EV); The signal FD is the signal numberassert (evsignal >= 0 && evsignal < NSIG); The signal cannot exceed nsig this number if (Tailq_empty (&sig->evsigevents[evsignal])) {//If the signal list is empty Event_debug ("%s:%p:changing Signal handler ", __func__, Ev)); Set the signal processing function, while saving the original signal processing function to Ev_base->sh_old if (_evsignal_set_handler (base, evsignal, evsignal_handler) = =-1) return ( -1);/* Catch Signals if they happen quickly */evsignal_base = base;if (!sig->ev_signal_added) {if (Event_add (&A Mp;sig->ev_signal, NULL)) return ( -1); sig->ev_signal_added = 1; Join epoll_wait}}//Add Ev->ev_signal_next to the end of the list of sig->evsigevents[evsignal]* Multiple Events listen to the same signal */tailq_insert_tail (&sig->evsigevents[evsignal], Ev, Ev_signal_nex t); return (0);}
Signal callback function
/* * All signals are generic one signal processing function */static Voidevsignal_handler (int sig) {int save_errno = errno; Save error code if (evsignal_base = = NULL) {Event_warn ("%s:received signal%d, but has no base configured", __func__, SIG); return; }evsignal_base->sig.evsigcaught[sig]++; The resulting signal number++evsignal_base->sig.evsignal_caught = 1; Set the signal flag indicating that the signal has been triggered #ifndef have_sigactionsignal (SIG, Evsignal_handler); #endif/* Wake up our notification mechanism */ Send (Evsignal_base->sig.ev_signal_pair[0], "a", 1, 0); Write data by writing Sockpair to trigger epoll_wait return errno = Save_errno;}
The timing event adopts minimum heap, timing value + Current event Most Left post timeout time, added to the minimum heap, mainly used in Event_base_dispatch
Libeven The entire source code analysis and sample are in my githup
[libevent Source analysis] Event_add