varnish-cache/bin/varnishd/waiter/cache_waiter_kqueue.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2011 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
32
#include "config.h"
33
34
#if defined(HAVE_KQUEUE)
35
36
#include "cache/cache_varnishd.h"
37
38
#include <sys/event.h>
39
40
#include <stdlib.h>
41
42
#include "waiter/waiter.h"
43
#include "waiter/waiter_priv.h"
44
#include "vtim.h"
45
46
#define NKEV    256
47
48
struct vwk {
49
        unsigned                magic;
50
#define VWK_MAGIC               0x1cc2acc2
51
        int                     kq;
52
        struct waiter           *waiter;
53
        pthread_t               thread;
54
        double                  next;
55
        int                     pipe[2];
56
        unsigned                nwaited;
57
        int                     die;
58
        struct lock             mtx;
59
};
60
61
/*--------------------------------------------------------------------*/
62
63
static void *
64 25
vwk_thread(void *priv)
65
{
66
        struct vwk *vwk;
67
        struct kevent ke[NKEV], *kp;
68
        int j, n;
69
        double now, then;
70
        struct timespec ts;
71
        struct waited *wp;
72
        struct waiter *w;
73
        char c;
74
75 25
        CAST_OBJ_NOTNULL(vwk, priv, VWK_MAGIC);
76 25
        w = vwk->waiter;
77 25
        CHECK_OBJ_NOTNULL(w, WAITER_MAGIC);
78 25
        THR_SetName("cache-kqueue");
79 25
        THR_Init();
80
81 25
        now = VTIM_real();
82 110043
        while (1) {
83 110318
                while (1) {
84 110318
                        Lck_Lock(&vwk->mtx);
85
                        /*
86
                         * XXX: We could avoid many syscalls here if we were
87
                         * XXX: allowed to just close the fd's on timeout.
88
                         */
89 110318
                        then = Wait_HeapDue(w, &wp);
90 110318
                        if (wp == NULL) {
91 87251
                                vwk->next = now + 100;
92 87251
                                break;
93 23067
                        } else if (then > now) {
94 22792
                                vwk->next = then;
95 22792
                                break;
96
                        }
97 275
                        CHECK_OBJ_NOTNULL(wp, WAITED_MAGIC);
98 275
                        EV_SET(ke, wp->fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
99 275
                        AZ(kevent(vwk->kq, ke, 1, NULL, 0, NULL));
100 275
                        AN(Wait_HeapDelete(w, wp));
101 275
                        Lck_Unlock(&vwk->mtx);
102 275
                        Wait_Call(w, wp, WAITER_TIMEOUT, now);
103
                }
104 110043
                then = vwk->next - now;
105 110043
                ts = VTIM_timespec(then);
106 110043
                Lck_Unlock(&vwk->mtx);
107 110043
                n = kevent(vwk->kq, NULL, 0, ke, NKEV, &ts);
108 110043
                assert(n >= 0);
109 110043
                assert(n <= NKEV);
110 110043
                now = VTIM_real();
111 195310
                for (kp = ke, j = 0; j < n; j++, kp++) {
112 85267
                        assert(kp->filter == EVFILT_READ);
113 85267
                        if ((uintptr_t)ke[j].udata == (uintptr_t)vwk) {
114 42530
                                assert(read(vwk->pipe[0], &c, 1) == 1);
115 42530
                                continue;
116
                        }
117 42737
                        CAST_OBJ_NOTNULL(wp, (void*)ke[j].udata, WAITED_MAGIC);
118 42737
                        Lck_Lock(&vwk->mtx);
119 42737
                        AN(Wait_HeapDelete(w, wp));
120 42737
                        Lck_Unlock(&vwk->mtx);
121 42737
                        vwk->nwaited--;
122 42737
                        if (kp->flags & EV_EOF)
123 27696
                                Wait_Call(w, wp, WAITER_REMCLOSE, now);
124
                        else
125 15041
                                Wait_Call(w, wp, WAITER_ACTION, now);
126 42737
                }
127 110043
                if (vwk->nwaited == 0 && vwk->die)
128 25
                        break;
129
        }
130 25
        closefd(&vwk->pipe[0]);
131 25
        closefd(&vwk->pipe[1]);
132 25
        closefd(&vwk->kq);
133 25
        return (NULL);
134
}
135
136
/*--------------------------------------------------------------------*/
137
138
static int v_matchproto_(waiter_enter_f)
139 43410
vwk_enter(void *priv, struct waited *wp)
140
{
141
        struct vwk *vwk;
142
        struct kevent ke;
143
144 43410
        CAST_OBJ_NOTNULL(vwk, priv, VWK_MAGIC);
145 43410
        EV_SET(&ke, wp->fd, EVFILT_READ, EV_ADD|EV_ONESHOT, 0, 0, wp);
146 43410
        Lck_Lock(&vwk->mtx);
147 43410
        vwk->nwaited++;
148 43410
        Wait_HeapInsert(vwk->waiter, wp);
149 43410
        AZ(kevent(vwk->kq, &ke, 1, NULL, 0, NULL));
150
151
        /* If the kqueue isn't due before our timeout, poke it via the pipe */
152 43410
        if (Wait_When(wp) < vwk->next)
153 42505
                assert(write(vwk->pipe[1], "X", 1) == 1);
154
155 43410
        Lck_Unlock(&vwk->mtx);
156 43410
        return (0);
157
}
158
159
/*--------------------------------------------------------------------*/
160
161
static void v_matchproto_(waiter_init_f)
162 43694
vwk_init(struct waiter *w)
163
{
164
        struct vwk *vwk;
165
        struct kevent ke;
166
167 43694
        CHECK_OBJ_NOTNULL(w, WAITER_MAGIC);
168 43694
        vwk = w->priv;
169 43694
        INIT_OBJ(vwk, VWK_MAGIC);
170 43694
        vwk->waiter = w;
171
172 43694
        vwk->kq = kqueue();
173 43694
        assert(vwk->kq >= 0);
174 43694
        Lck_New(&vwk->mtx, lck_waiter);
175 43694
        AZ(pipe(vwk->pipe));
176 43694
        EV_SET(&ke, vwk->pipe[0], EVFILT_READ, EV_ADD, 0, 0, vwk);
177 43694
        AZ(kevent(vwk->kq, &ke, 1, NULL, 0, NULL));
178
179 43694
        PTOK(pthread_create(&vwk->thread, NULL, vwk_thread, vwk));
180 43694
}
181
182
/*--------------------------------------------------------------------
183
 * It is the callers responsibility to trigger all fd's waited on to
184
 * fail somehow.
185
 */
186
187
static void v_matchproto_(waiter_fini_f)
188 25
vwk_fini(struct waiter *w)
189
{
190
        struct vwk *vwk;
191
        void *vp;
192
193 25
        CAST_OBJ_NOTNULL(vwk, w->priv, VWK_MAGIC);
194 25
        Lck_Lock(&vwk->mtx);
195 25
        vwk->die = 1;
196 25
        assert(write(vwk->pipe[1], "Y", 1) == 1);
197 25
        Lck_Unlock(&vwk->mtx);
198 25
        PTOK(pthread_join(vwk->thread, &vp));
199 25
        Lck_Delete(&vwk->mtx);
200 25
}
201
202
/*--------------------------------------------------------------------*/
203
204
#include "waiter/mgt_waiter.h"
205
206
const struct waiter_impl waiter_kqueue = {
207
        .name =         "kqueue",
208
        .init =         vwk_init,
209
        .fini =         vwk_fini,
210
        .enter =        vwk_enter,
211
        .size =         sizeof(struct vwk),
212
};
213
214
#endif /* defined(HAVE_KQUEUE) */