root/src/eventer/eventer_ports_impl.c

Revision 672bbf3524d6ab8bdce4d334e9170ef1b6f11107, 10.9 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 3 years ago)

unused variables on solaris scheduler

  • 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
39 #include <errno.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <signal.h>
43 #include <port.h>
44 #include <pthread.h>
45 #include <assert.h>
46
47 #define MAX_PORT_EVENTS 1024
48
49 struct _eventer_impl eventer_ports_impl;
50 #define LOCAL_EVENTER eventer_ports_impl
51 #define LOCAL_EVENTER_foreach_fdevent eventer_ports_impl_foreach_fdevent
52 #define LOCAL_EVENTER_foreach_timedevent eventer_ports_impl_foreach_timedevent
53 #define maxfds LOCAL_EVENTER.maxfds
54 #define master_fds LOCAL_EVENTER.master_fds
55
56 #include "eventer/eventer_impl_private.h"
57
58 static const struct timeval __dyna_increment = { 0, 1000 }; /* 1 ms */
59 static int port_fd = -1;
60
61 static int eventer_ports_impl_init() {
62   struct rlimit rlim;
63   int rv;
64
65   /* super init */
66   if((rv = eventer_impl_init()) != 0) return rv;
67
68   signal(SIGPIPE, SIG_IGN);
69   port_fd = port_create();
70   if(port_fd == -1) {
71     return -1;
72   }
73   getrlimit(RLIMIT_NOFILE, &rlim);
74   maxfds = rlim.rlim_cur;
75   master_fds = calloc(maxfds, sizeof(*master_fds));
76   return 0;
77 }
78 static int eventer_ports_impl_propset(const char *key, const char *value) {
79   if(eventer_impl_propset(key, value)) {
80     return -1;
81   }
82   return 0;
83 }
84 static void alter_fd(eventer_t e, int mask) {
85   if(mask & (EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION)) {
86     int events = 0;
87     if(mask & EVENTER_READ) events |= POLLIN;
88     if(mask & EVENTER_WRITE) events |= POLLOUT;
89     if(mask & EVENTER_EXCEPTION) events |= POLLERR;
90     if(port_associate(port_fd, PORT_SOURCE_FD, e->fd, events, (void *)e->fd) == -1) {
91       noitL(eventer_err,
92             "eventer port_associate failed: %s\n", strerror(errno));
93       abort();
94     }
95   }
96   else {
97     if(port_dissociate(port_fd, PORT_SOURCE_FD, e->fd) == -1) {
98       if(errno == ENOENT) return; /* Fine */
99       if(errno == EBADFD) return; /* Fine */
100       noitL(eventer_err,
101             "eventer port_dissociate failed: %s\n", strerror(errno));
102       abort();
103     }
104   }
105 }
106 static void eventer_ports_impl_add(eventer_t e) {
107   assert(e->mask);
108   ev_lock_state_t lockstate;
109   const char *cbname;
110   cbname = eventer_name_for_callback(e->callback);
111
112   if(e->mask & EVENTER_ASYNCH) {
113     noitL(eventer_deb, "debug: eventer_add asynch (%s)\n", cbname ? cbname : "???");
114     eventer_add_asynch(NULL, e);
115     return;
116   }
117
118   /* Recurrent delegation */
119   if(e->mask & EVENTER_RECURRENT) {
120     noitL(eventer_deb, "debug: eventer_add recurrent (%s)\n", cbname ? cbname : "???");
121     eventer_add_recurrent(e);
122     return;
123   }
124
125   /* Timed events are simple */
126   if(e->mask & EVENTER_TIMER) {
127     eventer_add_timed(e);
128     return;
129   }
130
131   /* file descriptor event */
132   noitL(eventer_deb, "debug: eventer_add fd (%s,%d,0x%04x)\n", cbname ? cbname : "???", e->fd, e->mask);
133   lockstate = acquire_master_fd(e->fd);
134   assert(e->whence.tv_sec == 0 && e->whence.tv_usec == 0);
135   master_fds[e->fd].e = e;
136   alter_fd(e, e->mask);
137   release_master_fd(e->fd, lockstate);
138 }
139 static eventer_t eventer_ports_impl_remove(eventer_t e) {
140   eventer_t removed = NULL;
141   if(e->mask & EVENTER_ASYNCH) {
142     abort();
143   }
144   if(e->mask & (EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION)) {
145     ev_lock_state_t lockstate;
146     lockstate = acquire_master_fd(e->fd);
147     if(e == master_fds[e->fd].e) {
148       removed = e;
149       master_fds[e->fd].e = NULL;
150       alter_fd(e, 0);
151     }
152     release_master_fd(e->fd, lockstate);
153   }
154   else if(e->mask & EVENTER_TIMER) {
155     removed = eventer_remove_timed(e);
156   }
157   else if(e->mask & EVENTER_RECURRENT) {
158     removed = eventer_remove_recurrent(e);
159   }
160   else {
161     abort();
162   }
163   return removed;
164 }
165 static void eventer_ports_impl_update(eventer_t e, int mask) {
166   if(e->mask & EVENTER_TIMER) {
167     eventer_update_timed(e,mask);
168     return;
169   }
170   alter_fd(e, mask);
171   e->mask = mask;
172 }
173 static eventer_t eventer_ports_impl_remove_fd(int fd) {
174   eventer_t eiq = NULL;
175   ev_lock_state_t lockstate;
176   if(master_fds[fd].e) {
177     lockstate = acquire_master_fd(fd);
178     eiq = master_fds[fd].e;
179     master_fds[fd].e = NULL;
180     alter_fd(eiq, 0);
181     release_master_fd(fd, lockstate);
182   }
183   return eiq;
184 }
185 static eventer_t eventer_ports_impl_find_fd(int fd) {
186   return master_fds[fd].e;
187 }
188 static void
189 eventer_ports_impl_trigger(eventer_t e, int mask) {
190   ev_lock_state_t lockstate;
191   const char *cbname;
192   struct timeval __now;
193   int fd, oldmask, newmask;
194
195   fd = e->fd;
196   if(e != master_fds[fd].e) return;
197   lockstate = acquire_master_fd(fd);
198   if(lockstate == EV_ALREADY_OWNED) return;
199   assert(lockstate == EV_OWNED);
200
201   gettimeofday(&__now, NULL);
202   oldmask = e->mask;
203   cbname = eventer_name_for_callback(e->callback);
204   noitLT(eventer_deb, &__now, "ports: fire on %d/%x to %s(%p)\n",
205          fd, mask, cbname?cbname:"???", e->callback);
206   newmask = e->callback(e, mask, e->closure, &__now);
207
208   if(newmask) {
209     alter_fd(e, newmask);
210     /* Set our mask */
211     e->mask = newmask;
212     noitLT(eventer_deb, &__now, "ports: complete on %d/(%x->%x) to %s(%p)\n",
213            fd, mask, newmask, cbname?cbname:"???", e->callback);
214   }
215   else {
216     noitLT(eventer_deb, &__now, "ports: complete on %d/none to %s(%p)\n",
217            fd, cbname?cbname:"???", e->callback);
218     /*
219      * Long story long:
220      *  When integrating with a few external event systems, we find
221      *  it difficult to make their use of remove+add as an update
222      *  as it can be recurrent in a single handler call and you cannot
223      *  remove completely from the event system if you are going to
224      *  just update (otherwise the eventer_t in your call stack could
225      *  be stale).  What we do is perform a superficial remove, marking
226      *  the mask as 0, but not eventer_remove_fd.  Then on an add, if
227      *  we already have an event, we just update the mask (as we
228      *  have not yet returned to the eventer's loop.
229      *  This leaves us in a tricky situation when a remove is called
230      *  and the add doesn't roll in, we return 0 (mask == 0) and hit
231      *  this spot.  We have intended to remove the event, but it still
232      *  resides at master_fds[fd].e -- even after we free it.
233      *  So, in the evnet that we return 0 and the event that
234      *  master_fds[fd].e == the event we're about to free... we NULL
235      *  it out.
236      */
237     if(master_fds[fd].e == e) master_fds[fd].e = NULL;
238     eventer_free(e);
239   }
240   release_master_fd(fd, lockstate);
241 }
242 static int eventer_ports_impl_loop() {
243   struct timeval __dyna_sleep = { 0, 0 };
244
245   while(1) {
246     struct timeval __now, __sleeptime;
247     struct timespec __ports_sleeptime;
248     unsigned int fd_cnt = 0;
249     int ret;
250     port_event_t pevents[MAX_PORT_EVENTS];
251
252     if(compare_timeval(eventer_max_sleeptime, __dyna_sleep) < 0)
253       __dyna_sleep = eventer_max_sleeptime;
254  
255     __sleeptime = __dyna_sleep;
256
257     eventer_dispatch_timed(&__now, &__sleeptime);
258
259     if(compare_timeval(__sleeptime, __dyna_sleep) > 0)
260       __sleeptime = __dyna_sleep;
261
262     /* Handle recurrent events */
263     eventer_dispatch_recurrent(&__now);
264
265     /* Now we move on to our fd-based events */
266     __ports_sleeptime.tv_sec = __sleeptime.tv_sec;
267     __ports_sleeptime.tv_nsec = __sleeptime.tv_usec * 1000;
268     fd_cnt = 1;
269
270     pevents[0].portev_source = 65535; /* This is impossible */
271
272     ret = port_getn(port_fd, pevents, MAX_PORT_EVENTS, &fd_cnt,
273                     &__ports_sleeptime);
274     /* The timeout case is a tad complex with ports.  -1/ETIME is clearly
275      * a timeout.  However, it i spossible that we got that and fd_cnt isn't
276      * 0, which means we both timed out and got events... WTF?
277      */
278     if(fd_cnt == 0 ||
279        (ret == -1 && errno == ETIME && pevents[0].portev_source == 65535))
280       add_timeval(__dyna_sleep, __dyna_increment, &__dyna_sleep);
281
282     if(ret == -1 && (errno != ETIME && errno != EINTR))
283       noitLT(eventer_err, &__now, "port_getn: %s\n", strerror(errno));
284
285     if(ret < 0)
286       noitLT(eventer_deb, &__now, "port_getn: %s\n", strerror(errno));
287
288     noitLT(eventer_deb, &__now, "debug: port_getn(%d, [], %d) => %d\n", port_fd,
289            fd_cnt, ret);
290
291     if(pevents[0].portev_source == 65535) {
292       /* the impossible still remains, which means our fd_cnt _must_ be 0 */
293       fd_cnt = 0;
294     }
295
296     if(fd_cnt > 0) {
297       int idx;
298       /* Loop a last time to process */
299       __dyna_sleep.tv_sec = __dyna_sleep.tv_usec = 0; /* reset */
300       for(idx = 0; idx < fd_cnt; idx++) {
301         port_event_t *pe;
302         eventer_t e;
303         int fd, mask;
304
305         pe = &pevents[idx];
306         if(pe->portev_source != PORT_SOURCE_FD) continue;
307         fd = (int)pe->portev_object;
308         assert((int)pe->portev_user == fd);
309         e = master_fds[fd].e;
310         mask = 0;
311         if(pe->portev_events & (POLLIN | POLLHUP))
312           mask |= EVENTER_READ;
313         if(pe->portev_events & (POLLOUT))
314           mask |= EVENTER_WRITE;
315         if(pe->portev_events & (POLLERR | POLLHUP | POLLNVAL))
316           mask |= EVENTER_EXCEPTION;
317
318         /* It's possible that someone removed the event and freed it
319          * before we got here.
320          */
321         eventer_ports_impl_trigger(e, mask);
322       }
323     }
324   }
325   /* NOTREACHED */
326 }
327
328 struct _eventer_impl eventer_ports_impl = {
329   "ports",
330   eventer_ports_impl_init,
331   eventer_ports_impl_propset,
332   eventer_ports_impl_add,
333   eventer_ports_impl_remove,
334   eventer_ports_impl_update,
335   eventer_ports_impl_remove_fd,
336   eventer_ports_impl_find_fd,
337   eventer_ports_impl_trigger,
338   eventer_ports_impl_loop,
339   eventer_ports_impl_foreach_fdevent,
340   { 0, 200000 },
341   0,
342   NULL
343 };
Note: See TracBrowser for help on using the browser.