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
51
#include "vapi/vsc.h"
52
#include "vapi/vsm.h"
53
54
struct vsc_sf_mode {
55
        const char              *name;
56
        unsigned                include;
57
        unsigned                fail;
58
        unsigned                append;
59
};
60
61
static const struct vsc_sf_mode VSC_SF_INCLUDE[1] = {{"include", 1, 1, 1}};
62
static const struct vsc_sf_mode VSC_SF_EXCLUDE[1] = {{"exclude", 0, 0, 1}};
63
static const struct vsc_sf_mode VSC_SF_REQUIRE[1] = {{"require", 1, 0, 0}};
64
65
struct vsc_sf {
66
        unsigned                        magic;
67
#define VSC_SF_MAGIC                    0x558478dd
68
        VTAILQ_ENTRY(vsc_sf)            list;
69
        char                            *pattern;
70
        const struct vsc_sf_mode        *mode;
71
};
72
73
VTAILQ_HEAD(vsc_sf_head, vsc_sf);
74
75
struct vsc_pt {
76
        struct VSC_point        point;
77
        char                    *name;
78
};
79
80
enum vsc_seg_type {
81
        VSC_SEG_COUNTERS = 1,
82
        VSC_SEG_DOCS,
83
};
84
85
struct vsc_seg {
86
        unsigned                magic;
87
#define VSC_SEG_MAGIC           0x801177d4
88
        enum vsc_seg_type       type;
89
        VTAILQ_ENTRY(vsc_seg)   list;
90
        VTAILQ_ENTRY(vsc_seg)   doc_list;
91
        struct vsm_fantom       fantom[1];
92
        const struct vsc_head   *head;
93
        const char              *body;
94
95
        struct vjsn             *vj;
96
97
        unsigned                npoints;
98
        struct vsc_pt           *points;
99
100
        int                     mapped;
101
        int                     exposed;
102
};
103
VTAILQ_HEAD(vsc_seg_head, vsc_seg);
104
105
struct vsc {
106
        unsigned                magic;
107
#define VSC_MAGIC               0x3373554a
108
109
        unsigned                raw;
110
        struct vsc_sf_head      sf_list;
111
        struct vsc_seg_head     segs;
112
        struct vsc_seg_head     docs;
113
114
        VSC_new_f               *fnew;
115
        VSC_destroy_f           *fdestroy;
116
        void                    *priv;
117
};
118
119
/*--------------------------------------------------------------------
120
 * Build the static level, type and point descriptions
121
 */
122
123
enum vsc_levels {
124
#define VSC_LEVEL_F(v,l,e,d) v,
125
#include "tbl/vsc_levels.h"
126
};
127
128
static const struct VSC_level_desc levels[] = {
129
#define VSC_LEVEL_F(v,l,e,d) [v] = {#v, l, e, d},
130
#include "tbl/vsc_levels.h"
131
};
132
133
static const ssize_t nlevels = sizeof(levels)/sizeof(*levels);
134
135
/*--------------------------------------------------------------------*/
136
137
struct vsc *
138 38800
VSC_New(void)
139
{
140
        struct vsc *vsc;
141
142 38800
        ALLOC_OBJ(vsc, VSC_MAGIC);
143 38800
        if (vsc == NULL)
144 0
                return (vsc);
145 38800
        VTAILQ_INIT(&vsc->sf_list);
146 38800
        VTAILQ_INIT(&vsc->segs);
147 38800
        VTAILQ_INIT(&vsc->docs);
148 38800
        return (vsc);
149 38800
}
150
151
/*--------------------------------------------------------------------*/
152
153
static int
154 1480
vsc_sf_arg(struct vsc *vsc, const char *glob, const struct vsc_sf_mode *mode)
155
{
156
        struct vsc_sf *sf;
157
158 1480
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
159 1480
        AN(glob);
160 1480
        AN(mode);
161
162 1480
        ALLOC_OBJ(sf, VSC_SF_MAGIC);
163 1480
        AN(sf);
164 1480
        REPLACE(sf->pattern, glob);
165 1480
        sf->mode = mode;
166 1480
        AN(mode->name);
167 1480
        if (mode->append)
168 1160
                VTAILQ_INSERT_TAIL(&vsc->sf_list, sf, list);
169
        else
170 320
                VTAILQ_INSERT_HEAD(&vsc->sf_list, sf, list);
171 1480
        return (1);
172
}
173
174
static int
175 840
vsc_f_arg(struct vsc *vsc, const char *opt)
176
{
177
178 840
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
179 840
        AN(opt);
180
181 840
        if (opt[0] == '^')
182 200
                return (vsc_sf_arg(vsc, opt + 1, VSC_SF_EXCLUDE));
183 640
        return (vsc_sf_arg(vsc, opt, VSC_SF_INCLUDE));
184 840
}
185
186
/*--------------------------------------------------------------------*/
187
188
int
189 1480
VSC_Arg(struct vsc *vsc, char arg, const char *opt)
190
{
191
192 1480
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
193
194 1480
        switch (arg) {
195 280
        case 'I': return (vsc_sf_arg(vsc, opt, VSC_SF_INCLUDE));
196 40
        case 'X': return (vsc_sf_arg(vsc, opt, VSC_SF_EXCLUDE));
197 320
        case 'R': return (vsc_sf_arg(vsc, opt, VSC_SF_REQUIRE));
198 840
        case 'f': return (vsc_f_arg(vsc, opt));
199 0
        case 'r': vsc->raw = !vsc->raw; return (1);
200 0
        default: return (0);
201
        }
202 1480
}
203
204
unsigned
205 240
VSC_IsRaw(const struct vsc *vsc)
206
{
207
208 240
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
209 240
        return (vsc->raw);
210
}
211
212
/*--------------------------------------------------------------------
213
 */
