- Timer handling
- Signal Processing
- TIMERFD and SIGNALFD
Timer handling
In the libevent source Analysis-event processing process, the use of timers, to see the source code:
NULL);//设置定时器事件
Where Evtimer_set is a macro definition
#define evtimer_set(ev, cb, arg) event_set((ev), -10, (cb), (arg))//event_set原型event *ev, evutil_socket_t fd, short events, (*callback)(evutil_socket_t, short, void *), void *arg)
You can see the timer event, fd=-1,event=0. An FD-1 event does not occur. When adding an event to Event_base:
event_add(&ev, &tv);//注册事件
You can see that there is a time-out TV. When epoll_wait, there will be a timeout time, timeout.
int epoll_wait(int epfd,structint maxevents,int timeout)
When the timeout is reached, the event has not yet occurred and Epoll_wait will return.
Not so simple in libevent, because there are multiple events monitored, there are many timeouts, and Event_base has a heap that manages timeout
struct min_heap timeheap;
This heap is small Gan. The heap insertion and deletion complexities are log (N). Timer events in the heap are processed after epoll_wait returns
Static voidTimeout_process (structEvent_base *Base){/ * Caller must hold lock. * / structTimeval now;struct Event*ev;if(Min_heap_empty (&Base->timeheap)) {//Heap is empty return; } gettime (Base, &now); while(EV = Min_heap_top (&Base->timeheap)) {if(EVUTIL_TIMERCMP (&ev->ev_timeout, &now, >))//value from heap top, find timeout then process Break;/* Delete This event from the I/O queues */Event_del_internal (EV); Event_debug (("Timeout_process:call%p", Ev->ev_callback)); Event_active_nolock (EV, Ev_timeout,1);//Add time-out to active queue}}
This is the timer handling principle in libevent.
Signal Processing
In libevent, the signal processing is not as simple as a timer. Because the timer can be implemented by waiting timeout, the signal is sent randomly, how to convert to IO?
Using a socket pair in libevent, take a look at a data structure in the Event_base
struct evsig_info {struct event ev_signal; //detection ev_signal_pair[1] Event evutil_socket_t ev_signal_pair[2 ]; //here is a 2 socket FD int ev_signal_added; //signal is registered int ev_n_signals_added; //added a total of several signals #ifdef _event_have_sigaction struct sigaction **sh_old; #else ev_sighandler_t **sh_old; #endif int sh_old_max;/sh_old size};
This data structure ev_signal_pair[2] is the key to converting signal into IO events. This is actually a pair of socket FD, both of which are local at both ends. Ev_signal_pair[0] As the write end, ev_signal_pair[1] as the FD event. When the signal occurs, write ev_signal_pair[0], you can detect ev_signal_pair[1] readable events.
evsig_initInitialize the signal and put the ev_signal_pair[1] socket as a listener. This function calls the evutil_socketpair(
AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) initialization Ev_signal_pair
intEvutil_ersatz_socketpair (intFamilyintTypeintProtocol, evutil_socket_t fd[2]) {evutil_socket_t listener =-1; evutil_socket_t connector =-1; evutil_socket_t acceptor =-1;structSockaddr_in listen_addr;structSockaddr_in connect_addr; ev_socklen_t size;intSaved_errno =-1;if(Protocol | | (Family! = af_inet)) {Evutil_set_socket_error (ERR (Eafnosupport));return-1; }if(!FD) {Evutil_set_socket_error (ERR (EINVAL));return-1; } listener = socket (af_inet, type,0);//Set listen for monitoring if(Listener <0)return-1;memset(&LISTEN_ADDR,0,sizeof(LISTEN_ADDR)); listen_addr.sin_family = af_inet; LISTEN_ADDR.SIN_ADDR.S_ADDR = htonl (Inaddr_loopback);//address is nativeListen_addr.sin_port =0;/ * Kernel chooses port. */ if(Bind (Listener, (structSOCKADDR *) &listen_addr,sizeof(LISTEN_ADDR)) == -1)GotoTidy_up_and_fail;if(Listen (Listener,1) == -1)GotoTidy_up_and_fail; Connector = socket (af_inet, type,0);//Initialize active connection End if(Connector <0)GotoTidy_up_and_fail;/ * We want to find out the port number to connect to. */Size =sizeof(CONNECT_ADDR);if(GetSockName (Listener, (structSOCKADDR *) &connect_addr, &size) = =-1)//Active connection address is native GotoTidy_up_and_fail;if(Size! =sizeof(CONNECT_ADDR))GotoAbort_tidy_up_and_fail;if(Connect (connector,structSOCKADDR *) &connect_addr,//Initiate connection sizeof(CONNECT_ADDR)) == -1)GotoTidy_up_and_fail; Size =sizeof(LISTEN_ADDR); Acceptor = Accept (Listener, (structSOCKADDR *) &listen_addr, &size);//Receive connection if(Acceptor <0)GotoTidy_up_and_fail;if(Size! =sizeof(LISTEN_ADDR))GotoAbort_tidy_up_and_fail;/ * Now check we is talking to ourself by matching port and host on the sockets. */ if(GetSockName (Connector, (structSOCKADDR *) &connect_addr, &size) = =-1)GotoTidy_up_and_fail;if(Size! =sizeof(CONNECT_ADDR) | | Listen_addr.sin_family! = connect_addr.sin_family | | Listen_addr.sin_addr.s_addr! = Connect_addr.sin_addr.s_addr | | Listen_addr.sin_port! = connect_addr.sin_port)GotoAbort_tidy_up_and_fail; Evutil_closesocket (listener); fd[0] = connector;//write-sidefd[1] = acceptor;//wait for each other to write FD return 0;}
This pair of socket pairs transforms the signal event into an IO event.
TIMERFD and SIGNALFDTIMERFD
A new TIMERFD is added to the Linux 2.6 kernel to make timers, which are associated with IO
This section describes the implementation of timers in Muduo. Let's look at a new system call for the 2.6 kernel, which can implement a file descriptor based timer based on these system calls. Can be timed so that the file descriptor is readable at a specific time.
#include <sys/timerfd.h>int timerfd_create(intint flags);int timerfd_settime(intint flags, struct itimerspec *new_value, struct itimerspec *old_value);int timerfd_gettime(intstruct itimerspec *curr_value);
1, Timerfd_create used to create a timer file, the function return value is a file handle FD.
2. Timerfd_settime is used to set a new time-out period and start timing. A flag of 0 indicates a relative time, and 1 represents an absolute time. New_value the new time for this setting, Old_value is the last time set. Returning 0 indicates that the setting was successful.
3. Timerfd_gettime is used to obtain the time remaining for the timer distance from the next time. If the timer has expired at the time of the call and the timer is in loop mode (the struct itimerspec::it_interval is not 0 when the timeout is set), then the timer starts again after calling this function.
Signalfd
Signal is the method of bringing the signal into the IO event system.
#include <sys/signalfd.h>int signalfd(intconstint flags);
Parameter FD: If 1 indicates a new FD; otherwise it should be an existing file descriptor.
Parameter mask: The set of signals detected by this FD.
Parameter flags: Change the behavior of signal ().
Reference
How to use new Linux API-SIGNALFD
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
Libevent source Analysis-timer and signal processing