varnish-cache/bin/varnishd/cache/cache_obj.c
0
/*-
1
 * Copyright (c) 2013-2016 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
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
 * Lifetime of an objcore:
30
 *      phase 0 - nonexistent
31
 *      phase 1 - created, but no stevedore associated
32
 *      phase 2 - stevedore associated, being filled out
33
 *      phase 3 - stable, no changes happening
34
 *      phase 4 - unavailable, being dismantled
35
 *      phase 5 - stevedore disassociated
36
 *      phase 6 - nonexistent
37
 *
38
 * 0->1 ObjNew()        creates objcore
39
 *
40
 * 1->2 STV_NewObject() associates a stevedore
41
 *
42
 * 2    ObjSetState()   sets state
43
 * 2    ObjWaitState()  waits for particular state
44
 *                      INVALID->REQ_DONE->STREAM->FINISHED->FAILED
45
 *
46
 * 2    ObjGetSpace()   allocates space
47
 * 2    ObjExtend()     commits content
48
 * 2    ObjWaitExtend() waits for content - used to implement ObjIterate())
49
 *
50
 * 2    ObjSetAttr()
51
 * 2      ObjCopyAttr()
52
 * 2      ObjSetFlag()
53
 * 2      ObjSetDouble()
54
 * 2      ObjSetU32()
55
 * 2      ObjSetU64()
56
 *
57
 * 2->3 ObjBocDone()    Boc removed from OC, clean it up
58
 *
59
 * 23   ObjHasAttr()
60
 * 23   ObjGetAttr()
61
 * 23     ObjCheckFlag()
62
 * 23     ObjGetDouble()
63
 * 23     ObjGetU32()
64
 * 23     ObjGetU64()
65
 * 23     ObjGetLen()
66
 * 23     ObjGetXID()
67
 *
68
 * 23   ObjIterate()    ... over body
69
 *
70
 * 23   ObjTouch()      Signal to LRU(-like) facilities
71
 *
72
 * 3->4 HSH_Snipe()     kill if not in use
73
 * 3->4 HSH_Kill()      make unavailable
74
 *
75
 * 234  ObjSlim()       Release body storage (but retain attribute storage)
76
 *
77
 * 4->5 ObjFreeObj()    disassociates stevedore
78
 *
79
 * 5->6 FREE_OBJ()      ...in HSH_DerefObjCore()
80
 */
81
82
#include "config.h"
83
84
#include <stdlib.h>
85
86
#include "cache_varnishd.h"
87
#include "cache_obj.h"
88
#include "vend.h"
89
#include "storage/storage.h"
90
91
static const struct obj_methods *
92 6336331
obj_getmethods(const struct objcore *oc)
93
{
94
95 6336331
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
96 6336331
        CHECK_OBJ_NOTNULL(oc->stobj->stevedore, STEVEDORE_MAGIC);
97 6336331
        AN(oc->stobj->stevedore->methods);
98 6336331
        return (oc->stobj->stevedore->methods);
99
}
100
101
static struct boc *
102 124876
obj_newboc(void)
103
{
104
        struct boc *boc;
105
106 124876
        ALLOC_OBJ(boc, BOC_MAGIC);
107 124870
        AN(boc);
108 124870
        Lck_New(&boc->mtx, lck_busyobj);
109 124870
        PTOK(pthread_cond_init(&boc->cond, NULL));
110 124870
        boc->refcount = 1;
111 124870
        boc->transit_buffer = cache_param->transit_buffer;
112 124870
        return (boc);
113
}
114
115
static void
116 114543
obj_deleteboc(struct boc **p)
117
{
118
        struct boc *boc;
119
120 114543
        TAKE_OBJ_NOTNULL(boc, p, BOC_MAGIC);
121 114543
        Lck_Delete(&boc->mtx);
122 114543
        PTOK(pthread_cond_destroy(&boc->cond));
123 114543
        free(boc->vary);
124 114543
        FREE_OBJ(boc);
125 114543
}
126
127
/*====================================================================
128
 * ObjNew()
129
 *
130
 */
