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 573712
WS_Assert(const struct ws *ws)
39
{
40
41 573712
        CHECK_OBJ_NOTNULL(ws, WS_MAGIC);
42 573712
        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 573641
        assert(ws->s != NULL);
47 573641
        assert(PAOK(ws->s));
48 573641
        assert(ws->e != NULL);
49 573641
        assert(PAOK(ws->e));
50 573641
        assert(ws->s < ws->e);
51 573641
        assert(ws->f >= ws->s);
52 573641
        assert(ws->f <= ws->e);
53 573641
        assert(PAOK(ws->f));
54 573641
        if (ws->r) {
55 134663
                assert(ws->r > ws->s);
56 134663
                assert(ws->r <= ws->e);
57 134663
                assert(PAOK(ws->r));
58
        }
59 573641
        assert(*ws->e == 0x15);
60 573641
}
61
62
int
63 14404
WS_Inside(const struct ws *ws, const void *bb, const void *ee)
64
{
65 14404
        const char *b = bb;
66 14404
        const char *e = ee;
67
68 14404
        WS_Assert(ws);
69 14404
        if (b < ws->s || b >= ws->e)
70 11608
                return (0);
71 2796
        if (e != NULL && (e < b || e > ws->e))
72 0
                return (0);
73 2796
        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 33940
WS_Init(struct ws *ws, const char *id, void *space, unsigned len)
94
{
95
96 33940
        DSL(DBG_WORKSPACE, 0,
97
            "WS_Init(%p, \"%s\", %p, %u)", ws, id, space, len);
98 33938
        assert(space != NULL);
99 33938
        INIT_OBJ(ws, WS_MAGIC);
100 33938
        ws->s = space;
101 33938
        assert(PAOK(space));
102 33938
        len = PRNDDN(len - 1);
103 33938
        ws->e = ws->s + len;
104 33938
        *ws->e = 0x15;
105 33938
        ws->f = ws->s;
106 33938
        assert(id[0] & 0x20);
107 33938
        assert(strlen(id) < sizeof ws->id);
108 33938
        strcpy(ws->id, id);
109 33938
        WS_Assert(ws);
110 33935
}
111
112
void
113 228
WS_MarkOverflow(struct ws *ws)
114
{
115 228
        CHECK_OBJ_NOTNULL(ws, WS_MAGIC);
116
117 228
        ws->id[0] &= ~0x20;             // cheesy toupper()
118 228
}
119
120
static void
121 57738
ws_ClearOverflow(struct ws *ws)
122
{
123 57738
        CHECK_OBJ_NOTNULL(ws, WS_MAGIC);
124
125 57738
        ws->id[0] |= 0x20;              // cheesy tolower()
126 57738
}
127
128
/*
129
 * Reset a WS to start or a given pointer, likely from WS_Snapshot
130
 */
131
132
void
133 57739
WS_Reset(struct ws *ws, uintptr_t pp)
134
{
135
        char *p;
136
137 57739
        WS_Assert(ws);
138 57737
        p = (char *)pp;
139 57737
        DSL(DBG_WORKSPACE, 0, "WS_Reset(%p, %p)", ws, p);
140 57735
        assert(ws->r == NULL);
141 57735
        if (p == NULL)
142 56985
                ws->f = ws->s;
143
        else {
144 750
                assert(p >= ws->s);
145 750
                assert(p <= ws->e);
146 750
                ws->f = p;
147
        }
148 57735
        ws_ClearOverflow(ws);
149 57738
        WS_Assert(ws);
150 57735
}
151
152
void *
153 18548
WS_Alloc(struct ws *ws, unsigned bytes)
154
{
155
        char *r;
156
157 18548
        WS_Assert(ws);
158 18551
        bytes = PRNDUP(bytes);
159
160 18551
        assert(ws->r == NULL);
161 18551
        if (ws->f + bytes > ws->e) {
162 72
                WS_MarkOverflow(ws);
163 72
                return (NULL);
164
        }
165 18479
        r = ws->f;
166 18479
        ws->f += bytes;
167 18479
        DSL(DBG_WORKSPACE, 0, "WS_Alloc(%p, %u) = %p", ws, bytes, r);
168 18480
        WS_Assert(ws);
169 18477
        return (r);
170
}
171
172
void *
173 11696
WS_Copy(struct ws *ws, const void *str, int len)
174
{
175
        char *r;
176
        unsigned bytes;
177
178 11696
        WS_Assert(ws);
179 11696
        assert(ws->r == NULL);
180
181 11696
        if (len == -1)
182 84
                len = strlen(str) + 1;
183 11696
        assert(len >= 0);
184
185 11696
        bytes = PRNDUP((unsigned)len);
186 11696
        if (ws->f + bytes > ws->e) {
187 2
                WS_MarkOverflow(ws);
188 2
                return (NULL);
189
        }
190 11694
        r = ws->f;
191 11694
        ws->f += bytes;
192 11694
        memcpy(r, str, len);
193 11694
        DSL(DBG_WORKSPACE, 0, "WS_Copy(%p, %d) = %p", ws, len, r);
194 11694
        WS_Assert(ws);
195 11694
        return (r);
196
}
197
198
void *
199 2200
WS_Printf(struct ws *ws, const char *fmt, ...)
200
{
201
        unsigned u, v;
202
        va_list ap;
203
        char *p;
204
205 2200
        u = WS_Reserve(ws, 0);
206 2200
        p = ws->f;
207 2200
        va_start(ap, fmt);
208 2200
        v = vsnprintf(p, u, fmt, ap);
209 2200
        va_end(ap);
210 2200
        if (v >= u) {
211 98
                WS_Release(ws, 0);
212 98
                WS_MarkOverflow(ws);
213 98
                p = NULL;
214
        } else {
215 2102
                WS_Release(ws, v + 1);
216
        }
217 2200
        return (p);
218
}
219
220
uintptr_t
221 56402
WS_Snapshot(struct ws *ws)
222
{
223
224 56402
        WS_Assert(ws);
225 56402
        assert(ws->r == NULL);
226 56402
        DSL(DBG_WORKSPACE, 0, "WS_Snapshot(%p) = %p", ws, ws->f);
227 56403
        return (ws->f == ws->s ? 0 : (uintptr_t)ws->f);
228
}
229
230
unsigned
231 66880
WS_Reserve(struct ws *ws, unsigned bytes)
232
{
233
        unsigned b2;
234
235 66880
        WS_Assert(ws);
236 66879
        assert(ws->r == NULL);
237
238 66879
        b2 = PRNDDN(ws->e - ws->f);
239 66879
        if (bytes != 0 && bytes < b2)
240 13779
                b2 = PRNDUP(bytes);
241
242 66879
        if (ws->f + b2 > ws->e) {
243 0
                WS_MarkOverflow(ws);
244 0
                return (0);
245
        }
246 66879
        ws->r = ws->f + b2;
247 66879
        DSL(DBG_WORKSPACE, 0, "WS_Reserve(%p, %u/%u) = %u",
248
            ws, b2, bytes, pdiff(ws->f, ws->r));
249 66880
        WS_Assert(ws);
250 66877
        return (pdiff(ws->f, ws->r));
251
}
252
253
unsigned
254 6051
WS_ReserveLumps(struct ws *ws, size_t sz)
255
{
256
        unsigned u;
257
258 6051
        u = WS_Reserve(ws, 0);
259 6055
        u /= sz;
260 6055
        return (u);
261
}
262
263
void
264 57126
WS_Release(struct ws *ws, unsigned bytes)
265
{
266 57126
        WS_Assert(ws);
267 57125
        bytes = PRNDUP(bytes);
268 57125
        assert(bytes <= ws->e - ws->f);
269 57125
        DSL(DBG_WORKSPACE, 0, "WS_Release(%p, %u)", ws, bytes);
270 57123
        assert(ws->r != NULL);
271 57123
        assert(ws->f + bytes <= ws->r);
272 57123
        ws->f += bytes;
273 57123
        ws->r = NULL;
274 57123
        WS_Assert(ws);
275 57122
}
276
277
void
278 9760
WS_ReleaseP(struct ws *ws, char *ptr)
279
{
280 9760
        WS_Assert(ws);
281 9760
        DSL(DBG_WORKSPACE, 0, "WS_ReleaseP(%p, %p (%zd))", ws, ptr, ptr - ws->f);
282 9760
        assert(ws->r != NULL);
283 9760
        assert(ptr >= ws->f);
284 9760
        assert(ptr <= ws->r);
285 9760
        ws->f += PRNDUP(ptr - ws->f);
286 9760
        ws->r = NULL;
287 9760
        WS_Assert(ws);
288 9760
}
289
290
int
291 34629
WS_Overflowed(const struct ws *ws)
292
{
293 34629
        CHECK_OBJ_NOTNULL(ws, WS_MAGIC);
294 34629
        AN(ws->id[0]);
295
296 34629
        if (ws->id[0] & 0x20)
297 34601
                return (0);
298 28
        return (1);
299
}