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