root/src/eventer/eventer_epoll_impl.c

Revision feb304872d1a9eec2a1d4ccc79c72e1bdef139f0, 9.0 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 8 months ago)

Change Epoll Error To Debug Level Message
When we reach the condition where epoll tries to modify a descheduled
fd, nothing actually breaks, but we can possibly fill the log with
error messages. Since this isn't crucial, but we may still want to be
aware of it for debugging purposes, changed the level of the message
from noit_error to noit_debug.

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  *       notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  *       copyright notice, this list of conditions and the following
13  *       disclaimer in the documentation and/or other materials provided
14  *       with the distribution.
15  *     * Neither the name OmniTI Computer Consulting, Inc. nor the names
16  *       of its contributors may be used to endorse or promote products
17  *       derived from this software without specific prior written
18  *       permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "noit_defines.h"
34 #include "eventer/eventer.h"
35 #include "utils/noit_atomic.h"
36 #include "utils/noit_skiplist.h"
37 #include "utils/noit_log.h"
38 #include "dtrace_probes.h"
39
40 #include <errno.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <sys/epoll.h>
44 #include <signal.h>
45 #include <pthread.h>
46 #include <assert.h>
47
48 struct _eventer_impl eventer_epoll_impl;
49 #define LOCAL_EVENTER eventer_epoll_impl
50 #define LOCAL_EVENTER_foreach_fdevent eventer_epoll_impl_foreach_fdevent
51 #define maxfds LOCAL_EVENTER.maxfds
52 #define master_fds LOCAL_EVENTER.master_fds
53
54 #include "eventer/eventer_impl_private.h"
55
56 static int *masks;
57 static int epoll_fd = -1;
58
59 static int eventer_epoll_impl_init() {
60   struct rlimit rlim;
61   int rv;
62
63   /* super init */
64   if((rv = eventer_impl_init()) != 0) return rv;
65
66   signal(SIGPIPE, SIG_IGN);
67   epoll_fd = epoll_create(1024);
68   if(epoll_fd == -1) {
69     return -1;
70   }
71   getrlimit(RLIMIT_NOFILE, &rlim);
72   maxfds = rlim.rlim_cur;
73   master_fds = calloc(maxfds, sizeof(*master_fds));
74   masks = calloc(maxfds, sizeof(*masks));
75   return 0;
76 }
77 static int eventer_epoll_impl_propset(const char *key, const char *value) {
78   if(eventer_impl_propset(key, value)) {
79     /* Do our epoll local properties here */
80     return -1;
81   }
82   return 0;
83 }
84 static void eventer_epoll_impl_add(eventer_t e) {
85   int rv;
86   struct epoll_event _ev;
87   ev_lock_state_t lockstate;
88   assert(e->mask);
89
90   if(e->mask & EVENTER_ASYNCH) {
91     eventer_add_asynch(NULL, e);
92     return;
93   }
94
95   /* Recurrent delegation */
96   if(e->mask & EVENTER_RECURRENT) {
97     eventer_add_recurrent(e);
98     return;
99   }
100
101   /* Timed events are simple */
102   if(e->mask & EVENTER_TIMER) {
103     eventer_add_timed(e);
104     return;
105   }
106
107   /* file descriptor event */
108   assert(e->whence.tv_sec == 0 && e->whence.tv_usec == 0);
109   memset(&_ev, 0, sizeof(_ev));
110   _ev.data.fd = e->fd;
111   if(e->mask & EVENTER_READ) _ev.events |= (EPOLLIN|EPOLLPRI);
112   if(e->mask & EVENTER_WRITE) _ev.events |= (EPOLLOUT);
113   if(e->mask & EVENTER_EXCEPTION) _ev.events |= (EPOLLERR|EPOLLHUP);
114
115   lockstate = acquire_master_fd(e->fd);
116   master_fds[e->fd].e = e;
117
118   rv = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, e->fd, &_ev);
119   if(rv != 0) {
120     noitL(eventer_err, "epoll_ctl(%d,add,%d,%x) -> %d (%d: %s)\n",
121           epoll_fd, e->fd, e->mask, rv, errno, strerror(errno));
122     abort();
123   }
124
125   release_master_fd(e->fd, lockstate);
126 }
127 static eventer_t eventer_epoll_impl_remove(eventer_t e) {
128   eventer_t removed = NULL;
129   if(e->mask & EVENTER_ASYNCH) {
130     abort();
131   }
132   if(e->mask & (EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION)) {
133     ev_lock_state_t lockstate;
134     struct epoll_event _ev;
135     memset(&_ev, 0, sizeof(_ev));
136     _ev.data.fd = e->fd;
137     lockstate = acquire_master_fd(e->fd);
138     if(e == master_fds[e->fd].e) {
139       removed = e;
140       master_fds[e->fd].e = NULL;
141       assert(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, e->fd, &_ev) == 0);
142     }
143     release_master_fd(e->fd, lockstate);
144   }
145   else if(e->mask & EVENTER_TIMER) {
146     removed = eventer_remove_timed(e);
147   }
148   else if(e->mask & EVENTER_RECURRENT) {
149     removed = eventer_remove_recurrent(e);
150   }
151   else {
152     abort();
153   }
154   return removed;
155 }
156 static void eventer_epoll_impl_update(eventer_t e, int mask) {
157   struct epoll_event _ev;
158   if(e->mask & EVENTER_TIMER) {
159     eventer_update_timed(e,mask);
160     return;
161   }
162   memset(&_ev, 0, sizeof(_ev));
163   _ev.data.fd = e->fd;
164   e->mask = mask;
165   if(e->mask & (EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION)) {
166     if(e->mask & EVENTER_READ) _ev.events |= (EPOLLIN|EPOLLPRI);
167     if(e->mask & EVENTER_WRITE) _ev.events |= (EPOLLOUT);
168     if(e->mask & EVENTER_EXCEPTION) _ev.events |= (EPOLLERR|EPOLLHUP);
169     assert(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, e->fd, &_ev) == 0);
170   }
171 }
172 static eventer_t eventer_epoll_impl_remove_fd(int fd) {
173   eventer_t eiq = NULL;
174   ev_lock_state_t lockstate;
175   if(master_fds[fd].e) {
176     struct epoll_event _ev;
177     memset(&_ev, 0, sizeof(_ev));
178     _ev.data.fd = fd;
179     lockstate = acquire_master_fd(fd);
180     eiq = master_fds[fd].e;
181     master_fds[fd].e = NULL;
182     assert(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &_ev) == 0);
183     release_master_fd(fd, lockstate);
184   }
185   return eiq;
186 }
187 static eventer_t eventer_epoll_impl_find_fd(int fd) {
188   return master_fds[fd].e;
189 }
190
191 static void eventer_epoll_impl_trigger(eventer_t e, int mask) {
192   struct timeval __now;
193   int fd, newmask;
194   const char *cbname;
195   ev_lock_state_t lockstate;
196
197   fd = e->fd;
198   if(e != master_fds[fd].e) return;
199   lockstate = acquire_master_fd(fd);
200   if(lockstate == EV_ALREADY_OWNED) return;
201   assert(lockstate == EV_OWNED);
202
203   gettimeofday(&__now, NULL);
204   cbname = eventer_name_for_callback_e(e->callback, e);
205   noitLT(eventer_deb, &__now, "epoll: fire on %d/%x to %s(%p)\n",
206          fd, mask, cbname?cbname:"???", e->callback);
207   EVENTER_CALLBACK_ENTRY((void *)e->callback, (char *)cbname, fd, e->mask, mask);
208   newmask = e->callback(e, mask, e->closure, &__now);
209   EVENTER_CALLBACK_RETURN((void *)e->callback, (char *)cbname, newmask);
210
211   if(newmask) {
212     struct epoll_event _ev;
213     memset(&_ev, 0, sizeof(_ev));
214     _ev.data.fd = fd;
215     if(newmask & EVENTER_READ) _ev.events |= (EPOLLIN|EPOLLPRI);
216     if(newmask & EVENTER_WRITE) _ev.events |= (EPOLLOUT);
217     if(newmask & EVENTER_EXCEPTION) _ev.events |= (EPOLLERR|EPOLLHUP);
218     if(master_fds[fd].e == NULL) {
219       noitL(noit_debug, "eventer %s(%p) epoll asked to modify descheduled fd: %d\n",
220             cbname?cbname:"???", e->callback, fd);
221     } else {
222       assert(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &_ev) == 0);
223     }
224     /* Set our mask */
225     e->mask = newmask;
226   }
227   else {
228     /* see kqueue implementation for details on the next line */
229     if(master_fds[fd].e == e) master_fds[fd].e = NULL;
230     eventer_free(e);
231   }
232   release_master_fd(fd, lockstate);
233 }
234 static int eventer_epoll_impl_loop() {
235   struct epoll_event *epev;
236
237   epev = malloc(sizeof(*epev) * maxfds);
238
239   while(1) {
240     struct timeval __now, __sleeptime;
241     int fd_cnt = 0;
242
243     __sleeptime = eventer_max_sleeptime;
244
245     eventer_dispatch_timed(&__now, &__sleeptime);
246
247     /* Handle recurrent events */
248     eventer_dispatch_recurrent(&__now);
249
250     /* Now we move on to our fd-based events */
251     fd_cnt = epoll_wait(epoll_fd, epev, maxfds,
252                         __sleeptime.tv_sec * 1000 + __sleeptime.tv_usec / 1000);
253     noitLT(eventer_deb, &__now, "debug: epoll_wait(%d, [], %d) => %d\n", epoll_fd, maxfds, fd_cnt);
254     if(fd_cnt < 0) {
255       noitLT(eventer_err, &__now, "epoll_wait: %s\n", strerror(errno));
256     }
257     else {
258       int idx;
259       /* loop once to clear */
260       for(idx = 0; idx < fd_cnt; idx++) {
261         struct epoll_event *ev;
262         eventer_t e;
263         int fd, mask = 0;
264
265         ev = &epev[idx];
266
267         if(ev->events & (EPOLLIN | EPOLLPRI)) mask |= EVENTER_READ;
268         if(ev->events & (EPOLLOUT)) mask |= EVENTER_WRITE;
269         if(ev->events & (EPOLLERR|EPOLLHUP)) mask |= EVENTER_EXCEPTION;
270
271         fd = ev->data.fd;
272
273         e = master_fds[fd].e;
274         /* It's possible that someone removed the event and freed it
275          * before we got here.
276          */
277         if(!e) continue;
278
279         eventer_epoll_impl_trigger(e, mask);
280       }
281     }
282   }
283   /* NOTREACHED */
284   return 0;
285 }
286
287 struct _eventer_impl eventer_epoll_impl = {
288   "epoll",
289   eventer_epoll_impl_init,
290   eventer_epoll_impl_propset,
291   eventer_epoll_impl_add,
292   eventer_epoll_impl_remove,
293   eventer_epoll_impl_update,
294   eventer_epoll_impl_remove_fd,
295   eventer_epoll_impl_find_fd,
296   eventer_epoll_impl_trigger,
297   eventer_epoll_impl_loop,
298   eventer_epoll_impl_foreach_fdevent,
299   eventer_wakeup_noop,
300   { 0, 200000 },
301   0,
302   NULL
303 };
Note: See TracBrowser for help on using the browser.