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 694570
WS_Assert(const struct ws *ws)
39
{
40
41 694570
        CHECK_OBJ_NOTNULL(ws, WS_MAGIC);
42 694570
        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 694491
        assert(ws->s != NULL);
47 694491
        assert(PAOK(ws->s));
48 694491
        assert(ws->e != NULL);
49 694491
        assert(PAOK(ws->e));
50 694491
        assert(ws->s < ws->e);
51 694491
        assert(ws->f >= ws->s);
52 694491
        assert(ws->f <= ws->e);
53 694491
        assert(PAOK(ws->f));
54 694491
        if (ws->r) {
55 158803
                assert(ws->r > ws->s);
56 158803
                assert(ws->r <= ws->e);
57 158803
                assert(PAOK(ws->r));
58
        }
59 694491
        assert(*ws->e == 0x15);
60 694491
}
61
62
int
63 19829
WS_Inside(const struct ws *ws, const void *bb, const void *ee)
64
{
65 19829
        const char *b = bb;
66 19829
        const char *e = ee;
67
68 19829
        WS_Assert(ws);
69 19829
        if (b < ws->s || b >= ws->e)
70 17719
                return (0);
71 2110
        if (e != NULL && (e < b || e > ws->e))
72 0
                return (0);
73 2110
        return (1);
74
}
75
76
void
77 40
WS_Assert_Allocated(const struct ws *ws, const void *ptr, ssize_t len)
78
{
79 40
        const char *p = ptr;
80
81 40
        WS_Assert(ws);
82 40
        if (len < 0)
83 0
                len = strlen(p) + 1;
84 40
        assert(p >= ws->s && (p + len) <= ws->f);
85 40
}
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 38964
WS_Init(struct ws *ws, const char *id, void *space, unsigned len)
94
{
95
96 38964
        DSL(DBG_WORKSPACE, 0,
97
            "WS_Init(%p, \"%s\", %p, %u)", ws, id, space, len);
98 38964
        assert(space != NULL);
99 38964
        INIT_OBJ(ws, WS_MAGIC);
100 38964
        ws->s = space;
101 38964
        assert(PAOK(space));
102 38964
        len = PRNDDN(len - 1);
103 38964
        ws->e = ws->s + len;
104 38964
        *ws->e = 0x15;
105 38964
        ws->f = ws->s;
106 38964
        assert(id[0] & 0x20);
107 38964
        assert(strlen(id) < sizeof ws->id);
108 38964
        strcpy(ws->id, id);
109 38964
        WS_Assert(ws);
110 38950
}
111
112
void
113 878
WS_MarkOverflow(struct ws *ws)
114
{
115 878
        CHECK_OBJ_NOTNULL(ws, WS_MAGIC);
116
117 878
        ws->id[0] &= ~0x20;             // cheesy toupper()
118 878
}
119
120
static void
121 68228
ws_ClearOverflow(struct ws *ws)
122
{
123 68228
        CHECK_OBJ_NOTNULL(ws, WS_MAGIC);
124
125 68228
        ws->id[0] |= 0x20;              // cheesy tolower()
126 68228
}
127
128
/*
129
 * Reset a WS to start or a given pointer, likely from WS_Snapshot
130
 */
