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
        siginfo_t               siginfo[1];
62
};
63
64
static struct vevsig            *vev_sigs;
65
static int                      vev_nsig;
66
67
struct vev_root {
68
        unsigned                magic;
69
#define VEV_BASE_MAGIC          0x477bcf3d
70
        unsigned                n_fd_events;
71
        struct pollfd           *pfd;
72
        struct vev              **pev;
73
        unsigned                npfd;
74
        unsigned                lpfd;
75
        struct vbh              *binheap;
76
        unsigned                psig;
77
        pthread_t               thread;
78
#ifdef DEBUG_EVENTS
79
        FILE                    *debug;
80
#endif
81
};
82
83
/*--------------------------------------------------------------------*/
84
85
#ifdef DEBUG_EVENTS
86
#define DBG(evb, ...) do {                              \
87
        if ((evb)->debug != NULL)                       \
88
                fprintf((evb)->debug, __VA_ARGS__);     \
89
        } while (0);
90
#else
91
#define DBG(evb, ...)   /* ... */
92
//#define DBG(evb, ...) fprintf(stderr, __VA_ARGS__);
93
#endif
94
95
/*--------------------------------------------------------------------*/
96
97
static void v_matchproto_(vbh_update_t)
98 4962176
vev_bh_update(void *priv, void *a, unsigned u)
99
{
100
        struct vev_root *evb;
101
        struct vev *e;
102
103 4962176
        CAST_OBJ_NOTNULL(evb, priv, VEV_BASE_MAGIC);
104 4962176
        CAST_OBJ_NOTNULL(e, a, VEV_MAGIC);
105 4962176
        assert(u < evb->lpfd);
106 4962176
        e->__binheap_idx = u;
107 4962176
        if (u != VBH_NOIDX) {
108 4186642
                evb->pev[u] = e;
109 4186642
                evb->pfd[u].fd = e->fd;
110 4186642
                evb->pfd[u].events =
111 4186642
                    e->fd_flags & (VEV__RD|VEV__WR|VEV__ERR|VEV__HUP);
112 4186642
        }
113 4962176
}
114
115
static int v_matchproto_(vbh_cmp_t)
116 2854749
vev_bh_cmp(void *priv, const void *a, const void *b)
117
{
118
        struct vev_root *evb;
119
        const struct vev *ea, *eb;
120
121 2854749
        CAST_OBJ_NOTNULL(evb, priv, VEV_BASE_MAGIC);
122 2854749
        CAST_OBJ_NOTNULL(ea, a, VEV_MAGIC);
123 2854749
        CAST_OBJ_NOTNULL(eb, b, VEV_MAGIC);
124 2854749
        return (ea->__when < eb->__when);
125
}
126
127
/*--------------------------------------------------------------------*/
128
129
static int
130 684080
vev_get_pfd(struct vev_root *evb)
131
{
132
        unsigned u;
133
134 684080
        if (evb->lpfd + 1 < evb->npfd)
135 524680
                return (0);
136
137 159400
        if (evb->npfd < 8)
138 121760
                u = 8;
139 37640
        else if (evb->npfd > 256)
140 0
                u = evb->npfd + 256;
141
        else
142 37640
                u = evb->npfd * 2;
143 159400
        evb->npfd = u;
144 159400
        evb->pfd = realloc(evb->pfd, sizeof(*evb->pfd) * u);
145 159400
        AN(evb->pfd);
146 159400
        evb->pev = realloc(evb->pev, sizeof(*evb->pev) * u);
147 159400
        AN(evb->pev);
148 159400
        return (0);
149 684080
}
150
151
/*--------------------------------------------------------------------*/
152
153
static int
154 74720
vev_get_sig(int sig)
155
{
156
        struct vevsig *os;
157
158 74720
        if (sig < vev_nsig)
159 37360
                return (0);
160
161 37360
        os = calloc((sig + 1L), sizeof *os);
162 37360
        if (os == NULL)
163 0
                return (ENOMEM);
164
165 37360
        if (vev_sigs != NULL) {
166 0
                memcpy(os, vev_sigs, vev_nsig * sizeof *os);
167 0
                free(vev_sigs);
168 0
        }
169 37360
        vev_sigs = os;
170 37360
        vev_nsig = sig + 1;
171
172 37360
        return (0);
173 74720
}
174
175
/*--------------------------------------------------------------------*/
176
177
static void
178 200
vev_sigaction(int sig, siginfo_t *siginfo, void *ctx)
179
{
180
        struct vevsig *es;
181
182 200
        (void)ctx;
183 200
        assert(sig < vev_nsig);
184 200
        assert(vev_sigs != NULL);
185 200
        es = &vev_sigs[sig];
186 200
        if (!es->happened) {
187 200
                es->vevb->psig++;
188 200
                memcpy(es->siginfo, siginfo, sizeof *es->siginfo);
189 200
                es->vev->siginfo = es->siginfo;
190 200
        }
191 200
        es->happened = 1;
192 200
}
193
194
/*--------------------------------------------------------------------*/
195
196
struct vev_root *
197 121760
VEV_New(void)
198
{
199
        struct vev_root *evb;
200
201 121760
        evb = calloc(1, sizeof *evb);
202 121760
        if (evb == NULL)
203 0
                return (evb);
204 121760
        evb->lpfd = VBH_NOIDX + 1;
205 121760
        if (vev_get_pfd(evb)) {
206 0
                free(evb);
207 0
                return (NULL);
208
        }
209 121760
        evb->magic = VEV_BASE_MAGIC;
210 121760
        evb->binheap = VBH_new(evb, vev_bh_cmp, vev_bh_update);
211 121760
        evb->thread = pthread_self();
212
#ifdef DEBUG_EVENTS
213
        evb->debug = fopen("/tmp/_.events", "w");
214
        AN(evb->debug);
215
        setbuf(evb->debug, NULL);
216
        DBG(evb, "\n\nStart debugging\n");
217
#endif
218 121760
        return (evb);
219 121760
}
220
221
/*--------------------------------------------------------------------*/
222
223
void
224 40080
VEV_Destroy(struct vev_root **evbp)
225
{
226
        struct vev_root *evb;
227
        struct vev *e;
228
229 40080
        TAKE_OBJ_NOTNULL(evb, evbp, VEV_BASE_MAGIC);
230 40080
        assert(pthread_equal(evb->thread, pthread_self()));
231 304779
        while ((e = VBH_root(evb->binheap)) != NULL) {
232 264699
                VEV_Stop(evb, e);
233 264699
                free(e);
234
        }
235 40080
        VBH_destroy(&evb->binheap);
236 40080
        free(evb->pfd);
237 40080
        free(evb->pev);
238 40080
        FREE_OBJ(evb);
239 40080
}
240
241
/*--------------------------------------------------------------------*/
242
243
struct vev *
244 562320
VEV_Alloc(void)
245
{
246
        struct vev *e;
247
248 562320
        e = calloc(1, sizeof *e);
249 562320
        if (e != NULL) {
250 562320
                e->fd = -1;
251 562320
        }
252 562320
        return (e);
253
}
254
255
/*--------------------------------------------------------------------*/
256
257
int
258 562320
VEV_Start(struct vev_root *evb, struct vev *e)
259
{
260
        struct vevsig *es;
261
262 562320
        CHECK_OBJ_NOTNULL(evb, VEV_BASE_MAGIC);
263 562320
        assert(e->magic != VEV_MAGIC);
264 562320
        assert(e->callback != NULL);
265 562320
        assert(e->sig >= 0);
266 562320
        assert(e->timeout >= 0.0);
267 562320
        assert(e->fd < 0 || e->fd_flags);
268 562320
        assert(pthread_equal(evb->thread, pthread_self()));
269
        DBG(evb, "ev_add(%p) fd = %d\n", e, e->fd);
270
271 562320
        if (vev_get_pfd(evb))
272 0
                return (ENOMEM);
273
274 562320
        if (e->sig > 0) {
275 74720
                if (vev_get_sig(e->sig))
276 0
                        return (ENOMEM);
277
278 74720
                assert(e->fd < 0);
279 74720
                es = &vev_sigs[e->sig];
280 74720
                if (es->vev != NULL)
281 0
                        return (EBUSY);
282 74720
                AZ(es->happened);
283 74720
                es->vev = e;
284 74720
                es->vevb = evb;
285 74720
                es->sigact.sa_flags = e->sig_flags | SA_SIGINFO;
286 74720
                es->sigact.sa_sigaction = vev_sigaction;
287 74720
        } else {
288 487600
                es = NULL;
289
        }
290
291 562320
        e->magic = VEV_MAGIC;   /* before VBH_insert() */
292
293 562320
        if (e->timeout != 0.0)
294 202920
                e->__when += VTIM_mono() + e->timeout;
295
        else
296 359400
                e->__when = 9e99;
297
298 562320
        evb->lpfd++;
299 562320
        VBH_insert(evb->binheap, e);
300 562320
        assert(e->__binheap_idx != VBH_NOIDX);
301
302 562320
        e->__vevb = evb;
303 562320
        e->__privflags = 0;
304
305 562320
        if (e->sig > 0) {
306 74720
                assert(es != NULL);
307 74720
                AZ(sigaction(e->sig, &es->sigact, NULL));
308 74720
        }
309
310 562320
        return (0);
311 562320
}
312
313
/*--------------------------------------------------------------------*/
314
315
void
316 559182
VEV_Stop(struct vev_root *evb, struct vev *e)
317
{
318
        struct vevsig *es;
319
320 559182
        CHECK_OBJ_NOTNULL(evb, VEV_BASE_MAGIC);
321 559182
        CHECK_OBJ_NOTNULL(e, VEV_MAGIC);
322
        DBG(evb, "ev_del(%p) fd = %d i=%u L=%d\n", e, e->fd, e->__binheap_idx, evb->lpfd);
323 559182
        assert(evb == e->__vevb);
324 559182
        assert(pthread_equal(evb->thread, pthread_self()));
325 559182
        assert(evb->pev[e->__binheap_idx] == e);
326
327 559182
        assert(e->__binheap_idx != VBH_NOIDX);
328 559182
        e->fd = -1;
329 559182
        VBH_delete(evb->binheap, e->__binheap_idx);
330 559182
        assert(e->__binheap_idx == VBH_NOIDX);
331 559182
        evb->lpfd--;
332
333 559182
        if (e->fd_events) {
334 0
                assert(evb->n_fd_events > 0);
335 0
                evb->n_fd_events--;
336 0
                e->fd_events = 0;
337 0
        }
338
339 559182
        if (e->sig > 0) {
340 74720
                assert(e->sig < vev_nsig);
341 74720
                es = &vev_sigs[e->sig];
342 74720
                assert(es->vev == e);
343 74720
                es->vev = NULL;
344 74720
                es->vevb = NULL;
345 74720
                es->sigact.sa_flags = 0;
346 74720
                es->sigact.sa_handler = SIG_DFL;
347 74720
                AZ(sigaction(e->sig, &es->sigact, NULL));
348 74720
                es->happened = 0;
349 74720
        }
350
351 559182
        e->__vevb = NULL;
352 559182
        FINI_OBJ(e);
353 559182
}
354
355
/*--------------------------------------------------------------------*/
356
357
int
358 37360
VEV_Loop(struct vev_root *evb)
359
{
360
        int i;
361
362 37360
        CHECK_OBJ_NOTNULL(evb, VEV_BASE_MAGIC);
363 37360
        assert(pthread_equal(evb->thread, pthread_self()));
364 37360
        do
365 1367541
                i = VEV_Once(evb);
366 1367541
        while (i == 1);
367 37360
        return (i);
368
}
369
370
/*--------------------------------------------------------------------*/
371
372
static int
373 216352
vev_sched_timeout(struct vev_root *evb, struct vev *e, vtim_mono t)
374
{
375
        int i;
376
377
378 216352
        i = e->callback(e, 0);
379 216352
        if (i) {
380 0
                VEV_Stop(evb, e);
381 0
                free(e);
382 0
        } else {
383 216352
                e->__when = t + e->timeout;
384 216352
                VBH_delete(evb->binheap, e->__binheap_idx);
385 216352
                VBH_insert(evb->binheap, e);
386
        }
387 216352
        return (1);
388
}
389
390
static int
391 160
vev_sched_signal(struct vev_root *evb)
392
{
393 160
        int i, j, retval = 1;
394
        struct vevsig *es;
395
        struct vev *e;
396
397 160
        es = vev_sigs;
398 2720
        for (j = 0; j < vev_nsig; j++, es++) {
399 2560
                if (!es->happened || es->vevb != evb)
400 2400
                        continue;
401 160
                evb->psig--;
402 160
                es->happened = 0;
403 160
                e = es->vev;
404 160
                assert(e != NULL);
405 160
                i = e->callback(e, VEV__SIG);
406 160
                if (e->siginfo != NULL) {
407 160
                        e->siginfo = NULL;
408 160
                        memset(es->siginfo, 0, sizeof *es->siginfo);
409 160
                }
410 160
                if (i) {
411 160
                        VEV_Stop(evb, e);
412 160
                        free(e);
413 160
                }
414 160
                if (i < 0)
415 160
                        retval = i;
416 160
        }
417 160
        return (retval);
418
}
419
420
int
421 1623099
VEV_Once(struct vev_root *evb)
422
{
423
        double t;
424
        struct vev *e;
425 1623099
        int i, k, tmo, retval = 1;
426
        unsigned u;
427
        int progress;
428
429 1623099
        CHECK_OBJ_NOTNULL(evb, VEV_BASE_MAGIC);
430 1623099
        assert(pthread_equal(evb->thread, pthread_self()));
431 1623099
        assert(evb->lpfd < evb->npfd);
432
433 1623099
        if (evb->psig)
434 0
                return (vev_sched_signal(evb));
435
436 1623099
        tmo = INFTIM;
437 1623099
        e = VBH_root(evb->binheap);
438 1623099
        if (e != NULL) {
439 1581779
                CHECK_OBJ(e, VEV_MAGIC);
440 1581779
                assert(e->__binheap_idx == VBH_NOIDX + 1);
441 1581779
                t = VTIM_mono();
442 1581779
                if (e->__when <= t)
443 53328
                        return (vev_sched_timeout(evb, e, t));
444 1528451
                if (e->__when < 9e99)
445 1366158
                        tmo = (int)((e->__when - t) * 1e3);
446 1528451
                if (tmo == 0)
447 8769
                        tmo = 1;
448 1528451
        }
449
450 1569771
        if (tmo == INFTIM && evb->lpfd == VBH_NOIDX + 1)
451 41520
                return (0);
452
453 1528251
        i = poll(evb->pfd + 1, evb->lpfd - 1, tmo);
454 1528251
        if (i == -1 && errno == EINTR)
455 160
                return (vev_sched_signal(evb));
456 1528091
        if (i == -1)
457 0
                return (-1);
458
459 1528091
        if (i == 0) {
460 170517
                assert(e != NULL);
461 170517
                t = VTIM_mono();
462 170517
                if (e->__when <= t)
463 163024
                        return (vev_sched_timeout(evb, e, t));
464 7493
        }
465
466 1365067
        AZ(evb->n_fd_events);
467 13231755
        for (u = 1; u < evb->lpfd; u++) {
468 11866688
                AZ(evb->pev[u]->fd_events);
469 11866688
                evb->pev[u]->fd_events = evb->pfd[u].revents;
470 11866688
                if (evb->pev[u]->fd_events)
471 1394431
                        evb->n_fd_events++;
472 11866688
        }
473 1365067
        assert(evb->n_fd_events == i);
474
475
        DBG(evb, "EVENTS %d\n", i);
476 2726012
        while (evb->n_fd_events > 0) {
477 1360945
                progress = 0;
478 13112329
                for (u = VBH_NOIDX + 1; u < evb->lpfd; u++) {
479 11751384
                        e = evb->pev[u];
480 11751384
                        if (e->fd_events == 0)
481 10357153
                                continue;
482
                        DBG(evb, "EVENT %p u=%u fd=%d ev=0x%x %d\n",
483
                            e, u, e->fd, e->fd_events, i);
484 1394231
                        k = e->callback(e, e->fd_events);
485 1394231
                        e->fd_events = 0;
486 1394231
                        assert(evb->n_fd_events > 0);
487 1394231
                        evb->n_fd_events--;
488 1394231
                        progress++;
489 1394231
                        if (k) {
490 167872
                                VEV_Stop(evb, e);
491 167872
                                free(e);
492 167872
                        }
493 1394231
                        if (k < 0)
494 37200
                                retval = k;
495 1394231
                }
496 1360945
                assert(progress > 0);
497
        }
498
499 1365067
        return (retval);
500 1623099
}