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 6340215
obj_getmethods(const struct objcore *oc)
93
{
94
95 6340215
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
96 6340215
        CHECK_OBJ_NOTNULL(oc->stobj->stevedore, STEVEDORE_MAGIC);
97 6340215
        AN(oc->stobj->stevedore->methods);
98 6340215
        return (oc->stobj->stevedore->methods);
99
}
100
101
static struct boc *
102 125084
obj_newboc(void)
103
{
104
        struct boc *boc;
105
106 125084
        ALLOC_OBJ(boc, BOC_MAGIC);
107 125082
        AN(boc);
108 125082
        Lck_New(&boc->mtx, lck_busyobj);
109 125082
        PTOK(pthread_cond_init(&boc->cond, NULL));
110 125082
        boc->refcount = 1;
111 125082
        boc->transit_buffer = cache_param->transit_buffer;
112 125082
        return (boc);
113
}
114
115
static void
116 114569
obj_deleteboc(struct boc **p)
117
{
118
        struct boc *boc;
119
120 114569
        TAKE_OBJ_NOTNULL(boc, p, BOC_MAGIC);
121 114569
        Lck_Delete(&boc->mtx);
122 114569
        PTOK(pthread_cond_destroy(&boc->cond));
123 114569
        free(boc->vary);
124 114569
        FREE_OBJ(boc);
125 114569
}
126
127
/*====================================================================
128
 * ObjNew()
129
 *
130
 */
131
132
struct objcore *
133 125083
ObjNew(const struct worker *wrk)
134
{
135
        struct objcore *oc;
136
137 125083
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
138
139 125083
        ALLOC_OBJ(oc, OBJCORE_MAGIC);
140 125083
        AN(oc);
141 125083
        wrk->stats->n_objectcore++;
142 125083
        oc->last_lru = NAN;
143 125083
        oc->flags = OC_F_BUSY;
144
145 125083
        oc->boc = obj_newboc();
146
147 125083
        return (oc);
148
}
149
150
/*====================================================================
151
 * ObjDestroy()
152
 *
153
 */
154
155
void
156 73037
ObjDestroy(const struct worker *wrk, struct objcore **p)
157
{
158
        struct objcore *oc;
159
160 73037
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
161 73037
        TAKE_OBJ_NOTNULL(oc, p, OBJCORE_MAGIC);
162 73037
        if (oc->boc != NULL)
163 1336
                obj_deleteboc(&oc->boc);
164 73037
        FREE_OBJ(oc);
165 73037
        wrk->stats->n_objectcore--;
166 73037
}
167
168
/*====================================================================
169
 * ObjIterate()
170
 *
171
 */
172
173
int
174 94981
ObjIterate(struct worker *wrk, struct objcore *oc,
175
    void *priv, objiterate_f *func, int final)