131
132
struct objcore *
133 124873
ObjNew(const struct worker *wrk)
134
{
135
        struct objcore *oc;
136
137 124873
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
138
139 124873
        ALLOC_OBJ(oc, OBJCORE_MAGIC);
140 124873
        AN(oc);
141 124873
        wrk->stats->n_objectcore++;
142 124873
        oc->last_lru = NAN;
143 124873
        oc->flags = OC_F_BUSY;
144
145 124873
        oc->boc = obj_newboc();
146
147 124873
        return (oc);
148
}
149
150
/*====================================================================
151
 * ObjDestroy()
152
 *
153
 */
154
155
void
156 73051
ObjDestroy(const struct worker *wrk, struct objcore **p)
157
{
158
        struct objcore *oc;
159
160 73051
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
161 73051
        TAKE_OBJ_NOTNULL(oc, p, OBJCORE_MAGIC);
162 73051
        if (oc->boc != NULL)
163 1348
                obj_deleteboc(&oc->boc);
164 73051
        FREE_OBJ(oc);
165 73051
        wrk->stats->n_objectcore--;
166 73051
}
167
168
/*====================================================================
169
 * ObjIterate()
170
 *
171
 */
172
173
int
174 93707
ObjIterate(struct worker *wrk, struct objcore *oc,
175
    void *priv, objiterate_f *func, int final)
176
{
177 93707
        const struct obj_methods *om = obj_getmethods(oc);
178
179 93707
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
180 93707
        AN(func);
181 93707
        AN(om->objiterator);
182 93707
        return (om->objiterator(wrk, oc, priv, func, final));
183
}
184
185
/*====================================================================
186
 * ObjGetSpace()
187
 *
188
 * This function returns a pointer and length of free space.  If there
189
 * is no free space, some will be added first.
190
 *
191
 * The "sz" argument is an input hint of how much space is desired.
192
 * 0 means "unknown", return some default size (maybe fetch_chunksize)
193
 */
194
195
int
196 2321343
ObjGetSpace(struct worker *wrk, struct objcore *oc, ssize_t *sz, uint8_t **ptr)
197
{
198 2321343
        const struct obj_methods *om = obj_getmethods(oc);
199
200 2321343
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
201 2321343
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
202 2321343
        AN(sz);
203 2321343
        AN(ptr);
204 2321343
        assert(*sz >= 0);
205
206 2321343
        AN(om->objgetspace);
207 2321343
        return (om->objgetspace(wrk, oc, sz, ptr));
208
}
209
210
/*====================================================================
211
 * ObjExtend()
212
 *
213
 * This function extends the used part of the object a number of bytes
214
 * into the last space returned by ObjGetSpace()
215
 *
216
 * The final flag must be set on the last call, and it will release any
217
 * surplus space allocated.
218
 */
219
220
static void
221 2263330
obj_extend_condwait(const struct objcore *oc)
222
{
223
224 2263330
        if (oc->boc->transit_buffer == 0)
225 2244101
                return;
226
227 19229
        assert(oc->flags & OC_F_TRANSIENT);
228 20783
        while (!(oc->flags & OC_F_CANCEL) && oc->boc->fetched_so_far >
229 20703
            oc->boc->delivered_so_far + oc->boc->transit_buffer)
230 1554
                (void)Lck_CondWait(&oc->boc->cond, &oc->boc->mtx);
231 2263330
}
232
233
void
234 2290785
ObjExtend(struct worker *wrk, struct objcore *oc, ssize_t l, int final)
235
{
236 2290785
        const struct obj_methods *om = obj_getmethods(oc);
237
238 2290785
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
239 2290785
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
240 2290785
        AN(om->objextend);
241 2290785
        assert(l >= 0);
242
243 2290785
        Lck_Lock(&oc->boc->mtx);
244 2290785
        if (l > 0) {
245 2263333
                obj_extend_condwait(oc);
246 2263333
                om->objextend(wrk, oc, l);
247 2263333
                oc->boc->fetched_so_far += l;
248 2263333
                PTOK(pthread_cond_broadcast(&oc->boc->cond));
249 2263333
        }
250 2290785
        Lck_Unlock(&oc->boc->mtx);
251
252 2290785
        assert(oc->boc->state < BOS_FINISHED);
253 2290785
        if (final && om->objtrimstore != NULL)
254 74120
                om->objtrimstore(wrk, oc);
255 2290785
}
256
257
/*====================================================================
258
 */
259
260
uint64_t
261 86193
ObjWaitExtend(const struct worker *wrk, const struct objcore *oc, uint64_t l,
262
    enum boc_state_e *statep)
