1 /*
2 * Copyright 2011 Red Hat, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25 /*
26 * An edited version of verto-libev.c, using an embedded libev with renamed
27 * symbols. The corresponding version of verto-libev.c is stored in this
28 * directory for reference, although it is not built here.
29 */
30
31 #include "autoconf.h"
32 #include <stdlib.h>
33 #include <string.h>
34 #include <errno.h>
35
36 #include <verto.h>
37 #include <verto-module.h>
38 #include "rename.h"
39
40 /* Ignore some warnings generated by the libev code, which the libev maintainer
41 * isn't interested in avoiding. */
42 #ifdef __GNUC__
43 #pragma GCC diagnostic ignored "-Wunused-value"
44 #pragma GCC diagnostic ignored "-Wcomment"
45 #pragma GCC diagnostic ignored "-Wunused-result"
46 #ifdef __clang__
47 #pragma GCC diagnostic ignored "-Wbitwise-op-parentheses"
48 #endif
49 #endif
50
51 #define EV_API_STATIC 1
52 #define EV_STANDALONE 1
53 /* Avoid using clock_gettime, which would create a dependency on librt. */
54 #define EV_USE_MONOTONIC 0
55 #define EV_USE_REALTIME 0
56 #define EV_FEATURES 0x4f /* No back ends or optional watchers */
57 /* Enable the optional watcher types we use. */
58 #define EV_IDLE_ENABLE 1
59 #define EV_SIGNAL_ENABLE 1
60 #define EV_CHILD_ENABLE 1
61 /* Enable the back ends we want. */
62 #ifdef HAVE_POLL_H
63 #define EV_USE_POLL 1
64 #endif
65 /* ev.c explicitly disables poll() on Mac or FreeBSD; fall back to select(). */
66 #define EV_USE_SELECT 1
67 #include "ev.c"
68
69 static verto_mod_ctx *
k5ev_ctx_new(void)70 k5ev_ctx_new(void)
71 {
72 return ev_loop_new(EVFLAG_AUTO);
73 }
74
75 static verto_mod_ctx *
k5ev_ctx_default(void)76 k5ev_ctx_default(void)
77 {
78 return ev_default_loop(EVFLAG_AUTO);
79 }
80
81 static void
k5ev_ctx_free(verto_mod_ctx * ctx)82 k5ev_ctx_free(verto_mod_ctx *ctx)
83 {
84 if (ctx != EV_DEFAULT)
85 ev_loop_destroy(ctx);
86 }
87
88 static void
k5ev_ctx_run(verto_mod_ctx * ctx)89 k5ev_ctx_run(verto_mod_ctx *ctx)
90 {
91 ev_run(ctx, 0);
92 }
93
94 static void
k5ev_ctx_run_once(verto_mod_ctx * ctx)95 k5ev_ctx_run_once(verto_mod_ctx *ctx)
96 {
97 ev_run(ctx, EVRUN_ONCE);
98 }
99
100 static void
k5ev_ctx_break(verto_mod_ctx * ctx)101 k5ev_ctx_break(verto_mod_ctx *ctx)
102 {
103 ev_break(ctx, EVBREAK_ONE);
104 }
105
106 static void
k5ev_ctx_reinitialize(verto_mod_ctx * ctx)107 k5ev_ctx_reinitialize(verto_mod_ctx *ctx)
108 {
109 ev_loop_fork(ctx);
110 }
111
112 static void
libev_callback(EV_P_ ev_watcher * w,int revents)113 libev_callback(EV_P_ ev_watcher *w, int revents)
114 {
115 verto_ev_flag state = VERTO_EV_FLAG_NONE;
116
117 #if EV_MULTIPLICITY
118 /* Match the check in ev.h, which doesn't mark this unused */
119 (void) EV_A;
120 #endif
121
122 if (verto_get_type(w->data)== VERTO_EV_TYPE_CHILD)
123 verto_set_proc_status(w->data, ((ev_child*) w)->rstatus);
124
125 if (revents & EV_READ)
126 state |= VERTO_EV_FLAG_IO_READ;
127 if (revents & EV_WRITE)
128 state |= VERTO_EV_FLAG_IO_WRITE;
129 if (revents & EV_ERROR)
130 state |= VERTO_EV_FLAG_IO_ERROR;
131
132 verto_set_fd_state(w->data, state);
133 verto_fire(w->data);
134 }
135
136 static void
k5ev_ctx_set_flags(verto_mod_ctx * ctx,const verto_ev * ev,verto_mod_ev * evpriv)137 k5ev_ctx_set_flags(verto_mod_ctx *ctx, const verto_ev *ev,
138 verto_mod_ev *evpriv)
139 {
140 if (verto_get_type(ev) == VERTO_EV_TYPE_IO) {
141 int events = EV_NONE;
142
143 if (verto_get_flags(ev) & VERTO_EV_FLAG_IO_READ)
144 events |= EV_READ;
145 if (verto_get_flags(ev) & VERTO_EV_FLAG_IO_WRITE)
146 events |= EV_WRITE;
147
148 ev_io_stop(ctx, (ev_io*) evpriv);
149 ev_io_set(((ev_io*) evpriv), verto_get_fd(ev), events);
150 ev_io_start(ctx, (ev_io*) evpriv);
151 }
152 }
153
154 #define setuptype(type, ...) \
155 w.type = malloc(sizeof(ev_ ## type)); \
156 if (w.type) { \
157 ev_ ## type ## _init(w.type, (EV_CB(type, (*))) __VA_ARGS__); \
158 ev_ ## type ## _start(ctx, w.type); \
159 } \
160 break
161
162 static verto_mod_ev *
k5ev_ctx_add(verto_mod_ctx * ctx,const verto_ev * ev,verto_ev_flag * flags)163 k5ev_ctx_add(verto_mod_ctx *ctx, const verto_ev *ev, verto_ev_flag *flags)
164 {
165 union {
166 ev_watcher *watcher;
167 ev_io *io;
168 ev_timer *timer;
169 ev_idle *idle;
170 ev_signal *signal;
171 ev_child *child;
172 } w;
173 ev_tstamp interval;
174
175 w.watcher = NULL;
176 *flags |= VERTO_EV_FLAG_PERSIST;
177 switch (verto_get_type(ev)) {
178 case VERTO_EV_TYPE_IO:
179 setuptype(io, libev_callback, verto_get_fd(ev), EV_NONE);
180 case VERTO_EV_TYPE_TIMEOUT:
181 interval = ((ev_tstamp) verto_get_interval(ev)) / 1000.0;
182 setuptype(timer, libev_callback, interval, interval);
183 case VERTO_EV_TYPE_IDLE:
184 setuptype(idle, libev_callback);
185 case VERTO_EV_TYPE_SIGNAL:
186 setuptype(signal, libev_callback, verto_get_signal(ev));
187 case VERTO_EV_TYPE_CHILD:
188 *flags &= ~VERTO_EV_FLAG_PERSIST; /* Child events don't persist */
189 setuptype(child, libev_callback, verto_get_proc(ev), 0);
190 default:
191 break; /* Not supported */
192 }
193
194 if (w.watcher) {
195 w.watcher->data = (void*) ev;
196 k5ev_ctx_set_flags(ctx, ev, w.watcher);
197 }
198 return w.watcher;
199 }
200
201 static void
k5ev_ctx_del(verto_mod_ctx * ctx,const verto_ev * ev,verto_mod_ev * evpriv)202 k5ev_ctx_del(verto_mod_ctx *ctx, const verto_ev *ev, verto_mod_ev *evpriv)
203 {
204 switch (verto_get_type(ev)) {
205 case VERTO_EV_TYPE_IO:
206 ev_io_stop(ctx, (ev_io*) evpriv);
207 break;
208 case VERTO_EV_TYPE_TIMEOUT:
209 ev_timer_stop(ctx, (ev_timer*) evpriv);
210 break;
211 case VERTO_EV_TYPE_IDLE:
212 ev_idle_stop(ctx, (ev_idle*) evpriv);
213 break;
214 case VERTO_EV_TYPE_SIGNAL:
215 ev_signal_stop(ctx, (ev_signal*) evpriv);
216 break;
217 case VERTO_EV_TYPE_CHILD:
218 ev_child_stop(ctx, (ev_child*) evpriv);
219 break;
220 default:
221 break;
222 }
223
224 free(evpriv);
225 }
226
227 verto_ctx *verto_new_k5ev(void);
228 verto_ctx *verto_default_k5ev(void);
229
230 VERTO_MODULE(k5ev, NULL,
231 VERTO_EV_TYPE_IO |
232 VERTO_EV_TYPE_TIMEOUT |
233 VERTO_EV_TYPE_IDLE |
234 VERTO_EV_TYPE_SIGNAL |
235 VERTO_EV_TYPE_CHILD);
236