xref: /freebsd/crypto/krb5/src/util/verto/verto-k5ev.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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