varnish-cache/lib/libvarnish/vev.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2009 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6
 *
7
 * SPDX-License-Identifier: BSD-2-Clause
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 */
30
31
#include "config.h"
32
33
#include <time.h>
34
#include <poll.h>
35
#include <pthread.h>
36
#include <signal.h>
37
#include <stdio.h>
38
#include <stdlib.h>
39
#include <string.h>
40
41
#include "vdef.h"
42
#include "miniobj.h"
43
#include "vas.h"
44
45
#include "vbh.h"
46
#include "vev.h"
47
#include "vtim.h"
48
49
#undef DEBUG_EVENTS
50
51
/* INFTIM indicates an infinite timeout for poll(2) */
52
#ifndef INFTIM
53
#define INFTIM -1
54
#endif
55
56
struct vevsig {
57
        struct vev_root         *vevb;
58
        struct vev              *vev;
59
        struct sigaction        sigact;
60
        unsigned char           happened;
61
};
62
63
static struct vevsig            *vev_sigs;
64
static int                      vev_nsig;
65
66
struct vev_root {
67
        unsigned                magic;
68
#define VEV_BASE_MAGIC          0x477bcf3d
69
        struct pollfd           *pfd;
70
        struct vev              **pev;
71
        unsigned                npfd;
72
        unsigned                lpfd;
73
        struct vbh              *binheap;
74
        unsigned                psig;
75
        pthread_t               thread;
76
#ifdef DEBUG_EVENTS
77
        FILE                    *debug;
78
#endif
79
};
80
81
/*--------------------------------------------------------------------*/
82
83
#ifdef DEBUG_EVENTS
84
#define DBG(evb, ...) do {                              \
85
        if ((evb)->debug != NULL)                       \
86
                fprintf((evb)->debug, __VA_ARGS__);     \
87
        } while (0);
