]> git.llucax.com Git - software/libev.git/blob - event.c
improve event compatibility, make watchers much smaller by union'ising io and sig...
[software/libev.git] / event.c
1 /*
2  * libevent compatibility layer
3  *
4  * Copyright (c) 2007 Marc Alexander Lehmann <libev@schmorp.de>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are
9  * met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *
14  *     * Redistributions in binary form must reproduce the above
15  *       copyright notice, this list of conditions and the following
16  *       disclaimer in the documentation and/or other materials provided
17  *       with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include <stddef.h>
33 #include <stdlib.h>
34 #include <sys/time.h>
35
36 #include "event.h"
37
38 struct event_base
39 {
40   int dummy;
41 };
42
43 static int x_actives;
44
45 static struct event_base x_base, *x_cur;
46
47 static void
48 tv_set (struct timeval *tv, ev_tstamp at)
49 {
50   tv->tv_sec  = (long)at;
51   tv->tv_usec = (long)((at - (ev_tstamp)tv->tv_sec) * 1e6);
52 }
53
54 static ev_tstamp
55 tv_get (struct timeval *tv)
56 {
57   if (tv)
58     return tv->tv_sec + tv->tv_usec * 1e-6;
59   else
60     return -1.;
61 }
62
63 #define EVENT_VERSION(a,b) # a "." # b
64
65 const char *event_get_version (void)
66 {
67   return EVENT_VERSION (EV_VERSION_MAJOR, EV_VERSION_MINOR);
68 }
69
70 const char *event_get_method (void)
71 {
72   return "libev";
73 }
74
75 void *event_init (void)
76 {
77   if (ev_init (0))
78     return x_cur = &x_base;
79
80   return 0;
81 }
82
83 void event_base_free (struct event_base *base)
84 {
85   /* nop */
86 }
87
88 int event_dispatch (void)
89 {
90   return event_base_dispatch (x_cur);
91 }
92
93 void event_set_log_callback (event_log_cb cb)
94 {
95   /* nop */
96 }
97
98 int event_loop (int flags)
99 {
100   return event_base_loop (x_cur, flags);
101 }
102
103 int event_loopexit (struct timeval *tv)
104 {
105   event_base_loopexit (x_cur, tv);
106 }
107
108 static void
109 x_cb (struct event *ev, int revents)
110 {
111   if (ev->ev_events & EV_SIGNAL)
112     {
113       /* sig */
114       if (ev_is_active (&ev->iosig.sig))
115         {
116           ev_signal_stop (&ev->iosig.sig);
117           --x_actives;
118         }
119     }
120   else
121     {
122        /* io */
123       if (!(ev->ev_events & EV_PERSIST) && ev_is_active (&ev->iosig.io))
124         {
125           ev_io_stop (&ev->iosig.io);
126           --x_actives;
127         }
128     }
129
130   revents &= EV_READ | EV_WRITE | EV_TIMEOUT | EV_SIGNAL;
131
132   if (revents & EV_TIMEOUT)
133     --x_actives;
134
135   ev->ev_res = revents;
136   ev->ev_callback (ev->ev_fd, revents, ev->ev_arg);
137 }
138
139 static void
140 x_cb_io (struct ev_io *w, int revents)
141 {
142   x_cb ((struct event *)(((char *)w) - offsetof (struct event, iosig.io)), revents);
143 }
144
145 static void
146 x_cb_to (struct ev_timer *w, int revents)
147 {
148   x_cb ((struct event *)(((char *)w) - offsetof (struct event, to)), revents);
149 }
150
151 static void
152 x_cb_sig (struct ev_signal *w, int revents)
153 {
154   x_cb ((struct event *)(((char *)w) - offsetof (struct event, iosig.sig)), revents);
155 }
156
157 void event_set (struct event *ev, int fd, short events, void (*cb)(int, short, void *), void *arg)
158 {
159   if (events & EV_SIGNAL)
160     ev_watcher_init (&ev->iosig.sig, x_cb_sig);
161   else
162     ev_watcher_init (&ev->iosig.io, x_cb_io);
163
164   ev_watcher_init (&ev->to, x_cb_to);
165
166   ev->ev_base     = x_cur;
167   ev->ev_fd       = fd;
168   ev->ev_events   = events;
169   ev->ev_pri      = 0;
170   ev->ev_callback = cb;
171   ev->ev_arg      = arg;
172   ev->ev_res      = 0;
173 }
174
175 int event_once (int fd, short events, void (*cb)(int, short, void *), void *arg, struct timeval *tv)
176 {
177   event_base_once (x_cur, fd, events, cb, arg, tv);
178 }
179
180 int event_add (struct event *ev, struct timeval *tv)
181 {
182   /* disable all watchers */
183   event_del (ev);
184
185   if (ev->ev_events & EV_SIGNAL)
186     {
187       ev_signal_set (&ev->iosig.sig, ev->ev_fd);
188       ev_signal_start (&ev->iosig.sig);
189       ++x_actives;
190     }
191   else if (ev->ev_events & (EV_READ | EV_WRITE))
192     {
193       ev_io_set (&ev->iosig.io, ev->ev_fd, ev->ev_events & (EV_READ | EV_WRITE));
194       ev_io_start (&ev->iosig.io);
195       ++x_actives;
196     }
197
198   if (tv)
199     {
200       ev_timer_set (&ev->to, tv_get (tv), 0.);
201       ev_timer_start (&ev->to);
202       ++x_actives;
203     }
204
205   return 0;
206 }
207
208 int event_del (struct event *ev)
209 {
210   if (ev->ev_events & EV_SIGNAL)
211     {
212       /* sig */
213       if (ev_is_active (&ev->iosig.sig))
214         {
215           ev_signal_stop (&ev->iosig.sig);
216           --x_actives;
217         }
218     }
219   else
220     {
221       /* io */
222       if (ev_is_active (&ev->iosig.io))
223         {
224           ev_io_stop (&ev->iosig.io);
225           --x_actives;
226         }
227     }
228
229   if (ev_is_active (&ev->to))
230     {
231       ev_timer_stop (&ev->to);
232       --x_actives;
233     }
234
235   return 0;
236 }
237
238 int event_pending (struct event *ev, short events, struct timeval *tv)
239 {
240   short revents;
241
242   if (ev->ev_events & EV_SIGNAL)
243     {
244       /* sig */
245       if (ev->iosig.sig.pending)
246         revents |= EV_SIGNAL;
247     }
248   else
249     {
250       /* io */
251       if (ev->iosig.io.pending)
252         revents |= ev->ev_events & (EV_READ | EV_WRITE);
253     }
254
255   if (ev->to.pending)
256     {
257       revents |= EV_TIMEOUT;
258
259       if (tv)
260         tv_set (tv, ev_now); /* not sure if this is right :) */
261     }
262
263   return events & revents;
264 }
265
266 int event_priority_init (int npri)
267 {
268   return event_base_priority_init (x_cur, npri);
269 }
270
271 int event_priority_set (struct event *ev, int pri)
272 {
273   ev->ev_pri = pri;
274
275   return 0;
276 }
277
278 int event_base_set (struct event_base *base, struct event *ev)
279 {
280   ev->ev_base = base;
281
282   return 0;
283 }
284
285 int event_base_loop (struct event_base *base, int flags)
286 {
287   do
288     {
289       ev_loop (flags | EVLOOP_ONESHOT);
290     }
291   while (!(flags & (EVLOOP_ONESHOT | EVLOOP_NONBLOCK)) && x_actives && !ev_loop_done);
292
293   return 0;
294 }
295
296 int event_base_dispatch (struct event_base *base)
297 {
298   return event_base_loop (base, 0);
299 }
300
301 static void
302 x_loopexit_cb (int revents, void *arg)
303 {
304   ev_loop_done = 2;
305 }
306
307 int event_base_loopexit (struct event_base *base, struct timeval *tv)
308 {
309   ev_tstamp after = tv_get (tv);
310
311   ev_once (-1, 0, after >= 0. ? after : 0., x_loopexit_cb, (void *)base);
312 }
313
314 struct x_once
315 {
316   int fd;
317   void (*cb)(int, short, void *);
318   void *arg;
319 };
320
321 static void
322 x_once_cb (int revents, void *arg)
323 {
324   struct x_once *once = arg;
325
326   once->cb (once->fd, revents, once->arg);
327   free (once);
328 }
329
330 int event_base_once (struct event_base *base, int fd, short events, void (*cb)(int, short, void *), void *arg, struct timeval *tv)
331 {
332   struct x_once *once = malloc (sizeof (struct x_once));
333
334   if (!once)
335     return -1;
336
337   once->fd  = fd;
338   once->cb  = cb;
339   once->arg = arg;
340
341   ev_once (fd, events & (EV_READ | EV_WRITE), tv_get (tv), x_once_cb, (void *)once);
342
343   return 0;
344 }
345
346 int event_base_priority_init (struct event_base *base, int npri)
347 {
348   return 0;
349 }
350