131
132
void
133 68241
WS_Reset(struct ws *ws, uintptr_t pp)
134
{
135
        char *p;
136
137 68241
        WS_Assert(ws);
138 68234
        p = (char *)pp;
139 68234
        DSL(DBG_WORKSPACE, 0, "WS_Reset(%p, %p)", ws, p);
140 68232
        assert(ws->r == NULL);
141 68232
        if (p == NULL)
142 67670
                ws->f = ws->s;
143
        else {
144 562
                assert(p >= ws->s);
145 562
                assert(p <= ws->e);
146 562
                ws->f = p;
147
        }
148 68232
        ws_ClearOverflow(ws);
149 68233
        WS_Assert(ws);
150 68221
}
151
152
void *
153 23576
WS_Alloc(struct ws *ws, unsigned bytes)
154
{
155
        char *r;
156
157 23576
        WS_Assert(ws);
158 23576
        bytes = PRNDUP(bytes);
159
160 23576
        assert(ws->r == NULL);
161 23576
        if (ws->f + bytes > ws->e) {
162 230
                WS_MarkOverflow(ws);
163 230
                return (NULL);
164
        }
165 23346
        r = ws->f;
166 23346
        ws->f += bytes;
167 23346
        DSL(DBG_WORKSPACE, 0, "WS_Alloc(%p, %u) = %p", ws, bytes, r);
168 23346
        WS_Assert(ws);
169 23346
        return (r);
170
}
171
172
void *
173 17476
WS_Copy(struct ws *ws, const void *str, int len)
174
{
175
        char *r;
176
        unsigned bytes;
177
178 17476
        WS_Assert(ws);
179 17475
        assert(ws->r == NULL);
180
181 17475
        if (len == -1)
182 94
                len = strlen(str) + 1;
183 17475
        assert(len >= 0);
184
185 17475
        bytes = PRNDUP((unsigned)len);
186 17475
        if (ws->f + bytes > ws->e) {
187 2
                WS_MarkOverflow(ws);
188 2
                return (NULL);
189
        }
190 17473
        r = ws->f;
191 17473
        ws->f += bytes;
192 17473
        memcpy(r, str, len);
193 17473
        DSL(DBG_WORKSPACE, 0, "WS_Copy(%p, %d) = %p", ws, len, r);
194 17475
        WS_Assert(ws);
195 17474
        return (r);
196
}
197
198
void *
199 3526
WS_Printf(struct ws *ws, const char *fmt, ...)
200
{
201
        unsigned u, v;
202
        va_list ap;
203
        char *p;
204
205 3526
        u = WS_Reserve(ws, 0);
206 3526
        p = ws->f;
207 3526
        va_start(ap, fmt);
208 3526
        v = vsnprintf(p, u, fmt, ap);
209 3526
        va_end(ap);
210 3526
        if (v >= u) {
211 290
                WS_Release(ws, 0);
212 290
                WS_MarkOverflow(ws);
213 290
                p = NULL;
214
        } else {
215 3236
                WS_Release(ws, v + 1);
216
        }
217 3526
        return (p);
218
}
219
220
uintptr_t
221 71023
WS_Snapshot(struct ws *ws)
222
{
223
224 71023
        WS_Assert(ws);
225 71019
        assert(ws->r == NULL);
226 71019
        DSL(DBG_WORKSPACE, 0, "WS_Snapshot(%p) = %p", ws, ws->f);
227 71019
        return (ws->f == ws->s ? 0 : (uintptr_t)ws->f);
228
}
229
230
unsigned
231 79201
WS_Reserve(struct ws *ws, unsigned bytes)
232
{
233
        unsigned b2;
234
235 79201
        WS_Assert(ws);
236 79196
        assert(ws->r == NULL);
237
238 79196
        b2 = PRNDDN(ws->e - ws->f);
239 79196
        if (bytes != 0 && bytes < b2)
240 17650
                b2 = PRNDUP(bytes);
241
242 79196
        if (ws->f + b2 > ws->e) {
243 0
                WS_MarkOverflow(ws);
244 0
                return (0);
245
        }
246 79196
        ws->r = ws->f + b2;
247 79196
        DSL(DBG_WORKSPACE, 0, "WS_Reserve(%p, %u/%u) = %u",
248
            ws, b2, bytes, pdiff(ws->f, ws->r));
249 79199
        WS_Assert(ws);
250 79197
        return (pdiff(ws->f, ws->r));
251
}
252
253
unsigned
254 7436
WS_ReserveLumps(struct ws *ws, size_t sz)
255
{
256
        unsigned u;
257
258 7436
        u = WS_Reserve(ws, 0);
259 7436
        u /= sz;
260 7436
        return (u);
261
}
262
263
void
264 68094
WS_Release(struct ws *ws, unsigned bytes)
265
{
266 68094
        WS_Assert(ws);
267 68095
        bytes = PRNDUP(bytes);
268 68095
        assert(bytes <= ws->e - ws->f);
269 68095
        DSL(DBG_WORKSPACE, 0, "WS_Release(%p, %u)", ws, bytes);
270 68094
        assert(ws->r != NULL);
271 68094
        assert(ws->f + bytes <= ws->r);
272 68094
        ws->f += bytes;
273 68094
        ws->r = NULL;
274 68094
        WS_Assert(ws);
275 68093
}
276
277
void
278 11100
WS_ReleaseP(struct ws *ws, const char *ptr)
279
{
280 11100
        WS_Assert(ws);
281 11100
        DSL(DBG_WORKSPACE, 0, "WS_ReleaseP(%p, %p (%zd))", ws, ptr, ptr - ws->f);
282 11100
        assert(ws->r != NULL);
283 11100
        assert(ptr >= ws->f);
284 11100
        assert(ptr <= ws->r);
285 11100
        ws->f += PRNDUP(ptr - ws->f);
286 11100
        ws->r = NULL;
287 11100
        WS_Assert(ws);
288 11100
}
289
290
int
291 69050
WS_Overflowed(const struct ws *ws)
292
{
293 69050
        CHECK_OBJ_NOTNULL(ws, WS_MAGIC);
294 69050
        AN(ws->id[0]);
295
296 69050
        if (ws->id[0] & 0x20)
297 68766
                return (0);
298 284
        return (1);
299
}