varnish-cache/bin/varnishd/cache/cache_ws.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2011 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
31
#include "config.h"
32
33
#include "cache_varnishd.h"
34
35
#include <stdio.h>
36
37
void
38 347303
WS_Assert(const struct ws *ws)
39
{
40
41 347303
        CHECK_OBJ_NOTNULL(ws, WS_MAGIC);
42 347303
        DSL(DBG_WORKSPACE, 0, "WS(%p) = (%s, %p %u %u %u)",
43
            ws, ws->id, ws->s, pdiff(ws->s, ws->f),
44
            ws->r == NULL ? 0 : pdiff(ws->f, ws->r),
45
            pdiff(ws->s, ws->e));
46 347282
        assert(ws->s != NULL);
47 347282
        assert(PAOK(ws->s));
48 347282
        assert(ws->e != NULL);
49 347282
        assert(PAOK(ws->e));
50 347282
        assert(ws->s < ws->e);
51 347282
        assert(ws->f >= ws->s);
52 347282
        assert(ws->f <= ws->e);
53 347282
        assert(PAOK(ws->f));
54 347282
        if (ws->r) {
55 79976
                assert(ws->r > ws->s);
56 79976
                assert(ws->r <= ws->e);
57 79976
                assert(PAOK(ws->r));
58
        }
59 347282
        assert(*ws->e == 0x15);
60 347282
}
61
62
int
63 10490
WS_Inside(const struct ws *ws, const void *bb, const void *ee)
64
{
65 10490
        const char *b = bb;
66 10490
        const char *e = ee;
67
68 10490
        WS_Assert(ws);
69 10490
        if (b < ws->s || b >= ws->e)
70 8808
                return (0);
71 1682
        if (e != NULL && (e < b || e > ws->e))
72 0
                return (0);
73 1682
        return (1);
74
}
75
76
void
77 0
WS_Assert_Allocated(const struct ws *ws, const void *ptr, ssize_t len)
78
{
79 0
        const char *p = ptr;
80
81 0
        WS_Assert(ws);
82 0
        if (len < 0)
83 0
                len = strlen(p) + 1;
84 0
        assert(p >= ws->s && (p + len) <= ws->f);
85 0
}
86
87
/*
88
 * NB: The id must be max 3 char and lower-case.
89
 * (upper-case the first char to indicate overflow)
90
 */
91
92
void
93 19544
WS_Init(struct ws *ws, const char *id, void *space, unsigned len)
94
{
95
96 19544
        DSL(DBG_WORKSPACE, 0,
97
            "WS_Init(%p, \"%s\", %p, %u)", ws, id, space, len);
98 19537
        assert(space != NULL);
99 19537
        INIT_OBJ(ws, WS_MAGIC);
100 19537
        ws->s = space;
101 19537
        assert(PAOK(space));
102 19537
        len = PRNDDN(len - 1);
103 19537
        ws->e = ws->s + len;
104 19537
        *ws->e = 0x15;
105 19537
        ws->f = ws->s;
106 19537
        assert(id[0] & 0x20);
107 19537
        assert(strlen(id) < sizeof ws->id);
108 19537
        strcpy(ws->id, id);
109 19537
        WS_Assert(ws);
110 19537
}
111
112
void
113 426
WS_MarkOverflow(struct ws *ws)
114
{
115 426
        CHECK_OBJ_NOTNULL(ws, WS_MAGIC);
116
117 426
        ws->id[0] &= ~0x20;             // cheesy toupper()
118 426
}
119
120
static void
121 34121
ws_ClearOverflow(struct ws *ws)
122
{
123 34121
        CHECK_OBJ_NOTNULL(ws, WS_MAGIC);
124
125 34121
        ws->id[0] |= 0x20;              // cheesy tolower()
126 34121
}
127
128
/*
129
 * Reset a WS to start or a given pointer, likely from WS_Snapshot
130
 */
