root/src/eventer/eventer_epoll_impl.c

Revision 3a48d08926ff8a3ea95003402260d96f360cc064, 9.1 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 2 weeks ago)

update eventer callback probe.
Cover all callsites and pass eventer_t as first arg.

  • 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, (void *)e->callback, (char *)cbname, fd, e->mask, mask);
208   newmask = e->callback(e, mask, e->closure, &__now);
209   EVENTER_CALLBACK_RETURN((void *)e, (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.