176
{
177 94981
        const struct obj_methods *om = obj_getmethods(oc);
178
179 94981
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
180 94981
        AN(func);
181 94981
        AN(om->objiterator);
182 94981
        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 2318366
ObjGetSpace(struct worker *wrk, struct objcore *oc, ssize_t *sz, uint8_t **ptr)
197
{
198 2318366
        const struct obj_methods *om = obj_getmethods(oc);
199
200 2318366
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
201 2318366
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
202 2318366
        AN(sz);
203 2318366
        AN(ptr);
204 2318366
        assert(*sz >= 0);
205
206 2318366
        AN(om->objgetspace);
207 2318366
        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 2260345
obj_extend_condwait(const struct objcore *oc)
222
{
223
224 2260345
        if (oc->boc->transit_buffer == 0)
225 2241097
                return;
226
227 19248
        assert(oc->flags & OC_F_TRANSIENT);
228 20802
        while (!(oc->flags & OC_F_CANCEL) && oc->boc->fetched_so_far >
229 20722
            oc->boc->delivered_so_far + oc->boc->transit_buffer)
230 1554
                (void)Lck_CondWait(&oc->boc->cond, &oc->boc->mtx);
231 2260345
}
232
233
void
234 2287804
ObjExtend(struct worker *wrk, struct objcore *oc, ssize_t l, int final)
235
{
236 2287804
        const struct obj_methods *om = obj_getmethods(oc);
237
238 2287804
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
239 2287804
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
240 2287804
        AN(om->objextend);
241 2287804
        assert(l >= 0);
242
243 2287804
        Lck_Lock(&oc->boc->mtx);
244 2287804
        if (l > 0) {
245 2260349
                obj_extend_condwait(oc);
246 2260349
                om->objextend(wrk, oc, l);
247 2260349
                oc->boc->fetched_so_far += l;
248 2260349
                PTOK(pthread_cond_broadcast(&oc->boc->cond));
249 2260349
        }
250 2287804
        Lck_Unlock(&oc->boc->mtx);
251
252 2287804
        assert(oc->boc->state < BOS_FINISHED);
253 2287804
        if (final && om->objtrimstore != NULL)
254 74160
                om->objtrimstore(wrk, oc);
255 2287804
}
256
257
/*====================================================================
258
 */
259
260
uint64_t
261 86532
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 86532
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
268 86532
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
269 86532
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
270 86532
        Lck_Lock(&oc->boc->mtx);
271 127375
        while (1) {
272 127375
                rv = oc->boc->fetched_so_far;
273 127375
                assert(l <= rv || oc->boc->state == BOS_FAILED);
274 127375
                if (oc->boc->transit_buffer > 0) {
275 24972
                        assert(oc->flags & OC_F_TRANSIENT);
276
                        /* Signal the new client position */
277 24972
                        oc->boc->delivered_so_far = l;
278 24972
                        PTOK(pthread_cond_signal(&oc->boc->cond));
279 24972
                }
280 127375
                state = oc->boc->state;
281 127375
                if (rv > l || state >= BOS_FINISHED)
282 86532
                        break;
283 40843
                (void)Lck_CondWait(&oc->boc->cond, &oc->boc->mtx);
284
        }
285 86532
        Lck_Unlock(&oc->boc->mtx);
286 86532
        if (statep != NULL)
287 86530
                *statep = state;
288 86548
        return (rv);
289
}
290
/*====================================================================
291
 */
292
293
void
294 293984
ObjSetState(struct worker *wrk, const struct objcore *oc,
295
    enum boc_state_e next)
296
{
297
        const struct obj_methods *om;
298
299 293984
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
300 293984
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
301 293984
        assert(next > oc->boc->state);
302
303 293984
        CHECK_OBJ_ORNULL(oc->stobj->stevedore, STEVEDORE_MAGIC);
304 293984
        assert(next != BOS_STREAM || oc->boc->state == BOS_PREP_STREAM);
305 293984
        assert(next != BOS_FINISHED || (oc->oa_present & (1 << OA_LEN)));
306
307 293984
        if (oc->stobj->stevedore != NULL) {
308 204708
                om = oc->stobj->stevedore->methods;
309 204708
                if (om->objsetstate != NULL)
310 0
                        om->objsetstate(wrk, oc, next);
311 204708
        }
312
313 293984
        Lck_Lock(&oc->boc->mtx);
314 293984
        oc->boc->state = next;
315 293984
        PTOK(pthread_cond_broadcast(&oc->boc->cond));
316 293984
        Lck_Unlock(&oc->boc->mtx);
317 293984
}
318
319
/*====================================================================
320
 */
321
322
void
323 102503
ObjWaitState(const struct objcore *oc, enum boc_state_e want)
324
{
325
326 102503
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
327 102503
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
328
329 102503
        Lck_Lock(&oc->boc->mtx);
330
        /* wake up obj_extend_condwait() */
331 102503
        if (oc->flags & OC_F_CANCEL)
332 13957
                PTOK(pthread_cond_signal(&oc->boc->cond));
333 1328418
        while (1) {
334 1328418
                if (oc->boc->state >= want)
335 102503
                        break;
336 1225915
                (void)Lck_CondWait(&oc->boc->cond, &oc->boc->mtx);
337
        }
338 102503
        Lck_Unlock(&oc->boc->mtx);
339 102503
}
340
341
/*====================================================================
342
 * ObjGetlen()
343
 *
344
 * This is a separate function because it may need locking
345
 */
346
347
uint64_t
348 208940
ObjGetLen(struct worker *wrk, struct objcore *oc)
349
{
350
        uint64_t len;
351
352 208940
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
353
354 208940
        AZ(ObjGetU64(wrk, oc, OA_LEN, &len));
355 208940
        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 55198
ObjSlim(struct worker *wrk, struct objcore *oc)
367
{
368 55198
        const struct obj_methods *om = obj_getmethods(oc);
369
370 55198
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
371
372 55198
        if (om->objslim != NULL)
373 55198
                om->objslim(wrk, oc);
374 55198
}
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 113239
ObjBocDone(struct worker *wrk, struct objcore *oc, struct boc **boc)
383
{
384
        const struct obj_methods *m;
385
386 113239
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
387 113239
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
388 113239
        AN(boc);
389 113239
        CHECK_OBJ_NOTNULL(*boc, BOC_MAGIC);
390 113239
        CHECK_OBJ_ORNULL(oc->stobj->stevedore, STEVEDORE_MAGIC);
391 113239
        if (oc->stobj->stevedore != NULL) {
392 111121
                m = obj_getmethods(oc);
393 111121
                if (m->objbocdone != NULL)
394 111118
                        m->objbocdone(wrk, oc, *boc);
395 111121
        }
396 113237
        obj_deleteboc(boc);
397 113237
}
398
399
/*====================================================================
400
 */
401
void
402 70422
ObjFreeObj(struct worker *wrk, struct objcore *oc)
403
{
404 70422
        const struct obj_methods *m = obj_getmethods(oc);
405
406 70422
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
407
408 70422
        AN(m->objfree);
409 70422
        m->objfree(wrk, oc);
410 70422
        AZ(oc->stobj->stevedore);
411 70422
}
412
413
/*====================================================================
414
 * ObjHasAttr()
415
 *
416
 * Check if object has this attribute
417
 */
418
419
int
420 302502
ObjHasAttr(struct worker *wrk, struct objcore *oc, enum obj_attr attr)
421
{
422
423 302502
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
424 302502
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
425
426 302502
        if (oc->oa_present)
427 301782
                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 302502
}
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 862430
ObjGetAttr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
445
   ssize_t *len)
446
{
447 862430
        const struct obj_methods *om = obj_getmethods(oc);
448
449 862430
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
450
451 862430
        AN(om->objgetattr);
452 862430
        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 414663
ObjSetAttr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
479
    ssize_t len, const void *ptr)
480
{
481 414663
        const struct obj_methods *om = obj_getmethods(oc);
482
        void *r;
483
484 414663
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
485 414663
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
486
487 414663
        AN(om->objsetattr);
488 414663
        assert((int)attr < 16);
489 414663
        r = om->objsetattr(wrk, oc, attr, len, ptr);
490 414663
        if (r)
491 414620
                oc->oa_present |= (1 << attr);
492 414667
        return (r);
493
}
494
495
/*====================================================================
496
 * ObjTouch()
497
 */
498
499
void
500 125788
ObjTouch(struct worker *wrk, struct objcore *oc, vtim_real now)
501
{
502 125788
        const struct obj_methods *om = obj_getmethods(oc);
503
504 125788
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
505 125788
        if (om->objtouch != NULL)
506 125785
                om->objtouch(wrk, oc, now);
507 125790
}
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 86754
ObjSetXID(struct worker *wrk, struct objcore *oc, vxid_t xid)
538
{
539
        uint64_t u;
540
541 86754
        u = VXID(xid);
542 86754
        AZ(ObjSetU64(wrk, oc, OA_VXID, u));
543 86754
        return (0);
544
}
545
546
547
vxid_t
548 110240
ObjGetXID(struct worker *wrk, struct objcore *oc)
549
{
550
        vxid_t u;
551
552 110240
        AZ(ObjGetU64(wrk, oc, OA_VXID, &u.vxid));
553 110240
        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 86758
ObjSetDouble(struct worker *wrk, struct objcore *oc, enum obj_attr a, double t)
566
{
567
        void *vp;
568
        uint64_t u;
569
570 86758
        assert(sizeof t == sizeof u);
571 86758
        memcpy(&u, &t, sizeof u);
572 86758
        vp = ObjSetAttr(wrk, oc, a, sizeof u, NULL);
573 86758
        if (vp == NULL)
574 0
                return (-1);
575 86758
        vbe64enc(vp, u);
576 86758
        return (0);
577 86758
}
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 193511
ObjSetU64(struct worker *wrk, struct objcore *oc, enum obj_attr a, uint64_t t)
603
{
604
        void *vp;
605
606 193511
        vp = ObjSetAttr(wrk, oc, a, sizeof t, NULL);
607 193511
        if (vp == NULL)
608 0
                return (-1);
609 193511
        vbe64enc(vp, t);
610 193511
        return (0);
611 193511
}
612
613
int
614 319300
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 319300
        vp = ObjGetAttr(wrk, oc, a, &l);
620 319300
        if (vp == NULL || l != sizeof *d)
621 28
                return (-1);
622 319300
        if (d != NULL)
623 319286
                *d = vbe64dec(vp);
624 319300
        return (0);
625 319284
}
626
627
/*--------------------------------------------------------------------
628
 */
629
630
int
631 281201
ObjCheckFlag(struct worker *wrk, struct objcore *oc, enum obj_flags of)
632
{
633
        const uint8_t *fp;
634
635 281201
        fp = ObjGetAttr(wrk, oc, OA_FLAGS, NULL);
636 281201
        AN(fp);
637 281201
        return ((*fp) & of);
638
}
639
640
void
641 19594
ObjSetFlag(struct worker *wrk, struct objcore *oc, enum obj_flags of, int val)
642
{
643
        uint8_t *fp;
644
645 19594
        fp = ObjSetAttr(wrk, oc, OA_FLAGS, 1, NULL);
646 19594
        AN(fp);
647 19594
        if (val)
648 19514
                (*fp) |= of;
649
        else
650 80
                (*fp) &= ~of;
651 19594
}
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 128062
ObjSendEvent(struct worker *wrk, struct objcore *oc, unsigned event)
723
{
724
        struct oev_entry *oev;
725
726 128062
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
727 128062
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
728 128062
        AN(event & OEV_MASK);
729 128062
        AZ(event & ~OEV_MASK);
730 128062
        if (!(event & oev_mask))
731 124502
                return;
732
733 3560
        PTOK(pthread_rwlock_rdlock(&oev_rwl));
734 7760
        VTAILQ_FOREACH(oev, &oev_list, list) {
735 4200
                CHECK_OBJ_NOTNULL(oev, OEV_MAGIC);
736 4200
                if (event & oev->mask)
737 4200
                        oev->func(wrk, oev->priv, oc, event);
738 4200
        }
739 3560
        PTOK(pthread_rwlock_unlock(&oev_rwl));
740
741 128062
}
742
743
void
744 36676
ObjInit(void)
745
{
746 36676
        VTAILQ_INIT(&oev_list);
747 36676
        PTOK(pthread_rwlock_init(&oev_rwl, NULL));
748 36676
}