263
{
264
        enum boc_state_e state;
265
        uint64_t rv;
266
267 86193
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
268 86193
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
269 86193
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
270 86193
        Lck_Lock(&oc->boc->mtx);
271 126587
        while (1) {
272 126587
                rv = oc->boc->fetched_so_far;
273 126587
                assert(l <= rv || oc->boc->state == BOS_FAILED);
274 126587
                if (oc->boc->transit_buffer > 0) {
275 24700
                        assert(oc->flags & OC_F_TRANSIENT);
276
                        /* Signal the new client position */
277 24700
                        oc->boc->delivered_so_far = l;
278 24700
                        PTOK(pthread_cond_signal(&oc->boc->cond));
279 24700
                }
280 126587
                state = oc->boc->state;
281 126587
                if (rv > l || state >= BOS_FINISHED)
282 86193
                        break;
283 40394
                (void)Lck_CondWait(&oc->boc->cond, &oc->boc->mtx);
284
        }
285 86193
        Lck_Unlock(&oc->boc->mtx);
286 86193
        if (statep != NULL)
287 86191
                *statep = state;
288 86205
        return (rv);
289
}
290
/*====================================================================
291
 */
292
293
void
294 293827
ObjSetState(struct worker *wrk, const struct objcore *oc,
295
    enum boc_state_e next)
296
{
297
        const struct obj_methods *om;
298
299 293827
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
300 293827
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
301 293827
        assert(next > oc->boc->state);
302
303 293827
        CHECK_OBJ_ORNULL(oc->stobj->stevedore, STEVEDORE_MAGIC);
304 293827
        assert(next != BOS_STREAM || oc->boc->state == BOS_PREP_STREAM);
305 293827
        assert(next != BOS_FINISHED || (oc->oa_present & (1 << OA_LEN)));
306
307 293827
        if (oc->stobj->stevedore != NULL) {
308 204590
                om = oc->stobj->stevedore->methods;
309 204590
                if (om->objsetstate != NULL)
310 0
                        om->objsetstate(wrk, oc, next);
311 204590
        }
312
313 293827
        Lck_Lock(&oc->boc->mtx);
314 293827
        oc->boc->state = next;
315 293827
        PTOK(pthread_cond_broadcast(&oc->boc->cond));
316 293827
        Lck_Unlock(&oc->boc->mtx);
317 293827
}
318
319
/*====================================================================
320
 */
321
322
void
323 102467
ObjWaitState(const struct objcore *oc, enum boc_state_e want)
324
{
325
326 102467
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
327 102467
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
328
329 102467
        Lck_Lock(&oc->boc->mtx);
330
        /* wake up obj_extend_condwait() */
331 102467
        if (oc->flags & OC_F_CANCEL)
332 13958
                PTOK(pthread_cond_signal(&oc->boc->cond));
333 1321214
        while (1) {
334 1321214
                if (oc->boc->state >= want)
335 102467
                        break;
336 1218747
                (void)Lck_CondWait(&oc->boc->cond, &oc->boc->mtx);
337
        }
338 102467
        Lck_Unlock(&oc->boc->mtx);
339 102467
}
340
341
/*====================================================================
342
 * ObjGetlen()
343
 *
344
 * This is a separate function because it may need locking
345
 */
346
347
uint64_t
348 207666
ObjGetLen(struct worker *wrk, struct objcore *oc)
349
{
350
        uint64_t len;
351
352 207666
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
353
354 207666
        AZ(ObjGetU64(wrk, oc, OA_LEN, &len));
355 207666
        return (len);
356
}
357
358
/*====================================================================
359
 * ObjSlim()
360
 *
361
 * Free the whatever storage can be freed, without freeing the actual
362
 * object yet.
363
 */
364
365
void
366 55199
ObjSlim(struct worker *wrk, struct objcore *oc)
367
{
368 55199
        const struct obj_methods *om = obj_getmethods(oc);
369
370 55199
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
371
372 55199
        if (om->objslim != NULL)
373 55199
                om->objslim(wrk, oc);
374 55199
}
375
376
/*====================================================================
377
 * Called when the boc used to populate the objcore is going away.
378
 * Useful for releasing any leftovers from Trim.
379
 */