131
132
void
133 34123
WS_Reset(struct ws *ws, uintptr_t pp)
134
{
135
        char *p;
136
137 34123
        WS_Assert(ws);
138 34121
        p = (char *)pp;
139 34121
        DSL(DBG_WORKSPACE, 0, "WS_Reset(%p, %p)", ws, p);
140 34121
        assert(ws->r == NULL);
141 34121
        if (p == NULL)
142 33845
                ws->f = ws->s;
143
        else {
144 276
                assert(p >= ws->s);
145 276
                assert(p <= ws->e);
146 276
                ws->f = p;
147
        }
148 34121
        ws_ClearOverflow(ws);
149 34121
        WS_Assert(ws);
150 34120
}
151
152
void *
153 11766
WS_Alloc(struct ws *ws, unsigned bytes)
154
{
155
        char *r;
156
157 11766
        WS_Assert(ws);
158 11766
        bytes = PRNDUP(bytes);
159
160 11766
        assert(ws->r == NULL);
161 11766
        if (ws->f + bytes > ws->e) {
162 109
                WS_MarkOverflow(ws);
163 109
                return (NULL);
164
        }
165 11657
        r = ws->f;
166 11657
        ws->f += bytes;
167 11657
        DSL(DBG_WORKSPACE, 0, "WS_Alloc(%p, %u) = %p", ws, bytes, r);
168 11657
        WS_Assert(ws);
169 11657
        return (r);
170
}
171
172
void *
173 8697
WS_Copy(struct ws *ws, const void *str, int len)
174
{
175
        char *r;
176
        unsigned bytes;
177
178 8697
        WS_Assert(ws);
179 8697
        assert(ws->r == NULL);
180
181 8697
        if (len == -1)
182 47
                len = strlen(str) + 1;
183 8697
        assert(len >= 0);
184
185 8697
        bytes = PRNDUP((unsigned)len);
186 8697
        if (ws->f + bytes > ws->e) {
187 1
                WS_MarkOverflow(ws);
188 1
                return (NULL);
189
        }
190 8696
        r = ws->f;
191 8696
        ws->f += bytes;
192 8696
        memcpy(r, str, len);
193 8696
        DSL(DBG_WORKSPACE, 0, "WS_Copy(%p, %d) = %p", ws, len, r);
194 8696
        WS_Assert(ws);
195 8696
        return (r);
196
}
197
198
void *
199 1692
WS_Printf(struct ws *ws, const char *fmt, ...)
200
{
201
        unsigned u, v;
202
        va_list ap;
203
        char *p;
204
205 1692
        u = WS_Reserve(ws, 0);
206 1692
        p = ws->f;
207 1692
        va_start(ap, fmt);
208 1692
        v = vsnprintf(p, u, fmt, ap);
209 1692
        va_end(ap);
210 1692
        if (v >= u) {
211 145
                WS_Release(ws, 0);
212 145
                WS_MarkOverflow(ws);
213 145
                p = NULL;
214
        } else {
215 1547
                WS_Release(ws, v + 1);
216
        }
217 1692
        return (p);
218
}
219
220
uintptr_t
221 35262
WS_Snapshot(struct ws *ws)
222
{
223
224 35262
        WS_Assert(ws);
225 35263
        assert(ws->r == NULL);
226 35263
        DSL(DBG_WORKSPACE, 0, "WS_Snapshot(%p) = %p", ws, ws->f);
227 35262
        return (ws->f == ws->s ? 0 : (uintptr_t)ws->f);
228
}
229
230
unsigned
231 39576
WS_Reserve(struct ws *ws, unsigned bytes)
232
{
233
        unsigned b2;
234
235 39576
        WS_Assert(ws);
236 39574
        assert(ws->r == NULL);
237
238 39574
        b2 = PRNDDN(ws->e - ws->f);
239 39574
        if (bytes != 0 && bytes < b2)
240 9165
                b2 = PRNDUP(bytes);
241
242 39574
        if (ws->f + b2 > ws->e) {
243 0
                WS_MarkOverflow(ws);
244 0
                return (0);
245
        }
246 39574
        ws->r = ws->f + b2;
247 39574
        DSL(DBG_WORKSPACE, 0, "WS_Reserve(%p, %u/%u) = %u",
248
            ws, b2, bytes, pdiff(ws->f, ws->r));
249 39574
        WS_Assert(ws);
250 39574
        return (pdiff(ws->f, ws->r));
251
}
252
253
unsigned
254 3776
WS_ReserveLumps(struct ws *ws, size_t sz)
255
{
256
        unsigned u;
257
258 3776
        u = WS_Reserve(ws, 0);
259 3776
        u /= sz;
260 3776
        return (u);
261
}
262
263
void
264 34018
WS_Release(struct ws *ws, unsigned bytes)
265
{
266 34018
        WS_Assert(ws);
267 34018
        bytes = PRNDUP(bytes);
268 34018
        assert(bytes <= ws->e - ws->f);
269 34018
        DSL(DBG_WORKSPACE, 0, "WS_Release(%p, %u)", ws, bytes);
270 34017
        assert(ws->r != NULL);
271 34017
        assert(ws->f + bytes <= ws->r);
272 34017
        ws->f += bytes;
273 34017
        ws->r = NULL;
274 34017
        WS_Assert(ws);
275 34016
}
276
277
void
278 5558
WS_ReleaseP(struct ws *ws, const char *ptr)
279
{
280 5558
        WS_Assert(ws);
281 5558
        DSL(DBG_WORKSPACE, 0, "WS_ReleaseP(%p, %p (%zd))", ws, ptr, ptr - ws->f);
282 5558
        assert(ws->r != NULL);
283 5558
        assert(ptr >= ws->f);
284 5558
        assert(ptr <= ws->r);
285 5558
        ws->f += PRNDUP(ptr - ws->f);
286 5558
        ws->r = NULL;
287 5558
        WS_Assert(ws);
288 5558
}
289
290
int
291 22005
WS_Overflowed(const struct ws *ws)
292
{
293 22005
        CHECK_OBJ_NOTNULL(ws, WS_MAGIC);
294 22005
        AN(ws->id[0]);
295
296 22005
        if (ws->id[0] & 0x20)
297 21969
                return (0);
298 36
        return (1);
299
}