214
215
static int
216 2149984
vsc_filter(const struct vsc *vsc, const char *nm)
217
{
218
        struct vsc_sf *sf;
219 2149984
        unsigned res = 0;
220
221 2149984
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
222 2594664
        VTAILQ_FOREACH(sf, &vsc->sf_list, list) {
223 452800
                if (!fnmatch(sf->pattern, nm, 0))
224 8120
                        return (!sf->mode->include);
225 444680
                res |= sf->mode->fail;
226 444680
        }
227 2141864
        return (res);
228 2149984
}
229
230
/*--------------------------------------------------------------------
231
 */
232
233
static void
234 1836544
vsc_clean_point(struct vsc_pt *point)
235
{
236 1836544
        REPLACE(point->name, NULL);
237 1836544
}
238
239
static void
240 2149984
vsc_fill_point(const struct vsc *vsc, const struct vsc_seg *seg,
241
    const struct vjsn_val *vv, struct vsb *vsb, struct vsc_pt *point)
242
{
243
        struct vjsn_val *vt;
244
245 2149984
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
246 2149984
        memset(point, 0, sizeof *point);
247
248 2149984
        vt = vjsn_child(vv, "name");
249 2149984
        AN(vt);
250 2149984
        assert(vjsn_is_string(vt));
251
252 2149984
        VSB_clear(vsb);
253 2149984
        VSB_printf(vsb, "%s.%s", seg->fantom->ident, vt->value);
254 2149984
        AZ(VSB_finish(vsb));
255
256 2149984
        if (vsc_filter(vsc, VSB_data(vsb)))
257 154960
                return;
258
259 1995024
        point->name = strdup(VSB_data(vsb));
260 1995024
        AN(point->name);
261 1995024
        point->point.name = point->name;
262
263
#define DOF(n, k)                               \
264
        vt = vjsn_child(vv, k);                 \
265
        AN(vt);                                 \
266
        assert(vjsn_is_string(vt));             \
267
        point->point.n = vt->value;
268
269 1995024
        DOF(ctype, "ctype");
270 1995024
        DOF(sdesc, "oneliner");
271 1995024
        DOF(ldesc, "docs");
272
#undef DOF
273 1995024
        vt = vjsn_child(vv, "type");
274 1995024
        AN(vt);
275 1995024
        assert(vjsn_is_string(vt));
276
277 1995024
        if (!strcmp(vt->value, "counter")) {
278 1753865
                point->point.semantics = 'c';
279 1995024
        } else if (!strcmp(vt->value, "gauge")) {
280 235610
                point->point.semantics = 'g';
281 241159
        } else if (!strcmp(vt->value, "bitmap")) {
282 5549
                point->point.semantics = 'b';
283 5549
        } else {
284 0
                point->point.semantics = '?';
285
        }
286
287 1995024
        vt = vjsn_child(vv, "format");
288 1995024
        AN(vt);
289 1995024
        assert(vjsn_is_string(vt));
290
291 1995024
        if (!strcmp(vt->value, "integer")) {
292 1803286
                point->point.format = 'i';
293 1995024
        } else if (!strcmp(vt->value, "bytes")) {
294 167829
                point->point.format = 'B';
295 191738
        } else if (!strcmp(vt->value, "bitmap")) {
296 5549
                point->point.format = 'b';
297 23909
        } else if (!strcmp(vt->value, "duration")) {
298 18360
                point->point.format = 'd';
299 18360
        } else {
300 0
                point->point.format = '?';
301
        }
302
303 1995024
        vt = vjsn_child(vv, "level");
304 1995024
        AN(vt);
305 1995024
        assert(vjsn_is_string(vt));
306
307 1995024
        if (!strcmp(vt->value, "info"))  {
308 946603
                point->point.level = &levels[info];
309 1995024
        } else if (!strcmp(vt->value, "diag")) {
310 613323
                point->point.level = &levels[diag];
311 1048421
        } else if (!strcmp(vt->value, "debug")) {
312 435098
                point->point.level = &levels[debug];
313 435098
        } else {
314 0
                WRONG("Illegal level");
315
        }
316
317 1995024
        vt = vjsn_child(vv, "index");
318 1995024
        AN(vt);
319
320 1995024
        point->point.ptr = (volatile const void*)(seg->body + atoi(vt->value));
321 1995024
        point->point.raw = vsc->raw;
322 2149984
}
323
324
static struct vsc_seg *
325 417321
vsc_new_seg(const struct vsm_fantom *fp, enum vsc_seg_type type)
326
{
327
        struct vsc_seg *sp;
328
329 417321
        ALLOC_OBJ(sp, VSC_SEG_MAGIC);
330 417321
        AN(sp);
331 417321
        *sp->fantom = *fp;
332 417321
        sp->type = type;
333
334 417321
        return (sp);
335
}
336
337
static void
338 387121
vsc_unmap_seg(const struct vsc *vsc, struct vsm *vsm, struct vsc_seg *sp)
339
{
340
        unsigned u;
341
        struct vsc_pt *pp;
342
343 387121
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
344 387121
        AN(vsm);
345 387121
        CHECK_OBJ_NOTNULL(sp, VSC_SEG_MAGIC);
346
347 387121
        AZ(sp->exposed);
348 387121
        if (!sp->mapped)
349 280371
                return;
350
351 106750
        if (sp->type == VSC_SEG_COUNTERS) {
352 79602
                pp = sp->points;
353 1916146
                for (u = 0; u < sp->npoints; u++, pp++)
354 1836544
                        vsc_clean_point(pp);
355 79602
                free(sp->points);
356 79602
                sp->points = NULL;
357 79602
                sp->npoints = 0;
358 79602
                AZ(sp->vj);
359 106750
        } else if (sp->type == VSC_SEG_DOCS) {
360 27148
                if (sp->vj != NULL)
361 27148
                        vjsn_delete(&sp->vj);
362 27148
                AZ(sp->vj);
363 27148
                AZ(sp->points);
364 27148
        } else {
365 0
                WRONG("Invalid segment type");
366
        }
367
368 106750
        AZ(VSM_Unmap(vsm, sp->fantom));
369 106750
        sp->head = NULL;
370 106750
        sp->body = NULL;
371 106750
        sp->mapped = 0;
372 387121
}
373
374
static int
375 918480
vsc_map_seg(const struct vsc *vsc, struct vsm *vsm, struct vsc_seg *sp)
376
{
377
        const struct vsc_head *head;
378
        struct vsc_seg *spd;
379
        const char *e;
380
        struct vjsn_val *vv, *vve;
381
        struct vsb *vsb;
382
        struct vsc_pt *pp;
383
        int retry;
384
385 918480
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
386 918480
        AN(vsm);
387 918480
        CHECK_OBJ_NOTNULL(sp, VSC_SEG_MAGIC);
388
389 918480
        if (sp->mapped)
390 781530
                return (0);
391
392 136950
        AZ(sp->exposed);
393
394 136950
        if (VSM_Map(vsm, sp->fantom))
395 0
                return (-1);
396 136950
        head = sp->fantom->b;
397
398
        /* It isn't ready yet. Sleep and try again. If it still
399
         * isn't ready, fail the mapping. The transitions inside
400
         * varnishd that we are waiting for are just some memcpy()
401
         * operations, so there is no reason to allow a long retry
402
         * time. */
403 136950
        for (retry = 10; retry > 0 && head->ready == 0; retry--)
404 0
                usleep(10000);
405
406 136950
        if (head->ready == 0) {
407 0
                AZ(VSM_Unmap(vsm, sp->fantom));
408 0
                return (-1);
409
        }
410
411 136950
        sp->head = head;
412 136950
        sp->body = (char*)sp->fantom->b + sp->head->body_offset;
413 136950
        sp->mapped = 1;
414
415 136950
        if (sp->type == VSC_SEG_DOCS) {
416
                /* Parse the DOCS json */
417 31628
                sp->vj = vjsn_parse(sp->body, &e);
418 31628
                XXXAZ(e);
419 31628
                AN(sp->vj);
420 31628
                return (0);
421
        }
422
423 105322
        assert(sp->type == VSC_SEG_COUNTERS);
424
425
        /* Find the corresponding DOCS seg. We are not able to
426
         * read and match on the doc_id until the DOCS section is
427
         * mapped. Iterate over all the DOCS sections, attempt to
428
         * map if needed, and then check the doc_id. */
429 344051
        VTAILQ_FOREACH(spd, &vsc->docs, doc_list) {
430 344051
                CHECK_OBJ_NOTNULL(spd, VSC_SEG_MAGIC);
431 344051
                assert(spd->type == VSC_SEG_DOCS);
432 344051
                if (!spd->mapped && vsc_map_seg(vsc, vsm, spd))
433 0
                        continue; /* Failed to map it */
434 344051
                AN(spd->mapped);
435 344051
                if (spd->head->doc_id == sp->head->doc_id)
436 105322
                        break; /* We have a match */
437 238729
        }
438 105322
        if (spd == NULL) {
439
                /* Could not find the right DOCS seg. Leave this
440
                 * seg as unmapped. */
441 0
                vsc_unmap_seg(vsc, vsm, sp);
442 0
                return (-1);
443
        }
444
445
        /* Create the VSC points list */
446 105322
        vve = vjsn_child(spd->vj->value, "elements");
447 105322
        AN(vve);
448 105322
        sp->npoints = strtoul(vve->value, NULL, 0);
449 105322
        sp->points = calloc(sp->npoints, sizeof *sp->points);
450 105322
        AN(sp->points);
451 105322
        vsb = VSB_new_auto();
452 105322
        AN(vsb);
453 105322
        vve = vjsn_child(spd->vj->value, "elem");
454 105322
        AN(vve);
455 105322
        pp = sp->points;
456 2255306
        VTAILQ_FOREACH(vv, &vve->children, list) {
457 2149984
                vsc_fill_point(vsc, sp, vv, vsb, pp);
458 2149984
                pp++;
459 2149984
        }
460 105322
        VSB_destroy(&vsb);
461 105322
        return (0);
462 918480
}
463
464
/*--------------------------------------------------------------------
465
 */