380
381
void
382 113199
ObjBocDone(struct worker *wrk, struct objcore *oc, struct boc **boc)
383
{
384
        const struct obj_methods *m;
385
386 113199
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
387 113199
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
388 113199
        AN(boc);
389 113199
        CHECK_OBJ_NOTNULL(*boc, BOC_MAGIC);
390 113199
        CHECK_OBJ_ORNULL(oc->stobj->stevedore, STEVEDORE_MAGIC);
391 113199
        if (oc->stobj->stevedore != NULL) {
392 111081
                m = obj_getmethods(oc);
393 111081
                if (m->objbocdone != NULL)
394 111077
                        m->objbocdone(wrk, oc, *boc);
395 111081
        }
396 113197
        obj_deleteboc(boc);
397 113197
}
398
399
/*====================================================================
400
 */
401
void
402 70423
ObjFreeObj(struct worker *wrk, struct objcore *oc)
403
{
404 70423
        const struct obj_methods *m = obj_getmethods(oc);
405
406 70423
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
407
408 70423
        AN(m->objfree);
409 70423
        m->objfree(wrk, oc);
410 70423
        AZ(oc->stobj->stevedore);
411 70423
}
412
413
/*====================================================================
414
 * ObjHasAttr()
415
 *
416
 * Check if object has this attribute
417
 */
418
419
int
420 300584
ObjHasAttr(struct worker *wrk, struct objcore *oc, enum obj_attr attr)
421
{
422
423 300584
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
424 300584
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
425
426 300584
        if (oc->oa_present)
427 299864
                return (oc->oa_present & (1 << attr));
428
429
        /* resurrected persistent objects don't have oa_present set */
430 720
        return (ObjGetAttr(wrk, oc, attr, NULL) != NULL ? 1 : 0);
431 300584
}
432
433
/*====================================================================
434
 * ObjGetAttr()
435
 *
436
 * Get an attribute of the object.
437
 *
438
 * Returns NULL on unset or zero length attributes and len set to
439
 * zero. Returns Non-NULL otherwise and len is updated with the attributes
440
 * length.
441
 */
442
443
const void *
444 855497
ObjGetAttr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
445
   ssize_t *len)
446
{
447 855497
        const struct obj_methods *om = obj_getmethods(oc);
448
449 855497
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
450
451 855497
        AN(om->objgetattr);
452 855497
        return (om->objgetattr(wrk, oc, attr, len));
453
}
454
455
/*====================================================================
456
 * ObjSetAttr()
457
 *
458
 * Setting fixed size attributes always succeeds.
459
 *
460
 * Setting a variable size attribute asserts if the combined size of the
461
 * variable attributes exceeds the total variable attribute space set at
462
 * object creation. If there is space it always succeeds.
463
 *
464
 * Setting an auxiliary attribute can fail.
465
 *
466
 * Resetting any variable asserts if the new length does not match the
467
 * previous length exactly.
468
 *
469
 * If ptr is Non-NULL, it points to the new content which is copied into
470
 * the attribute.  Otherwise the caller will have to do the copying.
471
 *
472
 * Return value is non-NULL on success and NULL on failure. If ptr was
473
 * non-NULL, it is an error to use the returned pointer to set the
474
 * attribute data, it is only a success indicator in that case.
475
 */
476
477
void *
478 414475
ObjSetAttr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
479
    ssize_t len, const void *ptr)
480
{
481 414475
        const struct obj_methods *om = obj_getmethods(oc);
482
        void *r;
483
484 414475
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
485 414475
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
486
487 414475
        AN(om->objsetattr);
488 414475
        assert((int)attr < 16);
489 414475
        r = om->objsetattr(wrk, oc, attr, len, ptr);
490 414475
        if (r)
491 414471
                oc->oa_present |= (1 << attr);
492 414507
        return (r);
493
}
494
495
/*====================================================================
496
 * ObjTouch()
497
 */
498
499
void
500 124496
ObjTouch(struct worker *wrk, struct objcore *oc, vtim_real now)
501
{
502 124496
        const struct obj_methods *om = obj_getmethods(oc);
503
504 124496
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
505 124496
        if (om->objtouch != NULL)
506 124497
                om->objtouch(wrk, oc, now);
507 124502
}
508
509
/*====================================================================
510
 * Utility functions which work on top of the previous ones
511
 */
512
513
int
514 1960
ObjCopyAttr(struct worker *wrk, struct objcore *oc, struct objcore *ocs,
515
    enum obj_attr attr)
