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 2938123
vev_bh_update(void *priv, void *a, unsigned u)
97
{
98
        struct vev_root *evb;
99
        struct vev *e;
100
101 2938123
        CAST_OBJ_NOTNULL(evb, priv, VEV_BASE_MAGIC);
102 2938123
        CAST_OBJ_NOTNULL(e, a, VEV_MAGIC);
103 2938123
        assert(u < evb->lpfd);
104 2938123
        e->__binheap_idx = u;
105 2938123
        if (u != VBH_NOIDX) {
106 2484053
                evb->pev[u] = e;
107 2484053
                evb->pfd[u].fd = e->fd;
108 2484053
                evb->pfd[u].events =
109 2484053
                    e->fd_flags & (VEV__RD|VEV__WR|VEV__ERR|VEV__HUP);
110 2484053
        }
111 2938123
}
112
113
static int v_matchproto_(vbh_cmp_t)
114 1707033
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 1707033
        CAST_OBJ_NOTNULL(evb, priv, VEV_BASE_MAGIC);
120 1707033
        CAST_OBJ_NOTNULL(ea, a, VEV_MAGIC);
121 1707033
        CAST_OBJ_NOTNULL(eb, b, VEV_MAGIC);
122 1707033
        return (ea->__when < eb->__when);
123
}
124
125
/*--------------------------------------------------------------------*/
126
127
static int
128 375650
vev_get_pfd(struct vev_root *evb)
129
{
130
        unsigned u;
131
132 375650
        if (evb->lpfd + 1 < evb->npfd)
133 303350
                return (0);
134
135 72300
        if (evb->npfd < 8)
136 49575
                u = 8;
137 22725
        else if (evb->npfd > 256)
138 0
                u = evb->npfd + 256;
139
        else
140 22725
                u = evb->npfd * 2;
141 72300
        evb->npfd = u;
142 72300
        evb->pfd = realloc(evb->pfd, sizeof(*evb->pfd) * u);
143 72300
        AN(evb->pfd);
144 72300
        evb->pev = realloc(evb->pev, sizeof(*evb->pev) * u);
145 72300
        AN(evb->pev);
146 72300
        return (0);
147 375650
}
148
149
/*--------------------------------------------------------------------*/
150
151
static int
152 45400
vev_get_sig(int sig)
153
{
154
        struct vevsig *os;
155
156 45400
        if (sig < vev_nsig)
157 22700
                return (0);
158
159 22700
        os = calloc((sig + 1L), sizeof *os);
160 22700
        if (os == NULL)
161 0
                return (ENOMEM);
162
163 22700
        if (vev_sigs != NULL) {
164 0
                memcpy(os, vev_sigs, vev_nsig * sizeof *os);
165 0
                free(vev_sigs);
166 0
        }
167 22700
        vev_sigs = os;
168 22700
        vev_nsig = sig + 1;
169
170 22700
        return (0);
171 45400
}
172
173
/*--------------------------------------------------------------------*/
174
175
static void
176 100
vev_sighandler(int sig)
177
{
178
        struct vevsig *es;
179
180 100
        assert(sig < vev_nsig);
181 100
        assert(vev_sigs != NULL);
182 100
        es = &vev_sigs[sig];
183 100
        if (!es->happened)
184 100
                es->vevb->psig++;
185 100
        es->happened = 1;
186 100
}
187
188
/*--------------------------------------------------------------------*/
189
190
struct vev_root *
191 49575
VEV_New(void)
192
{
193
        struct vev_root *evb;
194
195 49575
        evb = calloc(1, sizeof *evb);
196 49575
        if (evb == NULL)
197 0
                return (evb);
198 49575
        evb->lpfd = VBH_NOIDX + 1;
199 49575
        if (vev_get_pfd(evb)) {
200 0
                free(evb);
201 0
                return (NULL);
202
        }
203 49575
        evb->magic = VEV_BASE_MAGIC;
204 49575
        evb->binheap = VBH_new(evb, vev_bh_cmp, vev_bh_update);
205 49575
        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 49575
        return (evb);
213 49575
}
214
215
/*--------------------------------------------------------------------*/
216
217
void
218 24375
VEV_Destroy(struct vev_root **evbp)
219
{
220
        struct vev_root *evb;
221
        struct vev *e;
222
223 24375
        TAKE_OBJ_NOTNULL(evb, evbp, VEV_BASE_MAGIC);
224 24375
        assert(pthread_equal(evb->thread, pthread_self()));
225 185137
        while ((e = VBH_root(evb->binheap)) != NULL) {
226 160762
                VEV_Stop(evb, e);
227 160762
                free(e);
228
        }
229 24375
        VBH_destroy(&evb->binheap);
230 24375
        free(evb->pfd);
231 24375
        free(evb->pev);
232 24375
        FREE_OBJ(evb);
233 24375
}
234
235
/*--------------------------------------------------------------------*/
236
237
struct vev *
238 326075
VEV_Alloc(void)
239
{
240
        struct vev *e;
241
242 326075
        e = calloc(1, sizeof *e);
243 326075
        if (e != NULL) {
244 326075
                e->fd = -1;
245 326075
        }
246 326075
        return (e);
247
}
248
249
/*--------------------------------------------------------------------*/
250
251
int
252 326075
VEV_Start(struct vev_root *evb, struct vev *e)
253
{
254
        struct vevsig *es;
255
256 326075
        CHECK_OBJ_NOTNULL(evb, VEV_BASE_MAGIC);
257 326075
        assert(e->magic != VEV_MAGIC);
258 326075
        assert(e->callback != NULL);
259 326075
        assert(e->sig >= 0);
260 326075
        assert(e->timeout >= 0.0);
261 326075
        assert(e->fd < 0 || e->fd_flags);
262 326075
        assert(pthread_equal(evb->thread, pthread_self()));
263
        DBG(evb, "ev_add(%p) fd = %d\n", e, e->fd);
264
265 326075
        if (vev_get_pfd(evb))
266 0
                return (ENOMEM);
267
268 326075
        if (e->sig > 0) {
269 45400
                if (vev_get_sig(e->sig))
270 0
                        return (ENOMEM);
271
272 45400
                assert(e->fd < 0);
273 45400
                es = &vev_sigs[e->sig];
274 45400
                if (es->vev != NULL)
275 0
                        return (EBUSY);
276 45400
                AZ(es->happened);
277 45400
                es->vev = e;
278 45400
                es->vevb = evb;
279 45400
                es->sigact.sa_flags = e->sig_flags;
280 45400
                es->sigact.sa_handler = vev_sighandler;
281 45400
        } else {
282 280675
                es = NULL;
283
        }
284
285 326075
        e->magic = VEV_MAGIC;   /* before VBH_insert() */
286
287 326075
        if (e->timeout != 0.0)
288 115450
                e->__when += VTIM_mono() + e->timeout;
289
        else
290 210625
                e->__when = 9e99;
291
292 326075
        evb->lpfd++;
293 326075
        VBH_insert(evb->binheap, e);
294 326075
        assert(e->__binheap_idx != VBH_NOIDX);
295
296 326075
        e->__vevb = evb;
297 326075
        e->__privflags = 0;
298
299 326075
        if (e->sig > 0) {
300 45400
                assert(es != NULL);
301 45400
                AZ(sigaction(e->sig, &es->sigact, NULL));
302 45400
        }
303
304 326075
        return (0);
305 326075
}
306
307
/*--------------------------------------------------------------------*/
308
309
void
310 324975
VEV_Stop(struct vev_root *evb, struct vev *e)
311
{
312
        struct vevsig *es;
313
314 324975
        CHECK_OBJ_NOTNULL(evb, VEV_BASE_MAGIC);
315 324975
        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 324975
        assert(evb == e->__vevb);
318 324975
        assert(pthread_equal(evb->thread, pthread_self()));
319 324975
        assert(evb->pev[e->__binheap_idx] == e);
320
321 324975
        assert(e->__binheap_idx != VBH_NOIDX);
322 324975
        e->fd = -1;
323 324975
        VBH_delete(evb->binheap, e->__binheap_idx);
324 324975
        assert(e->__binheap_idx == VBH_NOIDX);
325 324975
        evb->lpfd--;
326
327 324975
        if (e->sig > 0) {
328 45400
                assert(e->sig < vev_nsig);
329 45400
                es = &vev_sigs[e->sig];
330 45400
                assert(es->vev == e);
331 45400
                es->vev = NULL;
332 45400
                es->vevb = NULL;
333 45400
                es->sigact.sa_flags = e->sig_flags;
334 45400
                es->sigact.sa_handler = SIG_DFL;
335 45400
                AZ(sigaction(e->sig, &es->sigact, NULL));
336 45400
                es->happened = 0;
337 45400
        }
338
339 324975
        e->__vevb = NULL;
340 324975
        FINI_OBJ(e);
341 324975
}
342
343
/*--------------------------------------------------------------------*/
344
345
int
346 22700
VEV_Loop(struct vev_root *evb)
347
{
348
        int i;
349
350 22700
        CHECK_OBJ_NOTNULL(evb, VEV_BASE_MAGIC);
351 22700
        assert(pthread_equal(evb->thread, pthread_self()));
352 22700
        do
353 825016
                i = VEV_Once(evb);
354 825016
        while (i == 1);
355 22700
        return (i);
356
}
357
358
/*--------------------------------------------------------------------*/
359
360
static int
361 129095
vev_sched_timeout(struct vev_root *evb, struct vev *e, vtim_mono t)
362
{
363
        int i;
364
365
366 129095
        i = e->callback(e, 0);
367 129095
        if (i) {
368 0
                VEV_Stop(evb, e);
369 0
                free(e);
370 0
        } else {
371 129095
                e->__when = t + e->timeout;
372 129095
                VBH_delete(evb->binheap, e->__binheap_idx);
373 129095
                VBH_insert(evb->binheap, e);
374
        }
375 129095
        return (1);
376
}
377
378
static int
379 75
vev_sched_signal(struct vev_root *evb)
380
{
381 75
        int i, j, retval = 1;
382
        struct vevsig *es;
383
        struct vev *e;
384
385 75
        es = vev_sigs;
386 1275
        for (j = 0; j < vev_nsig; j++, es++) {
387 1200
                if (!es->happened || es->vevb != evb)
388 1125
                        continue;
389 75
                evb->psig--;
390 75
                es->happened = 0;
391 75
                e = es->vev;
392 75
                assert(e != NULL);
393 75
                i = e->callback(e, VEV__SIG);
394 75
                if (i) {
395 75
                        VEV_Stop(evb, e);
396 75
                        free(e);
397 75
                }
398 75
                if (i < 0)
399 75
                        retval = i;
400 75
        }
401 75
        return (retval);
402
}
403
404
int
405 907766
VEV_Once(struct vev_root *evb)
406
{
407
        double t;
408
        struct vev *e;
409 907766
        int i, k, tmo, retval = 1;
410
        unsigned u;
411
412 907766
        CHECK_OBJ_NOTNULL(evb, VEV_BASE_MAGIC);
413 907766
        assert(pthread_equal(evb->thread, pthread_self()));
414 907766
        assert(evb->lpfd < evb->npfd);
415
416 907766
        if (evb->psig)
417 0
                return (vev_sched_signal(evb));
418
419 907766
        tmo = INFTIM;
420 907766
        e = VBH_root(evb->binheap);
421 907766
        if (e != NULL) {
422 882641
                CHECK_OBJ(e, VEV_MAGIC);
423 882641
                assert(e->__binheap_idx == VBH_NOIDX + 1);
424 882641
                t = VTIM_mono();
425 882641
                if (e->__when <= t)
426 32819
                        return (vev_sched_timeout(evb, e, t));
427 849822
                if (e->__when < 9e99)
428 816851
                        tmo = (int)((e->__when - t) * 1e3);
429 849822
                if (tmo == 0)
430 4983
                        tmo = 1;
431 849822
        }
432
433 874947
        if (tmo == INFTIM && evb->lpfd == VBH_NOIDX + 1)
434 25250
                return (0);
435
436 849697
        i = poll(evb->pfd + 1, evb->lpfd - 1, tmo);
437 849697
        if (i == -1 && errno == EINTR)
438 75
                return (vev_sched_signal(evb));
439 849622
        if (i == -1)
440 0
                return (-1);
441
442 849622
        if (i == 0) {
443 100544
                assert(e != NULL);
444 100544
                t = VTIM_mono();
445 100544
                if (e->__when <= t)
446 96276
                        return (vev_sched_timeout(evb, e, t));
447 4268
        }
448
449 753346
        k = 0;
450 7848087
        for (u = 1; u < evb->lpfd; u++) {
451 7094741
                evb->pev[u]->fd_events = evb->pfd[u].revents;
452 7094741
                if (evb->pev[u]->fd_events)
453 771137
                        k++;
454 7094741
        }
455 753346
        assert(k == i);
456
457
        DBG(evb, "EVENTS %d\n", i);
458 1504123
        while (i > 0) {
459 7777172
                for (u = VBH_NOIDX + 1; u < evb->lpfd; u++) {
460 7026395
                        e = evb->pev[u];
461 7026395
                        if (e->fd_events == 0)
462 6255383
                                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 771012
                        k = e->callback(e, e->fd_events);
466 771012
                        e->fd_events = 0;
467 771012
                        i--;
468 771012
                        if (k) {
469 94813
                                VEV_Stop(evb, e);
470 94813
                                free(e);
471 94813
                        }
472 771012
                        if (k < 0)
473 22625
                                retval = k;
474 771012
                }
475
        }
476 753346
        AZ(i);
477 753346
        return (retval);
478 907766
}