466
467
static void
468 1273973
vsc_expose(const struct vsc *vsc, struct vsc_seg *sp, int del)
469
{
470
        struct vsc_pt *pp;
471
        unsigned u;
472
        int expose;
473
474 1273973
        if (!sp->mapped) {
475 280371
                AZ(sp->exposed);
476 280371
                return;
477
        }
478
479 1001682
        if (vsc->fnew != NULL && !sp->exposed &&
480 9680
            !del && sp->head->ready == 1)
481 8080
                expose = 1;
482 1041932
        else if (vsc->fdestroy != NULL && sp->exposed &&
483 64490
            (del || sp->head->ready == 2))
484 8080
                expose = 0;
485
        else
486 977442
                return;
487
488 16160
        pp = sp->points;
489 188640
        for (u = 0; u < sp->npoints; u++, pp++) {
490 172480
                if (pp->name == NULL)
491 27280
                        continue;
492 145200
                if (expose)
493 72600
                        pp->point.priv = vsc->fnew(vsc->priv, &pp->point);
494
                else
495 72600
                        vsc->fdestroy(vsc->priv, &pp->point);
496 145200
        }
497 16160
        sp->exposed = expose;
498 1273973
}
499
500
/*--------------------------------------------------------------------
501
 */
502
503
static void
504 88608
vsc_del_segs(struct vsc *vsc, struct vsm *vsm, struct vsc_seg_head *head)
505
{
506
        struct vsc_seg *sp, *sp2;
507
508 475729
        VTAILQ_FOREACH_SAFE(sp, head, list, sp2) {
509 387121
                CHECK_OBJ(sp, VSC_SEG_MAGIC);
510 387121
                VTAILQ_REMOVE(head, sp, list);
511 387121
                if (sp->type == VSC_SEG_DOCS)
512 64560
                        VTAILQ_REMOVE(&vsc->docs, sp, doc_list);
513 387121
                vsc_expose(vsc, sp, 1);
514 387121
                vsc_unmap_seg(vsc, vsm, sp);
515 387121
                FREE_OBJ(sp);
516 387121
        }
517 88608
}
518
519
/*--------------------------------------------------------------------
520
 */