516
{
517
        const void *vps;
518
        void *vpd;
519
        ssize_t l;
520
521 1960
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
522 1960
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
523 1960
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
524 1960
        CHECK_OBJ_NOTNULL(ocs, OBJCORE_MAGIC);
525
526 1960
        vps = ObjGetAttr(wrk, ocs, attr, &l);
527
        // XXX: later we want to have zero-length OA's too
528 1960
        if (vps == NULL || l <= 0)
529 0
                return (-1);
530 1960
        vpd = ObjSetAttr(wrk, oc, attr, l, vps);
531 1960
        if (vpd == NULL)
532 0
                return (-1);
533 1960
        return (0);
534 1960
}
535
536
int
537 86715
ObjSetXID(struct worker *wrk, struct objcore *oc, vxid_t xid)
538
{
539
        uint64_t u;
540
541 86715
        u = VXID(xid);
542 86715
        AZ(ObjSetU64(wrk, oc, OA_VXID, u));
543 86715
        return (0);
544
}
545
546
547
vxid_t
548 107747
ObjGetXID(struct worker *wrk, struct objcore *oc)
549
{
550
        vxid_t u;
551
552 107747
        AZ(ObjGetU64(wrk, oc, OA_VXID, &u.vxid));
553 107747
        return (u);
554
}
555
556
/*--------------------------------------------------------------------
557
 * There is no well-defined byteorder for IEEE-754 double and the
558
 * correct solution (frexp(3) and manual encoding) is more work
559
 * than our (weak) goal of being endian-agnostic requires at this point.
560
 * We give it a shot by memcpy'ing doubles over a uint64_t and then
561
 * BE encode that.
562
 */
563
564
int
565 86718
ObjSetDouble(struct worker *wrk, struct objcore *oc, enum obj_attr a, double t)
566
{
567
        void *vp;
568
        uint64_t u;
569
570 86718
        assert(sizeof t == sizeof u);
571 86718
        memcpy(&u, &t, sizeof u);
572 86718
        vp = ObjSetAttr(wrk, oc, a, sizeof u, NULL);
573 86718
        if (vp == NULL)
574 0
                return (-1);
575 86718
        vbe64enc(vp, u);
576 86718
        return (0);
577 86718
}
578
579
int
580 80
ObjGetDouble(struct worker *wrk, struct objcore *oc, enum obj_attr a, double *d)
581
{
582
        const void *vp;
583
        uint64_t u;
584
        ssize_t l;
585
586 80
        assert(sizeof *d == sizeof u);
587 80
        vp = ObjGetAttr(wrk, oc, a, &l);
588 80
        if (vp == NULL)
589 0
                return (-1);
590 80
        if (d != NULL) {
591 80
                assert(l == sizeof u);
592 80
                u = vbe64dec(vp);
593 80
                memcpy(d, &u, sizeof *d);
594 80
        }
595 80
        return (0);
596 80
}
597
598
/*--------------------------------------------------------------------
599
 */
600
601
int
602 193431
ObjSetU64(struct worker *wrk, struct objcore *oc, enum obj_attr a, uint64_t t)
603
{
604
        void *vp;
605
606 193431
        vp = ObjSetAttr(wrk, oc, a, sizeof t, NULL);
607 193431
        if (vp == NULL)
608 0
                return (-1);
609 193431
        vbe64enc(vp, t);
610 193431
        return (0);
611 193431
}
612
613
int
614 315537
ObjGetU64(struct worker *wrk, struct objcore *oc, enum obj_attr a, uint64_t *d)
615
{
616
        const void *vp;
617
        ssize_t l;
618
619 315537
        vp = ObjGetAttr(wrk, oc, a, &l);
620 315537
        if (vp == NULL || l != sizeof *d)
621 34
                return (-1);
622 315533
        if (d != NULL)
623 315513
                *d = vbe64dec(vp);
624 315533
        return (0);
625 315523
}
626
627
/*--------------------------------------------------------------------
628
 */
