xref: /redis-3.2.3/src/ae.c (revision 80586cb8)
1 /* A simple event-driven programming library. Originally I wrote this code
2  * for the Jim's event-loop (Jim is a Tcl interpreter) but later translated
3  * it in form of a library for easy reuse.
4  *
5  * Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  *   * Redistributions of source code must retain the above copyright notice,
12  *     this list of conditions and the following disclaimer.
13  *   * Redistributions in binary form must reproduce the above copyright
14  *     notice, this list of conditions and the following disclaimer in the
15  *     documentation and/or other materials provided with the distribution.
16  *   * Neither the name of Redis nor the names of its contributors may be used
17  *     to endorse or promote products derived from this software without
18  *     specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <stdio.h>
34 #include <sys/time.h>
35 #include <sys/types.h>
36 #include <unistd.h>
37 #include <stdlib.h>
38 
39 #include "ae.h"
40 #include "zmalloc.h"
41 #include "config.h"
42 
43 /* Include the best multiplexing layer supported by this system.
44  * The following should be ordered by performances, descending. */
45 #ifdef HAVE_EPOLL
46 #include "ae_epoll.c"
47 #else
48     #ifdef HAVE_KQUEUE
49     #include "ae_kqueue.c"
50     #else
51     #include "ae_select.c"
52     #endif
53 #endif
54 
55 aeEventLoop *aeCreateEventLoop(int setsize) {
56     aeEventLoop *eventLoop;
57     int i;
58 
59     if ((eventLoop = zmalloc(sizeof(*eventLoop))) == NULL) return NULL;
60     eventLoop->events = NULL;
61     eventLoop->fired = NULL;
62     eventLoop->events = zmalloc(sizeof(aeFileEvent)*setsize);
63     eventLoop->fired = zmalloc(sizeof(aeFiredEvent)*setsize);
64     if (eventLoop->events == NULL || eventLoop->fired == NULL) {
65         zfree(eventLoop->events);
66         zfree(eventLoop->fired);
67         zfree(eventLoop);
68         return NULL;
69     }
70     eventLoop->setsize = setsize;
71     eventLoop->timeEventHead = NULL;
72     eventLoop->timeEventNextId = 0;
73     eventLoop->stop = 0;
74     eventLoop->maxfd = -1;
75     eventLoop->beforesleep = NULL;
76     if (aeApiCreate(eventLoop) == -1) {
77         zfree(eventLoop);
78         return NULL;
79     }
80     /* Events with mask == AE_NONE are not set. So let's initialize the
81      * vector with it. */
82     for (i = 0; i < setsize; i++)
83         eventLoop->events[i].mask = AE_NONE;
84     return eventLoop;
85 }
86 
87 void aeDeleteEventLoop(aeEventLoop *eventLoop) {
88     aeApiFree(eventLoop);
89     zfree(eventLoop->events);
90     zfree(eventLoop->fired);
91     zfree(eventLoop);
92 }
93 
94 void aeStop(aeEventLoop *eventLoop) {
95     eventLoop->stop = 1;
96 }
97 
98 int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
99         aeFileProc *proc, void *clientData)
100 {
101     if (fd >= eventLoop->setsize) return AE_ERR;
102     aeFileEvent *fe = &eventLoop->events[fd];
103 
104     if (aeApiAddEvent(eventLoop, fd, mask) == -1)
105         return AE_ERR;
106     fe->mask |= mask;
107     if (mask & AE_READABLE) fe->rfileProc = proc;
108     if (mask & AE_WRITABLE) fe->wfileProc = proc;
109     fe->clientData = clientData;
110     if (fd > eventLoop->maxfd)
111         eventLoop->maxfd = fd;
112     return AE_OK;
113 }
114 
115 void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask)
116 {
117     if (fd >= eventLoop->setsize) return;
118     aeFileEvent *fe = &eventLoop->events[fd];
119 
120     if (fe->mask == AE_NONE) return;
121     fe->mask = fe->mask & (~mask);
122     if (fd == eventLoop->maxfd && fe->mask == AE_NONE) {
123         /* Update the max fd */
124         int j;
125 
126         for (j = eventLoop->maxfd-1; j >= 0; j--)
127             if (eventLoop->events[j].mask != AE_NONE) break;
128         eventLoop->maxfd = j;
129     }
130     aeApiDelEvent(eventLoop, fd, mask);
131 }
132 
133 int aeGetFileEvents(aeEventLoop *eventLoop, int fd) {
134     if (fd >= eventLoop->setsize) return 0;
135     aeFileEvent *fe = &eventLoop->events[fd];
136 
137     return fe->mask;
138 }
139 
140 static void aeGetTime(long *seconds, long *milliseconds)
141 {
142     struct timeval tv;
143 
144     gettimeofday(&tv, NULL);
145     *seconds = tv.tv_sec;
146     *milliseconds = tv.tv_usec/1000;
147 }
148 
149 static void aeAddMillisecondsToNow(long long milliseconds, long *sec, long *ms) {
150     long cur_sec, cur_ms, when_sec, when_ms;
151 
152     aeGetTime(&cur_sec, &cur_ms);
153     when_sec = cur_sec + milliseconds/1000;
154     when_ms = cur_ms + milliseconds%1000;
155     if (when_ms >= 1000) {
156         when_sec ++;
157         when_ms -= 1000;
158     }
159     *sec = when_sec;
160     *ms = when_ms;
161 }
162 
163 long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds,
164         aeTimeProc *proc, void *clientData,
165         aeEventFinalizerProc *finalizerProc)
166 {
167     long long id = eventLoop->timeEventNextId++;
168     aeTimeEvent *te;
169 
170     te = zmalloc(sizeof(*te));
171     if (te == NULL) return AE_ERR;
172     te->id = id;
173     aeAddMillisecondsToNow(milliseconds,&te->when_sec,&te->when_ms);
174     te->timeProc = proc;
175     te->finalizerProc = finalizerProc;
176     te->clientData = clientData;
177     te->next = eventLoop->timeEventHead;
178     eventLoop->timeEventHead = te;
179     return id;
180 }
181 
182 int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id)
183 {
184     aeTimeEvent *te, *prev = NULL;
185 
186     te = eventLoop->timeEventHead;
187     while(te) {
188         if (te->id == id) {
189             if (prev == NULL)
190                 eventLoop->timeEventHead = te->next;
191             else
192                 prev->next = te->next;
193             if (te->finalizerProc)
194                 te->finalizerProc(eventLoop, te->clientData);
195             zfree(te);
196             return AE_OK;
197         }
198         prev = te;
199         te = te->next;
200     }
201     return AE_ERR; /* NO event with the specified ID found */
202 }
203 
204 /* Search the first timer to fire.
205  * This operation is useful to know how many time the select can be
206  * put in sleep without to delay any event.
207  * If there are no timers NULL is returned.
208  *
209  * Note that's O(N) since time events are unsorted.
210  * Possible optimizations (not needed by Redis so far, but...):
211  * 1) Insert the event in order, so that the nearest is just the head.
212  *    Much better but still insertion or deletion of timers is O(N).
213  * 2) Use a skiplist to have this operation as O(1) and insertion as O(log(N)).
214  */
215 static aeTimeEvent *aeSearchNearestTimer(aeEventLoop *eventLoop)
216 {
217     aeTimeEvent *te = eventLoop->timeEventHead;
218     aeTimeEvent *nearest = NULL;
219 
220     while(te) {
221         if (!nearest || te->when_sec < nearest->when_sec ||
222                 (te->when_sec == nearest->when_sec &&
223                  te->when_ms < nearest->when_ms))
224             nearest = te;
225         te = te->next;
226     }
227     return nearest;
228 }
229 
230 /* Process time events */
231 static int processTimeEvents(aeEventLoop *eventLoop) {
232     int processed = 0;
233     aeTimeEvent *te;
234     long long maxId;
235 
236     te = eventLoop->timeEventHead;
237     maxId = eventLoop->timeEventNextId-1;
238     while(te) {
239         long now_sec, now_ms;
240         long long id;
241 
242         if (te->id > maxId) {
243             te = te->next;
244             continue;
245         }
246         aeGetTime(&now_sec, &now_ms);
247         if (now_sec > te->when_sec ||
248             (now_sec == te->when_sec && now_ms >= te->when_ms))
249         {
250             int retval;
251 
252             id = te->id;
253             retval = te->timeProc(eventLoop, id, te->clientData);
254             processed++;
255             /* After an event is processed our time event list may
256              * no longer be the same, so we restart from head.
257              * Still we make sure to don't process events registered
258              * by event handlers itself in order to don't loop forever.
259              * To do so we saved the max ID we want to handle.
260              *
261              * FUTURE OPTIMIZATIONS:
262              * Note that this is NOT great algorithmically. Redis uses
263              * a single time event so it's not a problem but the right
264              * way to do this is to add the new elements on head, and
265              * to flag deleted elements in a special way for later
266              * deletion (putting references to the nodes to delete into
267              * another linked list). */
268             if (retval != AE_NOMORE) {
269                 aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms);
270             } else {
271                 aeDeleteTimeEvent(eventLoop, id);
272             }
273             te = eventLoop->timeEventHead;
274         } else {
275             te = te->next;
276         }
277     }
278     return processed;
279 }
280 
281 /* Process every pending time event, then every pending file event
282  * (that may be registered by time event callbacks just processed).
283  * Without special flags the function sleeps until some file event
284  * fires, or when the next time event occurrs (if any).
285  *
286  * If flags is 0, the function does nothing and returns.
287  * if flags has AE_ALL_EVENTS set, all the kind of events are processed.
288  * if flags has AE_FILE_EVENTS set, file events are processed.
289  * if flags has AE_TIME_EVENTS set, time events are processed.
290  * if flags has AE_DONT_WAIT set the function returns ASAP until all
291  * the events that's possible to process without to wait are processed.
292  *
293  * The function returns the number of events processed. */
294 int aeProcessEvents(aeEventLoop *eventLoop, int flags)
295 {
296     int processed = 0, numevents;
297 
298     /* Nothing to do? return ASAP */
299     if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) return 0;
300 
301     /* Note that we want call select() even if there are no
302      * file events to process as long as we want to process time
303      * events, in order to sleep until the next time event is ready
304      * to fire. */
305     if (eventLoop->maxfd != -1 ||
306         ((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) {
307         int j;
308         aeTimeEvent *shortest = NULL;
309         struct timeval tv, *tvp;
310 
311         if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT))
312             shortest = aeSearchNearestTimer(eventLoop);
313         if (shortest) {
314             long now_sec, now_ms;
315 
316             /* Calculate the time missing for the nearest
317              * timer to fire. */
318             aeGetTime(&now_sec, &now_ms);
319             tvp = &tv;
320             tvp->tv_sec = shortest->when_sec - now_sec;
321             if (shortest->when_ms < now_ms) {
322                 tvp->tv_usec = ((shortest->when_ms+1000) - now_ms)*1000;
323                 tvp->tv_sec --;
324             } else {
325                 tvp->tv_usec = (shortest->when_ms - now_ms)*1000;
326             }
327             if (tvp->tv_sec < 0) tvp->tv_sec = 0;
328             if (tvp->tv_usec < 0) tvp->tv_usec = 0;
329         } else {
330             /* If we have to check for events but need to return
331              * ASAP because of AE_DONT_WAIT we need to se the timeout
332              * to zero */
333             if (flags & AE_DONT_WAIT) {
334                 tv.tv_sec = tv.tv_usec = 0;
335                 tvp = &tv;
336             } else {
337                 /* Otherwise we can block */
338                 tvp = NULL; /* wait forever */
339             }
340         }
341 
342         numevents = aeApiPoll(eventLoop, tvp);
343         for (j = 0; j < numevents; j++) {
344             aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd];
345             int mask = eventLoop->fired[j].mask;
346             int fd = eventLoop->fired[j].fd;
347             int rfired = 0;
348 
349 	    /* note the fe->mask & mask & ... code: maybe an already processed
350              * event removed an element that fired and we still didn't
351              * processed, so we check if the event is still valid. */
352             if (fe->mask & mask & AE_READABLE) {
353                 rfired = 1;
354                 fe->rfileProc(eventLoop,fd,fe->clientData,mask);
355             }
356             if (fe->mask & mask & AE_WRITABLE) {
357                 if (!rfired || fe->wfileProc != fe->rfileProc)
358                     fe->wfileProc(eventLoop,fd,fe->clientData,mask);
359             }
360             processed++;
361         }
362     }
363     /* Check time events */
364     if (flags & AE_TIME_EVENTS)
365         processed += processTimeEvents(eventLoop);
366 
367     return processed; /* return the number of processed file/time events */
368 }
369 
370 /* Wait for millseconds until the given file descriptor becomes
371  * writable/readable/exception */
372 int aeWait(int fd, int mask, long long milliseconds) {
373     struct timeval tv;
374     fd_set rfds, wfds, efds;
375     int retmask = 0, retval;
376 
377     tv.tv_sec = milliseconds/1000;
378     tv.tv_usec = (milliseconds%1000)*1000;
379     FD_ZERO(&rfds);
380     FD_ZERO(&wfds);
381     FD_ZERO(&efds);
382 
383     if (mask & AE_READABLE) FD_SET(fd,&rfds);
384     if (mask & AE_WRITABLE) FD_SET(fd,&wfds);
385     if ((retval = select(fd+1, &rfds, &wfds, &efds, &tv)) > 0) {
386         if (FD_ISSET(fd,&rfds)) retmask |= AE_READABLE;
387         if (FD_ISSET(fd,&wfds)) retmask |= AE_WRITABLE;
388         return retmask;
389     } else {
390         return retval;
391     }
392 }
393 
394 void aeMain(aeEventLoop *eventLoop) {
395     eventLoop->stop = 0;
396     while (!eventLoop->stop) {
397         if (eventLoop->beforesleep != NULL)
398             eventLoop->beforesleep(eventLoop);
399         aeProcessEvents(eventLoop, AE_ALL_EVENTS);
400     }
401 }
402 
403 char *aeGetApiName(void) {
404     return aeApiName();
405 }
406 
407 void aeSetBeforeSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *beforesleep) {
408     eventLoop->beforesleep = beforesleep;
409 }
410