| | varnish-cache/lib/libvarnishapi/vsc.c |
0 |
|
/*- |
1 |
|
* Copyright (c) 2006 Verdens Gang AS |
2 |
|
* Copyright (c) 2006-2015 Varnish Software AS |
3 |
|
* All rights reserved. |
4 |
|
* |
5 |
|
* Author: Poul-Henning Kamp <phk@phk.freebsd.dk> |
6 |
|
* Author: Martin Blix Grydeland <martin@varnish-software.com> |
7 |
|
* |
8 |
|
* SPDX-License-Identifier: BSD-2-Clause |
9 |
|
* |
10 |
|
* Redistribution and use in source and binary forms, with or without |
11 |
|
* modification, are permitted provided that the following conditions |
12 |
|
* are met: |
13 |
|
* 1. Redistributions of source code must retain the above copyright |
14 |
|
* notice, this list of conditions and the following disclaimer. |
15 |
|
* 2. Redistributions in binary form must reproduce the above copyright |
16 |
|
* notice, this list of conditions and the following disclaimer in the |
17 |
|
* documentation and/or other materials provided with the distribution. |
18 |
|
* |
19 |
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
20 |
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
21 |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
22 |
|
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE |
23 |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
24 |
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
25 |
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
26 |
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
27 |
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
28 |
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
29 |
|
* SUCH DAMAGE. |
30 |
|
*/ |
31 |
|
|
32 |
|
#include "config.h" |
33 |
|
|
34 |
|
#include <sys/stat.h> |
35 |
|
|
36 |
|
#include <fnmatch.h> |
37 |
|
#include <stdint.h> |
38 |
|
#include <stdio.h> |
39 |
|
#include <stdlib.h> |
40 |
|
#include <string.h> |
41 |
|
#include <unistd.h> |
42 |
|
|
43 |
|
#include "vdef.h" |
44 |
|
#include "vas.h" |
45 |
|
#include "miniobj.h" |
46 |
|
#include "vqueue.h" |
47 |
|
#include "vjsn.h" |
48 |
|
#include "vsb.h" |
49 |
|
#include "vsc_priv.h" |
50 |
|
#include "vmb.h" |
51 |
|
|
52 |
|
#include "vapi/vsc.h" |
53 |
|
#include "vapi/vsm.h" |
54 |
|
|
55 |
|
struct vsc_sf_mode { |
56 |
|
const char *name; |
57 |
|
unsigned include; |
58 |
|
unsigned fail; |
59 |
|
unsigned append; |
60 |
|
}; |
61 |
|
|
62 |
|
static const struct vsc_sf_mode VSC_SF_INCLUDE[1] = {{"include", 1, 1, 1}}; |
63 |
|
static const struct vsc_sf_mode VSC_SF_EXCLUDE[1] = {{"exclude", 0, 0, 1}}; |
64 |
|
static const struct vsc_sf_mode VSC_SF_REQUIRE[1] = {{"require", 1, 0, 0}}; |
65 |
|
|
66 |
|
struct vsc_sf { |
67 |
|
unsigned magic; |
68 |
|
#define VSC_SF_MAGIC 0x558478dd |
69 |
|
VTAILQ_ENTRY(vsc_sf) list; |
70 |
|
char *pattern; |
71 |
|
const struct vsc_sf_mode *mode; |
72 |
|
}; |
73 |
|
|
74 |
|
VTAILQ_HEAD(vsc_sf_head, vsc_sf); |
75 |
|
|
76 |
|
struct vsc_pt { |
77 |
|
struct VSC_point point; |
78 |
|
char *name; |
79 |
|
}; |
80 |
|
|
81 |
|
struct vsc_seg { |
82 |
|
unsigned magic; |
83 |
|
#define VSC_SEG_MAGIC 0x801177d4 |
84 |
|
VTAILQ_ENTRY(vsc_seg) list; |
85 |
|
struct vsm_fantom fantom[1]; |
86 |
|
struct vsc_head *head; |
87 |
|
char *body; |
88 |
|
|
89 |
|
struct vjsn *vj; |
90 |
|
|
91 |
|
unsigned npoints; |
92 |
|
struct vsc_pt *points; |
93 |
|
int exposed; |
94 |
|
}; |
95 |
|
|
96 |
|
struct vsc { |
97 |
|
unsigned magic; |
98 |
|
#define VSC_MAGIC 0x3373554a |
99 |
|
|
100 |
|
unsigned raw; |
101 |
|
struct vsc_sf_head sf_list; |
102 |
|
VTAILQ_HEAD(,vsc_seg) segs; |
103 |
|
|
104 |
|
VSC_new_f *fnew; |
105 |
|
VSC_destroy_f *fdestroy; |
106 |
|
void *priv; |
107 |
|
}; |
108 |
|
|
109 |
|
/*-------------------------------------------------------------------- |
110 |
|
* Build the static level, type and point descriptions |
111 |
|
*/ |
112 |
|
|
113 |
|
enum vsc_levels { |
114 |
|
#define VSC_LEVEL_F(v,l,e,d) v, |
115 |
|
#include "tbl/vsc_levels.h" |
116 |
|
}; |
117 |
|
|
118 |
|
static const struct VSC_level_desc levels[] = { |
119 |
|
#define VSC_LEVEL_F(v,l,e,d) [v] = {#v, l, e, d}, |
120 |
|
#include "tbl/vsc_levels.h" |
121 |
|
}; |
122 |
|
|
123 |
|
static const ssize_t nlevels = sizeof(levels)/sizeof(*levels); |
124 |
|
|
125 |
|
/*--------------------------------------------------------------------*/ |
126 |
|
|
127 |
|
struct vsc * |
128 |
23550 |
VSC_New(void) |
129 |
|
{ |
130 |
|
struct vsc *vsc; |
131 |
|
|
132 |
23550 |
ALLOC_OBJ(vsc, VSC_MAGIC); |
133 |
23550 |
if (vsc == NULL) |
134 |
0 |
return (vsc); |
135 |
23550 |
VTAILQ_INIT(&vsc->sf_list); |
136 |
23550 |
VTAILQ_INIT(&vsc->segs); |
137 |
23550 |
return (vsc); |
138 |
23550 |
} |
139 |
|
|
140 |
|
/*--------------------------------------------------------------------*/ |
141 |
|
|
142 |
|
static int |
143 |
900 |
vsc_sf_arg(struct vsc *vsc, const char *glob, const struct vsc_sf_mode *mode) |
144 |
|
{ |
145 |
|
struct vsc_sf *sf; |
146 |
|
|
147 |
900 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
148 |
900 |
AN(glob); |
149 |
900 |
AN(mode); |
150 |
|
|
151 |
900 |
ALLOC_OBJ(sf, VSC_SF_MAGIC); |
152 |
900 |
AN(sf); |
153 |
900 |
REPLACE(sf->pattern, glob); |
154 |
900 |
sf->mode = mode; |
155 |
900 |
AN(mode->name); |
156 |
900 |
if (mode->append) |
157 |
700 |
VTAILQ_INSERT_TAIL(&vsc->sf_list, sf, list); |
158 |
|
else |
159 |
200 |
VTAILQ_INSERT_HEAD(&vsc->sf_list, sf, list); |
160 |
900 |
return (1); |
161 |
|
} |
162 |
|
|
163 |
|
static int |
164 |
500 |
vsc_f_arg(struct vsc *vsc, const char *opt) |
165 |
|
{ |
166 |
|
|
167 |
500 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
168 |
500 |
AN(opt); |
169 |
|
|
170 |
500 |
if (opt[0] == '^') |
171 |
125 |
return (vsc_sf_arg(vsc, opt + 1, VSC_SF_EXCLUDE)); |
172 |
375 |
return (vsc_sf_arg(vsc, opt, VSC_SF_INCLUDE)); |
173 |
500 |
} |
174 |
|
|
175 |
|
/*--------------------------------------------------------------------*/ |
176 |
|
|
177 |
|
int |
178 |
900 |
VSC_Arg(struct vsc *vsc, char arg, const char *opt) |
179 |
|
{ |
180 |
|
|
181 |
900 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
182 |
|
|
183 |
900 |
switch (arg) { |
184 |
175 |
case 'I': return (vsc_sf_arg(vsc, opt, VSC_SF_INCLUDE)); |
185 |
25 |
case 'X': return (vsc_sf_arg(vsc, opt, VSC_SF_EXCLUDE)); |
186 |
200 |
case 'R': return (vsc_sf_arg(vsc, opt, VSC_SF_REQUIRE)); |
187 |
500 |
case 'f': return (vsc_f_arg(vsc, opt)); |
188 |
0 |
case 'r': vsc->raw = !vsc->raw; return (1); |
189 |
0 |
default: return (0); |
190 |
|
} |
191 |
900 |
} |
192 |
|
|
193 |
|
unsigned |
194 |
150 |
VSC_IsRaw(const struct vsc *vsc) |
195 |
|
{ |
196 |
|
|
197 |
150 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
198 |
150 |
return (vsc->raw); |
199 |
|
} |
200 |
|
|
201 |
|
/*-------------------------------------------------------------------- |
202 |
|
*/ |
203 |
|
|
204 |
|
static int |
205 |
1355708 |
vsc_filter(const struct vsc *vsc, const char *nm) |
206 |
|
{ |
207 |
|
struct vsc_sf *sf; |
208 |
1355708 |
unsigned res = 0; |
209 |
|
|
210 |
1355708 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
211 |
1620783 |
VTAILQ_FOREACH(sf, &vsc->sf_list, list) { |
212 |
270025 |
if (!fnmatch(sf->pattern, nm, 0)) |
213 |
4950 |
return (!sf->mode->include); |
214 |
265075 |
res |= sf->mode->fail; |
215 |
265075 |
} |
216 |
1350758 |
return (res); |
217 |
1355708 |
} |
218 |
|
|
219 |
|
/*-------------------------------------------------------------------- |
220 |
|
*/ |
221 |
|
|
222 |
|
static void |
223 |
1173458 |
vsc_clean_point(struct vsc_pt *point) |
224 |
|
{ |
225 |
1173458 |
REPLACE(point->name, NULL); |
226 |
1173458 |
} |
227 |
|
|
228 |
|
static void |
229 |
1355708 |
vsc_fill_point(const struct vsc *vsc, const struct vsc_seg *seg, |
230 |
|
const struct vjsn_val *vv, struct vsb *vsb, struct vsc_pt *point) |
231 |
|
{ |
232 |
|
struct vjsn_val *vt; |
233 |
|
|
234 |
1355708 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
235 |
1355708 |
memset(point, 0, sizeof *point); |
236 |
|
|
237 |
1355708 |
vt = vjsn_child(vv, "name"); |
238 |
1355708 |
AN(vt); |
239 |
1355708 |
assert(vjsn_is_string(vt)); |
240 |
|
|
241 |
1355708 |
VSB_clear(vsb); |
242 |
1355708 |
VSB_printf(vsb, "%s.%s", seg->fantom->ident, vt->value); |
243 |
1355708 |
AZ(VSB_finish(vsb)); |
244 |
|
|
245 |
1355708 |
if (vsc_filter(vsc, VSB_data(vsb))) |
246 |
90100 |
return; |
247 |
|
|
248 |
1265608 |
point->name = strdup(VSB_data(vsb)); |
249 |
1265608 |
AN(point->name); |
250 |
1265608 |
point->point.name = point->name; |
251 |
|
|
252 |
|
#define DOF(n, k) \ |
253 |
|
vt = vjsn_child(vv, k); \ |
254 |
|
AN(vt); \ |
255 |
|
assert(vjsn_is_string(vt)); \ |
256 |
|
point->point.n = vt->value; |
257 |
|
|
258 |
1265608 |
DOF(ctype, "ctype"); |
259 |
1265608 |
DOF(sdesc, "oneliner"); |
260 |
1265608 |
DOF(ldesc, "docs"); |
261 |
|
#undef DOF |
262 |
1265608 |
vt = vjsn_child(vv, "type"); |
263 |
1265608 |
AN(vt); |
264 |
1265608 |
assert(vjsn_is_string(vt)); |
265 |
|
|
266 |
1265608 |
if (!strcmp(vt->value, "counter")) { |
267 |
1101349 |
point->point.semantics = 'c'; |
268 |
1265608 |
} else if (!strcmp(vt->value, "gauge")) { |
269 |
160033 |
point->point.semantics = 'g'; |
270 |
164259 |
} else if (!strcmp(vt->value, "bitmap")) { |
271 |
4226 |
point->point.semantics = 'b'; |
272 |
4226 |
} else { |
273 |
0 |
point->point.semantics = '?'; |
274 |
|
} |
275 |
|
|
276 |
1265608 |
vt = vjsn_child(vv, "format"); |
277 |
1265608 |
AN(vt); |
278 |
1265608 |
assert(vjsn_is_string(vt)); |
279 |
|
|
280 |
1265608 |
if (!strcmp(vt->value, "integer")) { |
281 |
1125434 |
point->point.format = 'i'; |
282 |
1265608 |
} else if (!strcmp(vt->value, "bytes")) { |
283 |
125048 |
point->point.format = 'B'; |
284 |
140174 |
} else if (!strcmp(vt->value, "bitmap")) { |
285 |
4226 |
point->point.format = 'b'; |
286 |
15126 |
} else if (!strcmp(vt->value, "duration")) { |
287 |
10900 |
point->point.format = 'd'; |
288 |
10900 |
} else { |
289 |
0 |
point->point.format = '?'; |
290 |
|
} |
291 |
|
|
292 |
1265608 |
vt = vjsn_child(vv, "level"); |
293 |
1265608 |
AN(vt); |
294 |
1265608 |
assert(vjsn_is_string(vt)); |
295 |
|
|
296 |
1265608 |
if (!strcmp(vt->value, "info")) { |
297 |
585288 |
point->point.level = &levels[info]; |
298 |
1265608 |
} else if (!strcmp(vt->value, "diag")) { |
299 |
359182 |
point->point.level = &levels[diag]; |
300 |
680320 |
} else if (!strcmp(vt->value, "debug")) { |
301 |
321138 |
point->point.level = &levels[debug]; |
302 |
321138 |
} else { |
303 |
0 |
WRONG("Illegal level"); |
304 |
|
} |
305 |
|
|
306 |
1265608 |
vt = vjsn_child(vv, "index"); |
307 |
1265608 |
AN(vt); |
308 |
|
|
309 |
1265608 |
point->point.ptr = (volatile void*)(seg->body + atoi(vt->value)); |
310 |
1265608 |
point->point.raw = vsc->raw; |
311 |
1355708 |
} |
312 |
|
|
313 |
|
static void |
314 |
78585 |
vsc_del_seg(const struct vsc *vsc, struct vsm *vsm, struct vsc_seg **spp) |
315 |
|
{ |
316 |
|
unsigned u; |
317 |
|
struct vsc_pt *pp; |
318 |
|
struct vsc_seg *sp; |
319 |
|
|
320 |
78585 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
321 |
78585 |
TAKE_OBJ_NOTNULL(sp, spp, VSC_SEG_MAGIC); |
322 |
78585 |
AZ(VSM_Unmap(vsm, sp->fantom)); |
323 |
78585 |
if (sp->vj != NULL) { |
324 |
17626 |
vjsn_delete(&sp->vj); |
325 |
17626 |
} else { |
326 |
60959 |
pp = sp->points; |
327 |
1234417 |
for (u = 0; u < sp->npoints; u++, pp++) |
328 |
1173458 |
vsc_clean_point(pp); |
329 |
60959 |
free(sp->points); |
330 |
|
} |
331 |
78585 |
FREE_OBJ(sp); |
332 |
78585 |
} |
333 |
|
|
334 |
|
static struct vsc_seg * |
335 |
95310 |
vsc_add_seg(const struct vsc *vsc, struct vsm *vsm, const struct vsm_fantom *fp) |
336 |
|
{ |
337 |
|
struct vsc_seg *sp, *spd; |
338 |
|
const char *e; |
339 |
|
struct vjsn_val *vv, *vve; |
340 |
|
struct vsb *vsb; |
341 |
|
struct vsc_pt *pp; |
342 |
|
|
343 |
95310 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
344 |
|
|
345 |
95310 |
ALLOC_OBJ(sp, VSC_SEG_MAGIC); |
346 |
95310 |
AN(sp); |
347 |
95310 |
*sp->fantom = *fp; |
348 |
95310 |
if (VSM_Map(vsm, sp->fantom)) { |
349 |
|
/* |
350 |
|
* If the seg was removed between our call to VSM_Status() |
351 |
|
* and now, we won't be able to map it. |
352 |
|
*/ |
353 |
0 |
FREE_OBJ(sp); |
354 |
0 |
return (NULL); |
355 |
|
} |
356 |
95310 |
sp->head = sp->fantom->b; |
357 |
95310 |
if (sp->head->ready == 0) { |
358 |
0 |
VRMB(); |
359 |
0 |
usleep(100000); |
360 |
0 |
} |
361 |
95310 |
assert(sp->head->ready > 0); |
362 |
95310 |
sp->body = (char*)sp->fantom->b + sp->head->body_offset; |
363 |
|
|
364 |
95310 |
if (!strcmp(fp->category, VSC_CLASS)) { |
365 |
852995 |
VTAILQ_FOREACH(spd, &vsc->segs, list) |
366 |
852995 |
if (spd->head->doc_id == sp->head->doc_id) |
367 |
75434 |
break; |
368 |
75434 |
AN(spd); |
369 |
|
// XXX: Refcount ? |
370 |
75434 |
vve = vjsn_child(spd->vj->value, "elements"); |
371 |
75434 |
AN(vve); |
372 |
75434 |
sp->npoints = strtoul(vve->value, NULL, 0); |
373 |
75434 |
sp->points = calloc(sp->npoints, sizeof *sp->points); |
374 |
75434 |
AN(sp->points); |
375 |
75434 |
vsb = VSB_new_auto(); |
376 |
75434 |
AN(vsb); |
377 |
75434 |
vve = vjsn_child(spd->vj->value, "elem"); |
378 |
75434 |
AN(vve); |
379 |
75434 |
pp = sp->points; |
380 |
1431142 |
VTAILQ_FOREACH(vv, &vve->children, list) { |
381 |
1355708 |
vsc_fill_point(vsc, sp, vv, vsb, pp); |
382 |
1355708 |
pp++; |
383 |
1355708 |
} |
384 |
75434 |
VSB_destroy(&vsb); |
385 |
75434 |
return (sp); |
386 |
|
} |
387 |
19876 |
assert(!strcmp(fp->category, VSC_DOC_CLASS)); |
388 |
19876 |
sp->vj = vjsn_parse(sp->body, &e); |
389 |
19876 |
XXXAZ(e); |
390 |
19876 |
AN(sp->vj); |
391 |
19876 |
return (sp); |
392 |
95310 |
} |
393 |
|
|
394 |
|
/*-------------------------------------------------------------------- |
395 |
|
*/ |
396 |
|
|
397 |
|
static void |
398 |
661560 |
vsc_expose(const struct vsc *vsc, struct vsc_seg *sp, int del) |
399 |
|
{ |
400 |
|
struct vsc_pt *pp; |
401 |
|
unsigned u; |
402 |
|
int expose; |
403 |
|
|
404 |
667160 |
if (vsc->fnew != NULL && !sp->exposed && |
405 |
5600 |
!del && sp->head->ready == 1) |
406 |
5600 |
expose = 1; |
407 |
691848 |
else if (vsc->fdestroy != NULL && sp->exposed && |
408 |
41488 |
(del || sp->head->ready == 2)) |
409 |
5600 |
expose = 0; |
410 |
|
else |
411 |
650360 |
return; |
412 |
|
|
413 |
11200 |
pp = sp->points; |
414 |
115400 |
for (u = 0; u < sp->npoints; u++, pp++) { |
415 |
104200 |
if (pp->name == NULL) |
416 |
16450 |
continue; |
417 |
87750 |
if (expose) |
418 |
43875 |
pp->point.priv = vsc->fnew(vsc->priv, &pp->point); |
419 |
|
else |
420 |
43875 |
vsc->fdestroy(vsc->priv, &pp->point); |
421 |
87750 |
} |
422 |
11200 |
sp->exposed = expose; |
423 |
661560 |
} |
424 |
|
|
425 |
|
/*-------------------------------------------------------------------- |
426 |
|
*/ |
427 |
|
|
428 |
|
static int |
429 |
536462 |
vsc_iter_seg(const struct vsc *vsc, const struct vsc_seg *sp, |
430 |
|
VSC_iter_f *fiter, void *priv) |
431 |
|
{ |
432 |
|
unsigned u; |
433 |
536462 |
int i = 0; |
434 |
|
struct vsc_pt *pp; |
435 |
|
|
436 |
536462 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
437 |
536462 |
CHECK_OBJ_NOTNULL(sp, VSC_SEG_MAGIC); |
438 |
536462 |
AN(fiter); |
439 |
536462 |
pp = sp->points; |
440 |
6283647 |
for (u = 0; u < sp->npoints && i == 0; u++, pp++) { |
441 |
5747185 |
if (pp->name != NULL) |
442 |
5698160 |
i = fiter(priv, &pp->point); |
443 |
5747185 |
} |
444 |
536462 |
return (i); |
445 |
|
} |
446 |
|
|
447 |
|
int |
448 |
28904 |
VSC_Iter(struct vsc *vsc, struct vsm *vsm, VSC_iter_f *fiter, void *priv) |
449 |
|
{ |
450 |
|
struct vsm_fantom ifantom; |
451 |
|
struct vsc_seg *sp, *sp2; |
452 |
28904 |
int i = 0; |
453 |
|
|
454 |
28904 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
455 |
28904 |
AN(vsm); |
456 |
28904 |
sp = VTAILQ_FIRST(&vsc->segs); |
457 |
749307 |
VSM_FOREACH(&ifantom, vsm) { |
458 |
741331 |
AN(ifantom.category); |
459 |
741331 |
if (strcmp(ifantom.category, VSC_CLASS) && |
460 |
266973 |
strcmp(ifantom.category, VSC_DOC_CLASS)) |
461 |
158356 |
continue; |
462 |
1076290 |
while (sp != NULL && |
463 |
490490 |
(strcmp(ifantom.ident, sp->fantom->ident) || |
464 |
487990 |
VSM_StillValid(vsm, sp->fantom) != VSM_valid)) { |
465 |
2825 |
sp2 = sp; |
466 |
2825 |
sp = VTAILQ_NEXT(sp, list); |
467 |
2825 |
VTAILQ_REMOVE(&vsc->segs, sp2, list); |
468 |
2825 |
vsc_expose(vsc, sp2, 1); |
469 |
2825 |
vsc_del_seg(vsc, vsm, &sp2); |
470 |
|
} |
471 |
582975 |
if (sp == NULL) { |
472 |
95310 |
sp = vsc_add_seg(vsc, vsm, &ifantom); |
473 |
95310 |
if (sp != NULL) { |
474 |
95310 |
VTAILQ_INSERT_TAIL(&vsc->segs, sp, list); |
475 |
95310 |
vsc_expose(vsc, sp, 0); |
476 |
95310 |
} |
477 |
95310 |
} else { |
478 |
487665 |
vsc_expose(vsc, sp, 0); |
479 |
|
} |
480 |
582975 |
if (sp != NULL) { |
481 |
582975 |
if (fiter != NULL && sp->head->ready < 2) |
482 |
536462 |
i = vsc_iter_seg(vsc, sp, fiter, priv); |
483 |
582975 |
sp = VTAILQ_NEXT(sp, list); |
484 |
582975 |
} |
485 |
|
|
486 |
582975 |
if (i) |
487 |
20928 |
break; |
488 |
|
} |
489 |
52853 |
while (sp != NULL) { |
490 |
23949 |
sp2 = sp; |
491 |
23949 |
sp = VTAILQ_NEXT(sp, list); |
492 |
23949 |
VTAILQ_REMOVE(&vsc->segs, sp2, list); |
493 |
23949 |
vsc_expose(vsc, sp2, 1); |
494 |
23949 |
vsc_del_seg(vsc, vsm, &sp2); |
495 |
|
} |
496 |
28904 |
return (i); |
497 |
|
} |
498 |
|
|
499 |
|
/*-------------------------------------------------------------------- |
500 |
|
*/ |
501 |
|
|
502 |
|
void |
503 |
150 |
VSC_State(struct vsc *vsc, VSC_new_f *fn, VSC_destroy_f *fd, void *priv) |
504 |
|
{ |
505 |
|
struct vsc_seg *sp; |
506 |
|
|
507 |
150 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
508 |
150 |
assert((fn == NULL && fd == NULL) || (fn != NULL && fd != NULL)); |
509 |
150 |
if (fd == NULL) { |
510 |
0 |
VTAILQ_FOREACH(sp, &vsc->segs, list) |
511 |
0 |
vsc_expose(vsc, sp, 1); |
512 |
0 |
} |
513 |
150 |
vsc->fnew = fn; |
514 |
150 |
vsc->fdestroy = fd; |
515 |
150 |
vsc->priv = priv; |
516 |
150 |
} |
517 |
|
|
518 |
|
/*-------------------------------------------------------------------- |
519 |
|
*/ |
520 |
|
|
521 |
|
const struct VSC_level_desc * |
522 |
250 |
VSC_ChangeLevel(const struct VSC_level_desc *old, int chg) |
523 |
|
{ |
524 |
|
int i; |
525 |
|
|
526 |
250 |
if (old == NULL) |
527 |
150 |
old = &levels[0]; |
528 |
275 |
for (i = 0; i < nlevels; i++) |
529 |
275 |
if (old == &levels[i]) |
530 |
250 |
break; |
531 |
250 |
if (i == nlevels) |
532 |
0 |
i = 0; |
533 |
|
|
534 |
250 |
i += chg; |
535 |
250 |
if (i >= nlevels) |
536 |
0 |
i = nlevels - 1; |
537 |
250 |
if (i < 0) |
538 |
0 |
i = 0; |
539 |
250 |
return (&levels[i]); |
540 |
|
} |
541 |
|
|
542 |
|
/*--------------------------------------------------------------------*/ |
543 |
|
|
544 |
|
void |
545 |
23000 |
VSC_Destroy(struct vsc **vscp, struct vsm *vsm) |
546 |
|
{ |
547 |
|
struct vsc *vsc; |
548 |
|
struct vsc_sf *sf, *sf2; |
549 |
|
struct vsc_seg *sp, *sp2; |
550 |
|
|
551 |
23000 |
TAKE_OBJ_NOTNULL(vsc, vscp, VSC_MAGIC); |
552 |
|
|
553 |
23475 |
VTAILQ_FOREACH_SAFE(sf, &vsc->sf_list, list, sf2) { |
554 |
475 |
CHECK_OBJ_NOTNULL(sf, VSC_SF_MAGIC); |
555 |
475 |
VTAILQ_REMOVE(&vsc->sf_list, sf, list); |
556 |
475 |
free(sf->pattern); |
557 |
475 |
FREE_OBJ(sf); |
558 |
475 |
} |
559 |
74811 |
VTAILQ_FOREACH_SAFE(sp, &vsc->segs, list, sp2) { |
560 |
51811 |
VTAILQ_REMOVE(&vsc->segs, sp, list); |
561 |
51811 |
vsc_expose(vsc, sp, 1); |
562 |
51811 |
vsc_del_seg(vsc, vsm, &sp); |
563 |
51811 |
} |
564 |
23000 |
FREE_OBJ(vsc); |
565 |
23000 |
} |
566 |
|
|