521
522
static int
523 810322
vsc_iter_seg(const struct vsc *vsc, const struct vsc_seg *sp,
524
    VSC_iter_f *fiter, void *priv)
525
{
526
        unsigned u;
527 810322
        int i = 0;
528
        struct vsc_pt *pp;
529
530 810322
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
531 810322
        CHECK_OBJ_NOTNULL(sp, VSC_SEG_MAGIC);
532 810322
        AN(fiter);
533 810322
        pp = sp->points;
534 11306618
        for (u = 0; u < sp->npoints && i == 0; u++, pp++) {
535 10496296
                if (pp->name != NULL)
536 10414976
                        i = fiter(priv, &pp->point);
537 10496296
        }
538 810322
        return (i);
539
}
540
541
int
542 50768
VSC_Iter(struct vsc *vsc, struct vsm *vsm, VSC_iter_f *fiter, void *priv)
543
{
544
        enum vsc_seg_type type;
545
        struct vsm_fantom ifantom;
546
        struct vsc_seg *sp, *sp2;
547
        struct vsc_seg_head removed;
548 50768
        int i = 0;
549
550 50768
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
551 50768
        AN(vsm);
552
553
        /* First walk the VSM segment list and consolidate with the shadow
554
         * VSC seg list. We avoid calling any of the callback functions
555
         * while iterating the VSMs. This removes any headaches wrt to
556
         * callbacks calling VSM_Status(). */
557 50768
        VTAILQ_INIT(&removed);
558 50768
        sp = VTAILQ_FIRST(&vsc->segs);
559 2454112
        VSM_FOREACH(&ifantom, vsm) {
560 2403344
                AN(ifantom.category);
561 2403344
                if (!strcmp(ifantom.category, VSC_CLASS))
562 1746194
                        type = VSC_SEG_COUNTERS;
563 657150
                else if (!strcmp(ifantom.category, VSC_DOC_CLASS))
564 353839
                        type = VSC_SEG_DOCS;
565
                else {
566
                        /* Not one of the categories we care about */
567 303311
                        continue;
568
                }
569
570 2125741
                while (sp != NULL) {
571 1708420
                        CHECK_OBJ_NOTNULL(sp, VSC_SEG_MAGIC);
572 1708420
                        if (VSM_StillValid(vsm, sp->fantom) == VSM_valid &&
573 1682712
                            !strcmp(ifantom.ident, sp->fantom->ident)) {
574
                                /* sp matches the expected value */
575 1682712
                                break;
576
                        }
577
578
                        /* sp is no longer in the VSM list. Remove it from
579
                         * our list. */
580 25708
                        sp2 = sp;
581 25708
                        sp = VTAILQ_NEXT(sp, list);
582 25708
                        VTAILQ_REMOVE(&vsc->segs, sp2, list);
583 25708
                        VTAILQ_INSERT_TAIL(&removed, sp2, list);
584
                }
585
586 2100033
                if (sp == NULL) {
587
                        /* New entries are always appended last in the VSM
588
                         * list. Since we have iterated past all the
589
                         * entries in our shadow list, the VSM entry is a
590
                         * new entry we have not seen before. */
591 417321
                        sp = vsc_new_seg(&ifantom, type);
592 417321
                        AN(sp);
593 417321
                        VTAILQ_INSERT_TAIL(&vsc->segs, sp, list);
594 417321
                        if (type == VSC_SEG_DOCS)
595 69040
                                VTAILQ_INSERT_TAIL(&vsc->docs, sp, doc_list);
596 417321
                }
597
598 2100033
                assert(sp->type == type);
599 2100033
                sp = VTAILQ_NEXT(sp, list);
600
        }
601 50768
        while (sp != NULL) {
602
                /* Clean up the tail end of the shadow list. */
603 0
                CHECK_OBJ_NOTNULL(sp, VSC_SEG_MAGIC);
604 0
                sp2 = sp;
605 0
                sp = VTAILQ_NEXT(sp, list);
606
607 0
                VTAILQ_REMOVE(&vsc->segs, sp2, list);
608 0
                VTAILQ_INSERT_TAIL(&removed, sp2, list);
609
        }
610
611 50768
        vsc_del_segs(vsc, vsm, &removed);
612
613
        /* Iterate our shadow list, reporting on each pointer value */
614 1113154
        VTAILQ_FOREACH(sp, &vsc->segs, list) {
615 1100209
                CHECK_OBJ_NOTNULL(sp, VSC_SEG_MAGIC);
616
617 1100209
                if (sp->type != VSC_SEG_COUNTERS)
618 213357
                        continue;
619
620
                /* Attempt to map the VSM. This is a noop if it was
621
                 * already mapped. If we fail we skip this seg on this
622
                 * call to VSC_Iter(), but will attempt again the next
623
                 * time VSC_Iter() is called. */
624 886852
                if (vsc_map_seg(vsc, vsm, sp))
625 0
                        continue;
626
627
                /* Expose the counters if necessary */
628 886852
                vsc_expose(vsc, sp, 0);
629
630 886852
                if (fiter != NULL && sp->head->ready == 1)
631 810322
                        i = vsc_iter_seg(vsc, sp, fiter, priv);
632 886852
                if (i)
633 37823
                        break;
634 849029
        }
635
636 50768
        return (i);
637
}
638
639
/*--------------------------------------------------------------------
640
 */