88
#else
89
#define DBG(evb, ...)   /* ... */
90
//#define DBG(evb, ...) fprintf(stderr, __VA_ARGS__);
91
#endif
92
93
/*--------------------------------------------------------------------*/
94
95
static void v_matchproto_(vbh_update_t)
96 2998080
vev_bh_update(void *priv, void *a, unsigned u)
97
{
98
        struct vev_root *evb;
99
        struct vev *e;
100
101 2998080
        CAST_OBJ_NOTNULL(evb, priv, VEV_BASE_MAGIC);
102 2998080
        CAST_OBJ_NOTNULL(e, a, VEV_MAGIC);
103 2998080
        assert(u < evb->lpfd);
104 2998080
        e->__binheap_idx = u;
105 2998080
        if (u != VBH_NOIDX) {
106 2526607
                evb->pev[u] = e;
107 2526607
                evb->pfd[u].fd = e->fd;
108 2526607
                evb->pfd[u].events =
109 2526607
                    e->fd_flags & (VEV__RD|VEV__WR|VEV__ERR|VEV__HUP);
110 2526607
        }
111 2998080
}
112
113
static int v_matchproto_(vbh_cmp_t)
114 1721541
vev_bh_cmp(void *priv, const void *a, const void *b)
115
{
116
        struct vev_root *evb;
117
        const struct vev *ea, *eb;
118
119 1721541
        CAST_OBJ_NOTNULL(evb, priv, VEV_BASE_MAGIC);
120 1721541
        CAST_OBJ_NOTNULL(ea, a, VEV_MAGIC);
121 1721541
        CAST_OBJ_NOTNULL(eb, b, VEV_MAGIC);
122 1721541
        return (ea->__when < eb->__when);
123
}
124
125
/*--------------------------------------------------------------------*/
126
127
static int
128 405104
vev_get_pfd(struct vev_root *evb)
129
{
130
        unsigned u;
131
132 405104
        if (evb->lpfd + 1 < evb->npfd)
133 327096
                return (0);
134
135 78008
        if (evb->npfd < 8)
136 53424
                u = 8;
137 24584
        else if (evb->npfd > 256)
138 0
                u = evb->npfd + 256;
139
        else
140 24584
                u = evb->npfd * 2;
141 78008
        evb->npfd = u;
142 78008
        evb->pfd = realloc(evb->pfd, sizeof(*evb->pfd) * u);
143 78008
        AN(evb->pfd);
144 78008
        evb->pev = realloc(evb->pev, sizeof(*evb->pev) * u);
145 78008
        AN(evb->pev);
146 78008
        return (0);
147 405104
}
148
149
/*--------------------------------------------------------------------*/
150
151
static int
152 49112
vev_get_sig(int sig)
153
{
154
        struct vevsig *os;
155
156 49112
        if (sig < vev_nsig)
157 24556
                return (0);
158
159 24556
        os = calloc((sig + 1L), sizeof *os);
160 24556
        if (os == NULL)
161 0
                return (ENOMEM);
162
163 24556
        if (vev_sigs != NULL) {
164 0
                memcpy(os, vev_sigs, vev_nsig * sizeof *os);
165 0
                free(vev_sigs);
166 0
        }
167 24556
        vev_sigs = os;
168 24556
        vev_nsig = sig + 1;
169
170 24556
        return (0);
171 49112
}
172
173
/*--------------------------------------------------------------------*/
174
175
static void
176 84
vev_sighandler(int sig)
177
{
178
        struct vevsig *es;
179
180 84
        assert(sig < vev_nsig);
181 84
        assert(vev_sigs != NULL);
182 84
        es = &vev_sigs[sig];
183 84
        if (!es->happened)
184 84
                es->vevb->psig++;
185 84
        es->happened = 1;
186 84
}
187
188
/*--------------------------------------------------------------------*/
189
190
struct vev_root *
191 53424
VEV_New(void)
192
{
193
        struct vev_root *evb;
194
195 53424
        evb = calloc(1, sizeof *evb);
196 53424
        if (evb == NULL)
197 0
                return (evb);
198 53424
        evb->lpfd = VBH_NOIDX + 1;
199 53424
        if (vev_get_pfd(evb)) {
200 0
                free(evb);
201 0
                return (NULL);
202
        }
203 53424
        evb->magic = VEV_BASE_MAGIC;
204 53424
        evb->binheap = VBH_new(evb, vev_bh_cmp, vev_bh_update);
205 53424
        evb->thread = pthread_self();
206
#ifdef DEBUG_EVENTS
207
        evb->debug = fopen("/tmp/_.events", "w");
208
        AN(evb->debug);
209
        setbuf(evb->debug, NULL);
210
        DBG(evb, "\n\nStart debugging\n");
211
#endif
212 53424
        return (evb);
213 53424
}
214
215
/*--------------------------------------------------------------------*/
216
217
void
218 26180
VEV_Destroy(struct vev_root **evbp)
219
{
220
        struct vev_root *evb;
221
        struct vev *e;
222
223 26180
        TAKE_OBJ_NOTNULL(evb, evbp, VEV_BASE_MAGIC);
224 26180
        assert(pthread_equal(evb->thread, pthread_self()));
225 199470
        while ((e = VBH_root(evb->binheap)) != NULL) {
226 173290
                VEV_Stop(evb, e);
227 173290
                free(e);
228
        }
229 26180
        VBH_destroy(&evb->binheap);
230 26180
        free(evb->pfd);
231 26180
        free(evb->pev);
232 26180
        FREE_OBJ(evb);
233 26180
}
234
235
/*--------------------------------------------------------------------*/
236
237
struct vev *
238 351680
VEV_Alloc(void)
239
{
240
        struct vev *e;
241
242 351680
        e = calloc(1, sizeof *e);
243 351680
        if (e != NULL) {
244 351680
                e->fd = -1;
245 351680
        }
246 351680
        return (e);
247
}
248
249
/*--------------------------------------------------------------------*/
250
251
int
252 351680
VEV_Start(struct vev_root *evb, struct vev *e)
253
{
254
        struct vevsig *es;
255
256 351680
        CHECK_OBJ_NOTNULL(evb, VEV_BASE_MAGIC);
257 351680
        assert(e->magic != VEV_MAGIC);
258 351680
        assert(e->callback != NULL);
259 351680
        assert(e->sig >= 0);
260 351680
        assert(e->timeout >= 0.0);
261 351680
        assert(e->fd < 0 || e->fd_flags);
262 351680
        assert(pthread_equal(evb->thread, pthread_self()));
263
        DBG(evb, "ev_add(%p) fd = %d\n", e, e->fd);
264
265 351680
        if (vev_get_pfd(evb))
266 0
                return (ENOMEM);
267
268 351680
        if (e->sig > 0) {
269 49112
                if (vev_get_sig(e->sig))
270 0
                        return (ENOMEM);
271
272 49112
                assert(e->fd < 0);
273 49112
                es = &vev_sigs[e->sig];
274 49112
                if (es->vev != NULL)
275 0
                        return (EBUSY);
276 49112
                AZ(es->happened);
277 49112
                es->vev = e;
278 49112
                es->vevb = evb;
279 49112
                es->sigact.sa_flags = e->sig_flags;
280 49112
                es->sigact.sa_handler = vev_sighandler;
281 49112
        } else {
282 302568
                es = NULL;
283
        }
284
285 351680
        e->magic = VEV_MAGIC;   /* before VBH_insert() */
286
287 351680
        if (e->timeout != 0.0)
288 124712
                e->__when += VTIM_mono() + e->timeout;
289
        else
290 226968
                e->__when = 9e99;
291
292 351680
        evb->lpfd++;
293 351680
        VBH_insert(evb->binheap, e);
294 351680
        assert(e->__binheap_idx != VBH_NOIDX);
295
296 351680
        e->__vevb = evb;
297 351680
        e->__privflags = 0;
298
299 351680
        if (e->sig > 0) {
300 49112
                assert(es != NULL);
301 49112
                AZ(sigaction(e->sig, &es->sigact, NULL));
302 49112
        }
303
304 351680
        return (0);
305 351680
}
306
307
/*--------------------------------------------------------------------*/
308
309
void
310 350952
VEV_Stop(struct vev_root *evb, struct vev *e)
311
{
312
        struct vevsig *es;
313
314 350952
        CHECK_OBJ_NOTNULL(evb, VEV_BASE_MAGIC);
315 350952
        CHECK_OBJ_NOTNULL(e, VEV_MAGIC);
316
        DBG(evb, "ev_del(%p) fd = %d i=%u L=%d\n", e, e->fd, e->__binheap_idx, evb->lpfd);
317 350952
        assert(evb == e->__vevb);
318 350952
        assert(pthread_equal(evb->thread, pthread_self()));
319 350952
        assert(evb->pev[e->__binheap_idx] == e);
320
321 350952
        assert(e->__binheap_idx != VBH_NOIDX);
322 350952
        e->fd = -1;
323 350952
        VBH_delete(evb->binheap, e->__binheap_idx);
324 350952
        assert(e->__binheap_idx == VBH_NOIDX);
325 350952
        evb->lpfd--;
326
327 350952
        if (e->sig > 0) {
328 49056
                assert(e->sig < vev_nsig);
329 49056
                es = &vev_sigs[e->sig];
330 49056
                assert(es->vev == e);
331 49056
                es->vev = NULL;
332 49056
                es->vevb = NULL;
333 49056
                es->sigact.sa_flags = e->sig_flags;
334 49056
                es->sigact.sa_handler = SIG_DFL;
335 49056
                AZ(sigaction(e->sig, &es->sigact, NULL));
336 49056
                es->happened = 0;
337 49056
        }
338
339 350952
        e->__vevb = NULL;
340 350952
        FINI_OBJ(e);
341 350952
}
342
343
/*--------------------------------------------------------------------*/
344
345
int
346 24556
VEV_Loop(struct vev_root *evb)
347
{
348
        int i;
349
350 24556
        CHECK_OBJ_NOTNULL(evb, VEV_BASE_MAGIC);
351 24556
        assert(pthread_equal(evb->thread, pthread_self()));
352 24556
        do
353 868722
                i = VEV_Once(evb);
354 868722
        while (i == 1);
355 24556
        return (i);
356
}
357
358
/*--------------------------------------------------------------------*/
359
360
static int
361 120521
vev_sched_timeout(struct vev_root *evb, struct vev *e, vtim_mono t)
362
{
363
        int i;
364
365
366 120521
        i = e->callback(e, 0);
367 120521
        if (i) {
368 0
                VEV_Stop(evb, e);
369 0
                free(e);
370 0
        } else {
371 120521
                e->__when = t + e->timeout;
372 120521
                VBH_delete(evb->binheap, e->__binheap_idx);
373 120521
                VBH_insert(evb->binheap, e);
374
        }
375 120521
        return (1);
376
}
377
378
static int
379 84
vev_sched_signal(struct vev_root *evb)
380
{
381 84
        int i, j, retval = 1;
382
        struct vevsig *es;
383
        struct vev *e;
384
385 84
        es = vev_sigs;
386 1428
        for (j = 0; j < vev_nsig; j++, es++) {
387 1344
                if (!es->happened || es->vevb != evb)
388 1260
                        continue;
389 84
                evb->psig--;
390 84
                es->happened = 0;
391 84
                e = es->vev;
392 84
                assert(e != NULL);
393 84
                i = e->callback(e, VEV__SIG);
394 84
                if (i) {
395 84
                        VEV_Stop(evb, e);
396 84
                        free(e);
397 84
                }
398 84
                if (i < 0)
399 84
                        retval = i;
400 84
        }
401 84
        return (retval);
402
}
403
404
int
405 955165
VEV_Once(struct vev_root *evb)
406
{
407
        double t;
408
        struct vev *e;
409 955165
        int i, k, tmo, retval = 1;
410
        unsigned u;
411
412 955165
        CHECK_OBJ_NOTNULL(evb, VEV_BASE_MAGIC);
413 955165
        assert(pthread_equal(evb->thread, pthread_self()));
414 955165
        assert(evb->lpfd < evb->npfd);
415
416 955165
        if (evb->psig)
417 0
                return (vev_sched_signal(evb));
418
419 955165
        tmo = INFTIM;
420 955165
        e = VBH_root(evb->binheap);
421 955165
        if (e != NULL) {
422 928032
                CHECK_OBJ(e, VEV_MAGIC);
423 928032
                assert(e->__binheap_idx == VBH_NOIDX + 1);
424 928032
                t = VTIM_mono();
425 928032
                if (e->__when <= t)
426 36953
                        return (vev_sched_timeout(evb, e, t));
427 891079
                if (e->__when < 9e99)
428 858439
                        tmo = (int)((e->__when - t) * 1e3);
429 891079
                if (tmo == 0)
430 4033
                        tmo = 1;
431 891079
        }
432
433 918212
        if (tmo == INFTIM && evb->lpfd == VBH_NOIDX + 1)
434 27244
                return (0);
435
436 890968
        i = poll(evb->pfd + 1, evb->lpfd - 1, tmo);
437 890968
        if (i == -1 && errno == EINTR)
438 84
                return (vev_sched_signal(evb));
439 890884
        if (i == -1)
440 0
                return (-1);
441
442 890884
        if (i == 0) {
443 86936
                assert(e != NULL);
444 86936
                t = VTIM_mono();
445 86936
                if (e->__when <= t)
446 83568
                        return (vev_sched_timeout(evb, e, t));
447 3368
        }
448
449 807316
        k = 0;
450 8431363
        for (u = 1; u < evb->lpfd; u++) {
451 7624047
                evb->pev[u]->fd_events = evb->pfd[u].revents;
452 7624047
                if (evb->pev[u]->fd_events)
453 828236
                        k++;
454 7624047
        }
455 807316
        assert(k == i);
456
457
        DBG(evb, "EVENTS %d\n", i);
458 1613120
        while (i > 0) {
459 8362040
                for (u = VBH_NOIDX + 1; u < evb->lpfd; u++) {
460 7556236
                        e = evb->pev[u];
461 7556236
                        if (e->fd_events == 0)
462 6728113
                                continue;
463
                        DBG(evb, "EVENT %p u=%u fd=%d ev=0x%x %d\n",
464
                            e, u, e->fd, e->fd_events, i);
465 828123
                        k = e->callback(e, e->fd_events);
466 828123
                        e->fd_events = 0;
467 828123
                        i--;
468 828123
                        if (k) {
469 102706
                                VEV_Stop(evb, e);
470 102706
                                free(e);
471 102706
                        }
472 828123
                        if (k < 0)
473 24444
                                retval = k;
474 828123
                }
475
        }
476 807316
        AZ(i);
477 807316
        return (retval);
478 955165
}