629
630
int
631 279268
ObjCheckFlag(struct worker *wrk, struct objcore *oc, enum obj_flags of)
632
{
633
        const uint8_t *fp;
634
635 279268
        fp = ObjGetAttr(wrk, oc, OA_FLAGS, NULL);
636 279268
        AN(fp);
637 279268
        return ((*fp) & of);
638
}
639
640
void
641 19595
ObjSetFlag(struct worker *wrk, struct objcore *oc, enum obj_flags of, int val)
642
{
643
        uint8_t *fp;
644
645 19595
        fp = ObjSetAttr(wrk, oc, OA_FLAGS, 1, NULL);
646 19595
        AN(fp);
647 19595
        if (val)
648 19515
                (*fp) |= of;
649
        else
650 80
                (*fp) &= ~of;
651 19595
}
652
653
/*====================================================================
654
 * Object event subscription mechanism.
655
 *
656
 * XXX: it is extremely unclear what the locking circumstances are here.
657
 */
658
659
struct oev_entry {
660
        unsigned                        magic;
661
#define OEV_MAGIC                       0xb0b7c5a1
662
        unsigned                        mask;
663
        obj_event_f                     *func;
664
        void                            *priv;
665
        VTAILQ_ENTRY(oev_entry)         list;
666
};
667
668
static VTAILQ_HEAD(,oev_entry)          oev_list;
669
static pthread_rwlock_t                 oev_rwl;
670
static unsigned                         oev_mask;
671
672
/*
673
 * NB: ObjSubscribeEvents() is not atomic:
674
 * oev_mask is checked optimistically in ObjSendEvent()
675
 */
676
uintptr_t
677 1560
ObjSubscribeEvents(obj_event_f *func, void *priv, unsigned mask)
678
{
679
        struct oev_entry *oev;
680
681 1560
        AN(func);
682 1560
        AZ(mask & ~OEV_MASK);
683
684 1560
        ALLOC_OBJ(oev, OEV_MAGIC);
685 1560
        AN(oev);
686 1560
        oev->func = func;
687 1560
        oev->priv = priv;
688 1560
        oev->mask = mask;
689 1560
        PTOK(pthread_rwlock_wrlock(&oev_rwl));
690 1560
        VTAILQ_INSERT_TAIL(&oev_list, oev, list);
691 1560
        oev_mask |= mask;
692 1560
        PTOK(pthread_rwlock_unlock(&oev_rwl));
693 1560
        return ((uintptr_t)oev);
694
}
695
696
void
697 40
ObjUnsubscribeEvents(uintptr_t *handle)
698
{
699 40
        struct oev_entry *oev, *oev2 = NULL;
700 40
        unsigned newmask = 0;
701
702 40
        AN(handle);
703 40
        AN(*handle);
704 40
        PTOK(pthread_rwlock_wrlock(&oev_rwl));
705 80
        VTAILQ_FOREACH(oev, &oev_list, list) {
706 40
                CHECK_OBJ_NOTNULL(oev, OEV_MAGIC);
707 40
                if ((uintptr_t)oev == *handle)
708 40
                        oev2 = oev;
709
                else
710 0
                        newmask |= oev->mask;
711 40
        }
712 40
        AN(oev2);
713 40
        VTAILQ_REMOVE(&oev_list, oev2, list);
714 40
        oev_mask = newmask;
715 40
        AZ(newmask & ~OEV_MASK);
716 40
        PTOK(pthread_rwlock_unlock(&oev_rwl));
717 40
        FREE_OBJ(oev2);
718 40
        *handle = 0;
719 40
}
720
721
void
722 127983
ObjSendEvent(struct worker *wrk, struct objcore *oc, unsigned event)
723
{
724
        struct oev_entry *oev;
725
726 127983
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
727 127983
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
728 127983
        AN(event & OEV_MASK);
729 127983
        AZ(event & ~OEV_MASK);
730 127983
        if (!(event & oev_mask))
731 124421
                return;
732
733 3562
        PTOK(pthread_rwlock_rdlock(&oev_rwl));
734 7761
        VTAILQ_FOREACH(oev, &oev_list, list) {
735 4201
                CHECK_OBJ_NOTNULL(oev, OEV_MAGIC);
736 4201
                if (event & oev->mask)
737 4199
                        oev->func(wrk, oev->priv, oc, event);
738 4201
        }
739 3560
        PTOK(pthread_rwlock_unlock(&oev_rwl));
740
741 127981
}
742
743
void
744 36630
ObjInit(void)
745
{
746 36630
        VTAILQ_INIT(&oev_list);
747 36630
        PTOK(pthread_rwlock_init(&oev_rwl, NULL));
748 36630
}