641
642
void
643 240
VSC_State(struct vsc *vsc, VSC_new_f *fn, VSC_destroy_f *fd, void *priv)
644
{
645
        struct vsc_seg *sp;
646
647 240
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
648 240
        assert((fn == NULL && fd == NULL) || (fn != NULL && fd != NULL));
649 240
        if (fd == NULL) {
650 0
                VTAILQ_FOREACH(sp, &vsc->segs, list)
651 0
                        vsc_expose(vsc, sp, 1);
652 0
        }
653 240
        vsc->fnew = fn;
654 240
        vsc->fdestroy = fd;
655 240
        vsc->priv = priv;
656 240
}
657
658
/*--------------------------------------------------------------------
659
 */
660
661
const struct VSC_level_desc *
662 400
VSC_ChangeLevel(const struct VSC_level_desc *old, int chg)
663
{
664
        int i;
665
666 400
        if (old == NULL)
667 240
                old = &levels[0];
668 440
        for (i = 0; i < nlevels; i++)
669 440
                if (old == &levels[i])
670 400
                        break;
671 400
        if (i == nlevels)
672 0
                i = 0;
673
674 400
        i += chg;
675 400
        if (i >= nlevels)
676 0
                i = nlevels - 1;
677 400
        if (i < 0)
678 0
                i = 0;
679 400
        return (&levels[i]);
680
}
681
682
/*--------------------------------------------------------------------*/
683
684
void
685 37840
VSC_Destroy(struct vsc **vscp, struct vsm *vsm)
686
{
687
        struct vsc *vsc;
688
        struct vsc_sf *sf, *sf2;
689
690 37840
        TAKE_OBJ_NOTNULL(vsc, vscp, VSC_MAGIC);
691
692 38640
        VTAILQ_FOREACH_SAFE(sf, &vsc->sf_list, list, sf2) {
693 800
                CHECK_OBJ_NOTNULL(sf, VSC_SF_MAGIC);
694 800
                VTAILQ_REMOVE(&vsc->sf_list, sf, list);
695 800
                free(sf->pattern);
696 800
                FREE_OBJ(sf);
697 800
        }
698
699 37840
        vsc_del_segs(vsc, vsm, &vsc->segs);
700 37840
        assert(VTAILQ_EMPTY(&vsc->docs));
701 37840
        FREE_OBJ(vsc);
702 37840
}