source: lib/libvarnish/vev.c @ 8aa1d8

Revision 8aa1d8, 11.1 KB checked in by Poul-Henning Kamp <phk@…>, 3 years ago (diff)

Eliminate nested <*.h> includes from include/*

Sort #includes according to rules which are for me to know and you
to guess.

  • Property mode set to 100644
Line 
1/*-
2 * Copyright (c) 2006 Verdens Gang AS
3 * Copyright (c) 2006-2009 Varnish Software AS
4 * All rights reserved.
5 *
6 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include "config.h"
31
32#include <errno.h>
33#include <poll.h>
34#include <pthread.h>
35#include <signal.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <time.h>
40
41#include "miniobj.h"
42#include "vas.h"
43
44#include "binary_heap.h"
45#include "vqueue.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
56struct vevsig {
57        struct vev_base         *vevb;
58        struct vev              *vev;
59        struct sigaction        sigact;
60        unsigned char           happened;
61};
62
63static struct vevsig            *vev_sigs;
64static int                      vev_nsig;
65
66struct vev_base {
67        unsigned                magic;
68#define VEV_BASE_MAGIC          0x477bcf3d
69        VTAILQ_HEAD(,vev)       events;
70        struct pollfd           *pfd;
71        unsigned                npfd;
72        unsigned                lpfd;
73        struct binheap          *binheap;
74        unsigned char           compact_pfd;
75        unsigned char           disturbed;
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#endif
93
94/*--------------------------------------------------------------------*/
95
96static void
97vev_bh_update(void *priv, void *a, unsigned u)
98{
99        struct vev_base *evb;
100        struct vev *e;
101
102        CAST_OBJ_NOTNULL(evb, priv, VEV_BASE_MAGIC);
103        CAST_OBJ_NOTNULL(e, a, VEV_MAGIC);
104        e->__binheap_idx = u;
105}
106
107static int
108vev_bh_cmp(void *priv, void *a, void *b)
109{
110        struct vev_base *evb;
111        struct vev *ea, *eb;
112
113        CAST_OBJ_NOTNULL(evb, priv, VEV_BASE_MAGIC);
114        CAST_OBJ_NOTNULL(ea, a, VEV_MAGIC);
115        CAST_OBJ_NOTNULL(eb, b, VEV_MAGIC);
116        return (ea->__when < eb->__when);
117}
118
119/*--------------------------------------------------------------------*/
120
121static int
122vev_get_pfd(struct vev_base *evb)
123{
124        unsigned u;
125        void *p;
126
127        if (evb->lpfd + 1 < evb->npfd)
128                return (0);
129
130        if (evb->npfd < 8)
131                u = 8;
132        else if (evb->npfd > 256)
133                u = evb->npfd + 256;
134        else
135                u = evb->npfd * 2;
136        p = realloc(evb->pfd, sizeof *evb->pfd * u);
137        if (p == NULL)
138                return (1);
139        evb->npfd = u;
140        evb->pfd = p;
141        return (0);
142}
143
144/*--------------------------------------------------------------------*/
145
146static int
147vev_get_sig(int sig)
148{
149        struct vevsig *os;
150
151        if (sig < vev_nsig)
152                return (0);
153
154        os = calloc(sizeof *os, (sig + 1L));
155        if (os == NULL)
156                return (ENOMEM);
157
158        memcpy(os, vev_sigs, vev_nsig * sizeof *os);
159
160        free(vev_sigs);
161        vev_sigs = os;
162        vev_nsig = sig + 1;
163
164        return (0);
165}
166
167/*--------------------------------------------------------------------*/
168
169static void
170vev_sighandler(int sig)
171{
172        struct vevsig *es;
173
174        assert(sig < vev_nsig);
175        assert(vev_sigs != NULL);
176        es = &vev_sigs[sig];
177        if (!es->happened)
178                es->vevb->psig++;
179        es->happened = 1;
180}
181
182/*--------------------------------------------------------------------*/
183
184struct vev_base *
185vev_new_base(void)
186{
187        struct vev_base *evb;
188
189        evb = calloc(sizeof *evb, 1);
190        if (evb == NULL)
191                return (evb);
192        if (vev_get_pfd(evb)) {
193                free(evb);
194                return (NULL);
195        }
196        evb->magic = VEV_BASE_MAGIC;
197        VTAILQ_INIT(&evb->events);
198        evb->binheap = binheap_new(evb, vev_bh_cmp, vev_bh_update);
199        evb->thread = pthread_self();
200#ifdef DEBUG_EVENTS
201        evb->debug = fopen("/tmp/_.events", "w");
202        AN(evb->debug);
203        setbuf(evb->debug, NULL);
204        DBG(evb, "\n\nStart debugging\n");
205#endif
206        return (evb);
207}
208
209/*--------------------------------------------------------------------*/
210
211void
212vev_destroy_base(struct vev_base *evb)
213{
214        CHECK_OBJ_NOTNULL(evb, VEV_BASE_MAGIC);
215        assert(evb->thread == pthread_self());
216        evb->magic = 0;
217        free(evb);
218}
219
220/*--------------------------------------------------------------------*/
221
222struct vev *
223vev_new(void)
224{
225        struct vev *e;
226
227        e = calloc(sizeof *e, 1);
228        if (e != NULL) {
229                e->fd = -1;
230        }
231        return (e);
232}
233
234/*--------------------------------------------------------------------*/
235
236int
237vev_add(struct vev_base *evb, struct vev *e)
238{
239        struct vevsig *es;
240
241        CHECK_OBJ_NOTNULL(evb, VEV_BASE_MAGIC);
242        assert(e->magic != VEV_MAGIC);
243        assert(e->callback != NULL);
244        assert(e->sig >= 0);
245        assert(e->timeout >= 0.0);
246        assert(e->fd < 0 || e->fd_flags);
247        assert(evb->thread == pthread_self());
248        DBG(evb, "ev_add(%p) fd = %d\n", e, e->fd);
249
250        if (e->sig > 0 && vev_get_sig(e->sig))
251                return (ENOMEM);
252
253        if (e->fd >= 0 && vev_get_pfd(evb))
254                return (ENOMEM);
255
256        if (e->sig > 0) {
257                es = &vev_sigs[e->sig];
258                if (es->vev != NULL)
259                        return (EBUSY);
260                assert(es->happened == 0);
261                es->vev = e;
262                es->vevb = evb;
263                es->sigact.sa_flags = e->sig_flags;
264                es->sigact.sa_handler = vev_sighandler;
265        } else {
266                es = NULL;
267        }
268
269        if (e->fd >= 0) {
270                assert(evb->lpfd < evb->npfd);
271                evb->pfd[evb->lpfd].fd = e->fd;
272                evb->pfd[evb->lpfd].events =
273                    e->fd_flags & (EV_RD|EV_WR|EV_ERR|EV_HUP);
274                e->__poll_idx = evb->lpfd;
275                evb->lpfd++;
276                DBG(evb, "... pidx = %d lpfd = %d\n",
277                    e->__poll_idx, evb->lpfd);
278        } else
279                e->__poll_idx = -1;
280
281        e->magic = VEV_MAGIC;   /* before binheap_insert() */
282
283        if (e->timeout != 0.0) {
284                e->__when += VTIM_mono() + e->timeout;
285                binheap_insert(evb->binheap, e);
286                assert(e->__binheap_idx > 0);
287                DBG(evb, "... bidx = %d\n", e->__binheap_idx);
288        } else {
289                e->__when = 0.0;
290                e->__binheap_idx = 0;
291        }
292
293        e->__vevb = evb;
294        e->__privflags = 0;
295        if (e->fd < 0)
296                VTAILQ_INSERT_TAIL(&evb->events, e, __list);
297        else
298                VTAILQ_INSERT_HEAD(&evb->events, e, __list);
299
300        if (e->sig > 0) {
301                assert(es != NULL);
302                assert(sigaction(e->sig, &es->sigact, NULL) == 0);
303        }
304
305        return (0);
306}
307
308/*--------------------------------------------------------------------*/
309
310void
311vev_del(struct vev_base *evb, struct vev *e)
312{
313        struct vevsig *es;
314
315        CHECK_OBJ_NOTNULL(evb, VEV_BASE_MAGIC);
316        CHECK_OBJ_NOTNULL(e, VEV_MAGIC);
317        DBG(evb, "ev_del(%p) fd = %d\n", e, e->fd);
318        assert(evb == e->__vevb);
319        assert(evb->thread == pthread_self());
320
321        if (e->__binheap_idx != 0)
322                binheap_delete(evb->binheap, e->__binheap_idx);
323        assert(e->__binheap_idx == 0);
324
325        if (e->fd >= 0) {
326                DBG(evb, "... pidx = %d\n", e->__poll_idx);
327                evb->pfd[e->__poll_idx].fd = -1;
328                if (e->__poll_idx == evb->lpfd - 1)
329                        evb->lpfd--;
330                else
331                        evb->compact_pfd++;
332                e->fd = -1;
333                DBG(evb, "... lpfd = %d\n", evb->lpfd);
334        }
335
336        if (e->sig > 0) {
337                assert(e->sig < vev_nsig);
338                es = &vev_sigs[e->sig];
339                assert(es->vev == e);
340                es->vev = NULL;
341                es->vevb = NULL;
342                es->sigact.sa_flags = e->sig_flags;
343                es->sigact.sa_handler = SIG_DFL;
344                assert(sigaction(e->sig, &es->sigact, NULL) == 0);
345                es->happened = 0;
346        }
347
348        VTAILQ_REMOVE(&evb->events, e, __list);
349
350        e->magic = 0;
351        e->__vevb = NULL;
352
353        evb->disturbed = 1;
354}
355
356/*--------------------------------------------------------------------*/
357
358int
359vev_schedule(struct vev_base *evb)
360{
361        int i;
362
363        CHECK_OBJ_NOTNULL(evb, VEV_BASE_MAGIC);
364        assert(evb->thread == pthread_self());
365        do
366                i = vev_schedule_one(evb);
367        while (i == 1);
368        return (i);
369}
370
371/*--------------------------------------------------------------------*/
372
373static void
374vev_compact_pfd(struct vev_base *evb)
375{
376        unsigned u;
377        struct pollfd *p;
378        struct vev *ep;
379        int lfd;
380
381        DBG(evb, "compact_pfd() lpfd = %d\n", evb->lpfd);
382        p = evb->pfd;
383        for (u = 0; u < evb->lpfd; u++, p++) {
384                DBG(evb, "...[%d] fd = %d\n", u, p->fd);
385                if (p->fd >= 0)
386                        continue;
387                if (u == evb->lpfd - 1)
388                        break;
389                lfd = evb->pfd[evb->lpfd - 1].fd;
390                VTAILQ_FOREACH(ep, &evb->events, __list)
391                        if (ep->fd == lfd)
392                                break;
393                AN(ep);
394                DBG(evb, "...[%d] move %p pidx %d\n", u, ep, ep->__poll_idx);
395                *p = evb->pfd[--evb->lpfd];
396                ep->__poll_idx = u;
397        }
398        evb->lpfd = u;
399        evb->compact_pfd = 0;
400        DBG(evb, "... lpfd = %d\n", evb->lpfd);
401}
402
403/*--------------------------------------------------------------------*/
404
405static int
406vev_sched_timeout(struct vev_base *evb, struct vev *e, double t)
407{
408        int i;
409
410
411        i = e->callback(e, 0);
412        if (i) {
413                vev_del(evb, e);
414                free(e);
415        } else {
416                e->__when = t + e->timeout;
417                binheap_delete(evb->binheap, e->__binheap_idx);
418                binheap_insert(evb->binheap, e);
419        }
420        return (1);
421}
422
423static int
424vev_sched_signal(struct vev_base *evb)
425{
426        int i, j;
427        struct vevsig *es;
428        struct vev *e;
429
430        es = vev_sigs;
431        for (j = 0; j < vev_nsig; j++, es++) {
432                if (!es->happened || es->vevb != evb)
433                        continue;
434                evb->psig--;
435                es->happened = 0;
436                e = es->vev;
437                assert(e != NULL);
438                i = e->callback(e, EV_SIG);
439                if (i) {
440                        vev_del(evb, e);
441                        free(e);
442                }
443        }
444        return (1);
445}
446
447int
448vev_schedule_one(struct vev_base *evb)
449{
450        double t;
451        struct vev *e, *e2, *e3;
452        int i, j, tmo;
453        struct pollfd *pfd;
454
455        CHECK_OBJ_NOTNULL(evb, VEV_BASE_MAGIC);
456        assert(evb->thread == pthread_self());
457        e = binheap_root(evb->binheap);
458        if (e != NULL) {
459                CHECK_OBJ_NOTNULL(e, VEV_MAGIC);
460                assert(e->__binheap_idx == 1);
461                t = VTIM_mono();
462                if (e->__when <= t)
463                        return (vev_sched_timeout(evb, e, t));
464                tmo = (int)((e->__when - t) * 1e3);
465                if (tmo == 0)
466                        tmo = 1;
467        } else
468                tmo = INFTIM;
469
470        if (evb->compact_pfd)
471                vev_compact_pfd(evb);
472
473        if (tmo == INFTIM && evb->lpfd == 0)
474                return (0);
475
476        if (evb->psig)
477                return (vev_sched_signal(evb));
478        assert(evb->lpfd < evb->npfd);
479        i = poll(evb->pfd, evb->lpfd, tmo);
480        if (i == -1 && errno == EINTR)
481                return (vev_sched_signal(evb));
482        if (i == 0) {
483                assert(e != NULL);
484                t = VTIM_mono();
485                if (e->__when <= t)
486                        return (vev_sched_timeout(evb, e, t));
487        }
488        evb->disturbed = 0;
489        VTAILQ_FOREACH_SAFE(e, &evb->events, __list, e2) {
490                if (i == 0)
491                        break;
492                if (e->fd < 0)
493                        continue;
494                assert(e->__poll_idx < evb->lpfd);
495                pfd = &evb->pfd[e->__poll_idx];
496                assert(pfd->fd == e->fd);
497                if (!pfd->revents)
498                        continue;
499                DBG(evb, "callback(%p) fd = %d what = 0x%x pidx = %d\n",
500                    e, e->fd, pfd->revents, e->__poll_idx);
501                j = e->callback(e, pfd->revents);
502                i--;
503                if (evb->disturbed) {
504                        VTAILQ_FOREACH(e3, &evb->events, __list) {
505                                if (e3 == e) {
506                                        e3 = VTAILQ_NEXT(e, __list);
507                                        break;
508                                } else if (e3 == e2)
509                                        break;
510                        }
511                        e2 = e3;
512                        evb->disturbed = 0;
513                }
514                if (j) {
515                        vev_del(evb, e);
516                        evb->disturbed = 0;
517                        free(e);
518                }
519        }
520        assert(i == 0);
521        return (1);
522}
Note: See TracBrowser for help on using the repository browser.