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 3918155
obj_getmethods(const struct objcore *oc)
93
{
94
95 3918155
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
96 3918155
        CHECK_OBJ_NOTNULL(oc->stobj->stevedore, STEVEDORE_MAGIC);
97 3918155
        AN(oc->stobj->stevedore->methods);
98 3918155
        return (oc->stobj->stevedore->methods);
99
}
100
101
static struct boc *
102 74323
obj_newboc(void)
103
{
104
        struct boc *boc;
105
106 74323
        ALLOC_OBJ(boc, BOC_MAGIC);
107 74323
        AN(boc);
108 74323
        Lck_New(&boc->mtx, lck_busyobj);
109 74323
        PTOK(pthread_cond_init(&boc->cond, NULL));
110 74323
        boc->refcount = 1;
111 74323
        boc->transit_buffer = cache_param->transit_buffer;
112 74323
        return (boc);
113
}
114
115
static void
116 67896
obj_deleteboc(struct boc **p)
117
{
118
        struct boc *boc;
119
120 67896
        TAKE_OBJ_NOTNULL(boc, p, BOC_MAGIC);
121 67896
        Lck_Delete(&boc->mtx);
122 67896
        PTOK(pthread_cond_destroy(&boc->cond));
123 67896
        free(boc->vary);
124 67896
        FREE_OBJ(boc);
125 67896
}
126
127
/*====================================================================
128
 * ObjNew()
129
 *
130
 */
131
132
struct objcore *
133 74321
ObjNew(const struct worker *wrk)
134
{
135
        struct objcore *oc;
136
137 74321
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
138
139 74321
        ALLOC_OBJ(oc, OBJCORE_MAGIC);
140 74321
        AN(oc);
141 74321
        wrk->stats->n_objectcore++;
142 74321
        oc->last_lru = NAN;
143 74321
        oc->flags = OC_F_BUSY;
144
145 74321
        oc->boc = obj_newboc();
146
147 74321
        return (oc);
148
}
149
150
/*====================================================================
151
 * ObjDestroy()
152
 *
153
 */
154
155
void
156 42311
ObjDestroy(const struct worker *wrk, struct objcore **p)
157
{
158
        struct objcore *oc;
159
160 42311
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
161 42311
        TAKE_OBJ_NOTNULL(oc, p, OBJCORE_MAGIC);
162 42311
        if (oc->boc != NULL)
163 672
                obj_deleteboc(&oc->boc);
164 42311
        FREE_OBJ(oc);
165 42311
        wrk->stats->n_objectcore--;
166 42311
}
167
168
/*====================================================================
169
 * ObjIterate()
170
 *
171
 */
172
173
int
174 55720
ObjIterate(struct worker *wrk, struct objcore *oc,
175
    void *priv, objiterate_f *func, int final)
176
{
177 55720
        const struct obj_methods *om = obj_getmethods(oc);
178
179 55720
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
180 55720
        AN(func);
181 55720
        AN(om->objiterator);
182 55720
        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 1446994
ObjGetSpace(struct worker *wrk, struct objcore *oc, ssize_t *sz, uint8_t **ptr)
197
{
198 1446994
        const struct obj_methods *om = obj_getmethods(oc);
199
200 1446994
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
201 1446994
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
202 1446994
        AN(sz);
203 1446994
        AN(ptr);
204 1446994
        assert(*sz >= 0);
205
206 1446994
        AN(om->objgetspace);
207 1446994
        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 1410818
obj_extend_condwait(const struct objcore *oc)
222
{
223
224 1410818
        if (oc->boc->transit_buffer == 0)
225 1398708
                return;
226
227 12110
        assert(oc->flags & (OC_F_PRIVATE | OC_F_HFM | OC_F_HFP));
228
        /* NB: strictly signaling progress both ways would be prone to
229
         * deadlocks, so instead we wait for signals from the client side
230
         * when delivered_so_far so far is updated, but in case the fetch
231
         * thread was not waiting at the time of the signal, we will see
232
         * updates to delivered_so_far after timing out.
233
         */
234 13073
        while (!(oc->flags & OC_F_CANCEL) && oc->boc->fetched_so_far >
235 13023
            oc->boc->delivered_so_far + oc->boc->transit_buffer)
236 963
                (void)Lck_CondWait(&oc->boc->cond, &oc->boc->mtx);
237 1410818
}
238
239
void
240 1428108
ObjExtend(struct worker *wrk, struct objcore *oc, ssize_t l, int final)
241
{
242 1428108
        const struct obj_methods *om = obj_getmethods(oc);
243
244 1428108
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
245 1428108
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
246 1428108
        AN(om->objextend);
247 1428108
        assert(l >= 0);
248
249 1428108
        Lck_Lock(&oc->boc->mtx);
250 1428108
        if (l > 0) {
251 1410823
                obj_extend_condwait(oc);
252 1410823
                om->objextend(wrk, oc, l);
253 1410823
                oc->boc->fetched_so_far += l;
254 1410823
                PTOK(pthread_cond_broadcast(&oc->boc->cond));
255 1410823
        }
256 1428108
        Lck_Unlock(&oc->boc->mtx);
257
258 1428108
        assert(oc->boc == NULL || oc->boc->state < BOS_FINISHED);
259 1428106
        if (final && om->objtrimstore != NULL)
260 43523
                om->objtrimstore(wrk, oc);
261 1428106
}
262
263
/*====================================================================
264
 */
265
266
uint64_t
267 53869
ObjWaitExtend(const struct worker *wrk, const struct objcore *oc, uint64_t l)
268
{
269
        uint64_t rv;
270
271 53869
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
272 53869
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
273 53869
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
274 53869
        Lck_Lock(&oc->boc->mtx);
275 79340
        while (1) {
276 79340
                rv = oc->boc->fetched_so_far;
277 79340
                assert(l <= rv || oc->boc->state == BOS_FAILED);
278 79340
                if (oc->boc->transit_buffer > 0) {
279 15883
                        assert(oc->flags & (OC_F_PRIVATE | OC_F_HFM | OC_F_HFP));
280
                        /* Signal the new client position */
281 15883
                        oc->boc->delivered_so_far = l;
282 15883
                        PTOK(pthread_cond_signal(&oc->boc->cond));
283 15883
                }
284 79340
                if (rv > l || oc->boc->state >= BOS_FINISHED)
285 53869
                        break;
286 25471
                (void)Lck_CondWait(&oc->boc->cond, &oc->boc->mtx);
287
        }
288 53869
        rv = oc->boc->fetched_so_far;
289 53869
        Lck_Unlock(&oc->boc->mtx);
290 53869
        return (rv);
291
}
292
293
/*====================================================================
294
 */
295
296
void
297 179466
ObjSetState(struct worker *wrk, const struct objcore *oc,
298
    enum boc_state_e next)
299
{
300
        const struct obj_methods *om;
301
302 179466
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
303 179466
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
304 179466
        assert(next > oc->boc->state);
305
306 179466
        CHECK_OBJ_ORNULL(oc->stobj->stevedore, STEVEDORE_MAGIC);
307 179466
        assert(next != BOS_STREAM || oc->boc->state == BOS_PREP_STREAM);
308 179466
        assert(next != BOS_FINISHED || (oc->oa_present & (1 << OA_LEN)));
309
310 179466
        if (oc->stobj->stevedore != NULL) {
311 124993
                om = oc->stobj->stevedore->methods;
312 124993
                if (om->objsetstate != NULL)
313 0
                        om->objsetstate(wrk, oc, next);
314 124993
        }
315
316 179466
        Lck_Lock(&oc->boc->mtx);
317 179466
        oc->boc->state = next;
318 179466
        PTOK(pthread_cond_broadcast(&oc->boc->cond));
319 179466
        Lck_Unlock(&oc->boc->mtx);
320 179466
}
321
322
/*====================================================================
323
 */
324
325
void
326 62831
ObjWaitState(const struct objcore *oc, enum boc_state_e want)
327
{
328
329 62831
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
330 62831
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
331
332 62831
        Lck_Lock(&oc->boc->mtx);
333
        /* wake up obj_extend_condwait() */
334 62831
        if (oc->flags & OC_F_CANCEL)
335 8886
                PTOK(pthread_cond_signal(&oc->boc->cond));
336 830632
        while (1) {
337 830632
                if (oc->boc->state >= want)
338 62831
                        break;
339 767801
                (void)Lck_CondWait(&oc->boc->cond, &oc->boc->mtx);
340
        }
341 62831
        Lck_Unlock(&oc->boc->mtx);
342 62831
}
343
344
/*====================================================================
345
 * ObjGetlen()
346
 *
347
 * This is a separate function because it may need locking
348
 */
349
350
uint64_t
351 124373
ObjGetLen(struct worker *wrk, struct objcore *oc)
352
{
353
        uint64_t len;
354
355 124373
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
356
357 124373
        AZ(ObjGetU64(wrk, oc, OA_LEN, &len));
358 124373
        return (len);
359
}
360
361
/*====================================================================
362
 * ObjSlim()
363
 *
364
 * Free the whatever storage can be freed, without freeing the actual
365
 * object yet.
366
 */
367
368
void
369 35624
ObjSlim(struct worker *wrk, struct objcore *oc)
370
{
371 35624
        const struct obj_methods *om = obj_getmethods(oc);
372
373 35624
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
374
375 35624
        if (om->objslim != NULL)
376 35624
                om->objslim(wrk, oc);
377 35624
}
378
379
/*====================================================================
380
 * Called when the boc used to populate the objcore is going away.
381
 * Useful for releasing any leftovers from Trim.
382
 */
383
384
void
385 67225
ObjBocDone(struct worker *wrk, struct objcore *oc, struct boc **boc)
386
{
387
        const struct obj_methods *m;
388
389 67225
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
390 67225
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
391 67225
        AN(boc);
392 67225
        CHECK_OBJ_NOTNULL(*boc, BOC_MAGIC);
393 67225
        CHECK_OBJ_ORNULL(oc->stobj->stevedore, STEVEDORE_MAGIC);
394 67225
        if (oc->stobj->stevedore != NULL) {
395 65875
                m = obj_getmethods(oc);
396 65875
                if (m->objbocdone != NULL)
397 65874
                        m->objbocdone(wrk, oc, *boc);
398 65875
        }
399 67225
        obj_deleteboc(boc);
400 67225
}
401
402
/*====================================================================
403
 */
404
void
405 40814
ObjFreeObj(struct worker *wrk, struct objcore *oc)
406
{
407 40814
        const struct obj_methods *m = obj_getmethods(oc);
408
409 40814
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
410
411 40814
        AN(m->objfree);
412 40814
        m->objfree(wrk, oc);
413 40814
        AZ(oc->stobj->stevedore);
414 40814
}
415
416
/*====================================================================
417
 * ObjHasAttr()
418
 *
419
 * Check if object has this attribute
420
 */
421
422
int
423 184076
ObjHasAttr(struct worker *wrk, struct objcore *oc, enum obj_attr attr)
424
{
425
426 184076
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
427 184076
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
428
429 184076
        if (oc->oa_present)
430 183626
                return (oc->oa_present & (1 << attr));
431
432
        /* resurrected persistent objects don't have oa_present set */
433 450
        return (ObjGetAttr(wrk, oc, attr, NULL) != NULL ? 1 : 0);
434 184076
}
435
436
/*====================================================================
437
 * ObjGetAttr()
438
 *
439
 * Get an attribute of the object.
440
 *
441
 * Returns NULL on unset or zero length attributes and len set to
442
 * zero. Returns Non-NULL otherwise and len is updated with the attributes
443
 * length.
444
 */
445
446
const void *
447 518434
ObjGetAttr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
448
   ssize_t *len)
449
{
450 518434
        const struct obj_methods *om = obj_getmethods(oc);
451
452 518434
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
453
454 518434
        AN(om->objgetattr);
455 518434
        return (om->objgetattr(wrk, oc, attr, len));
456
}
457
458
/*====================================================================
459
 * ObjSetAttr()
460
 *
461
 * Setting fixed size attributes always succeeds.
462
 *
463
 * Setting a variable size attribute asserts if the combined size of the
464
 * variable attributes exceeds the total variable attribute space set at
465
 * object creation. If there is space it always succeeds.
466
 *
467
 * Setting an auxiliary attribute can fail.
468
 *
469
 * Resetting any variable asserts if the new length does not match the
470
 * previous length exactly.
471
 *
472
 * If ptr is Non-NULL, it points to the new content which is copied into
473
 * the attribute.  Otherwise the caller will have to do the copying.
474
 *
475
 * Return value is non-NULL on success and NULL on failure. If ptr was
476
 * non-NULL, it is an error to use the returned pointer to set the
477
 * attribute data, it is only a success indicator in that case.
478
 */
479
480
void *
481 250660
ObjSetAttr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
482
    ssize_t len, const void *ptr)
483
{
484 250660
        const struct obj_methods *om = obj_getmethods(oc);
485
        void *r;
486
487 250660
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
488 250660
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
489
490 250660
        AN(om->objsetattr);
491 250660
        assert((int)attr < 16);
492 250660
        r = om->objsetattr(wrk, oc, attr, len, ptr);
493 250660
        if (r)
494 250647
                oc->oa_present |= (1 << attr);
495 250668
        return (r);
496
}
497
498
/*====================================================================
499
 * ObjTouch()
500
 */
501
502
void
503 76266
ObjTouch(struct worker *wrk, struct objcore *oc, vtim_real now)
504
{
505 76266
        const struct obj_methods *om = obj_getmethods(oc);
506
507 76266
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
508 76266
        if (om->objtouch != NULL)
509 76266
                om->objtouch(wrk, oc, now);
510 76268
}
511
512
/*====================================================================
513
 * Utility functions which work on top of the previous ones
514
 */
515
516
int
517 1173
ObjCopyAttr(struct worker *wrk, struct objcore *oc, struct objcore *ocs,
518
    enum obj_attr attr)
519
{
520
        const void *vps;
521
        void *vpd;
522
        ssize_t l;
523
524 1173
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
525 1173
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
526 1173
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
527 1173
        CHECK_OBJ_NOTNULL(ocs, OBJCORE_MAGIC);
528
529 1173
        vps = ObjGetAttr(wrk, ocs, attr, &l);
530
        // XXX: later we want to have zero-length OA's too
531 1173
        if (vps == NULL || l <= 0)
532 0
                return (-1);
533 1173
        vpd = ObjSetAttr(wrk, oc, attr, l, vps);
534 1173
        if (vpd == NULL)
535 0
                return (-1);
536 1173
        return (0);
537 1173
}
538
539
int
540 52798
ObjSetXID(struct worker *wrk, struct objcore *oc, vxid_t xid)
541
{
542
        uint64_t u;
543
544 52798
        u = VXID(xid);
545 52798
        AZ(ObjSetU64(wrk, oc, OA_VXID, u));
546 52798
        return (0);
547
}
548
549
550
vxid_t
551 63024
ObjGetXID(struct worker *wrk, struct objcore *oc)
552
{
553
        vxid_t u;
554
555 63024
        AZ(ObjGetU64(wrk, oc, OA_VXID, &u.vxid));
556 63024
        return (u);
557
}
558
559
/*--------------------------------------------------------------------
560
 * There is no well-defined byteorder for IEEE-754 double and the
561
 * correct solution (frexp(3) and manual encoding) is more work
562
 * than our (weak) goal of being endian-agnostic requires at this point.
563
 * We give it a shot by memcpy'ing doubles over a uint64_t and then
564
 * BE encode that.
565
 */
566
567
int
568 52798
ObjSetDouble(struct worker *wrk, struct objcore *oc, enum obj_attr a, double t)
569
{
570
        void *vp;
571
        uint64_t u;
572
573 52798
        assert(sizeof t == sizeof u);
574 52798
        memcpy(&u, &t, sizeof u);
575 52798
        vp = ObjSetAttr(wrk, oc, a, sizeof u, NULL);
576 52798
        if (vp == NULL)
577 0
                return (-1);
578 52798
        vbe64enc(vp, u);
579 52798
        return (0);
580 52798
}
581
582
int
583 50
ObjGetDouble(struct worker *wrk, struct objcore *oc, enum obj_attr a, double *d)
584
{
585
        const void *vp;
586
        uint64_t u;
587
        ssize_t l;
588
589 50
        assert(sizeof *d == sizeof u);
590 50
        vp = ObjGetAttr(wrk, oc, a, &l);
591 50
        if (vp == NULL)
592 0
                return (-1);
593 50
        if (d != NULL) {
594 50
                assert(l == sizeof u);
595 50
                u = vbe64dec(vp);
596 50
                memcpy(d, &u, sizeof *d);
597 50
        }
598 50
        return (0);
599 50
}
600
601
/*--------------------------------------------------------------------
602
 */
603
604
int
605 116222
ObjSetU64(struct worker *wrk, struct objcore *oc, enum obj_attr a, uint64_t t)
606
{
607
        void *vp;
608
609 116222
        vp = ObjSetAttr(wrk, oc, a, sizeof t, NULL);
610 116222
        if (vp == NULL)
611 0
                return (-1);
612 116222
        vbe64enc(vp, t);
613 116222
        return (0);
614 116222
}
615
616
int
617 187481
ObjGetU64(struct worker *wrk, struct objcore *oc, enum obj_attr a, uint64_t *d)
618
{
619
        const void *vp;
620
        ssize_t l;
621
622 187481
        vp = ObjGetAttr(wrk, oc, a, &l);
623 187481
        if (vp == NULL || l != sizeof *d)
624 14
                return (-1);
625 187481
        if (d != NULL)
626 187474
                *d = vbe64dec(vp);
627 187481
        return (0);
628 187469
}
629
630
/*--------------------------------------------------------------------
631
 */
632
633
int
634 169644
ObjCheckFlag(struct worker *wrk, struct objcore *oc, enum obj_flags of)
635
{
636
        const uint8_t *fp;
637
638 169644
        fp = ObjGetAttr(wrk, oc, OA_FLAGS, NULL);
639 169644
        AN(fp);
640 169644
        return ((*fp) & of);
641
}
642
643
void
644 12121
ObjSetFlag(struct worker *wrk, struct objcore *oc, enum obj_flags of, int val)
645
{
646
        uint8_t *fp;
647
648 12121
        fp = ObjSetAttr(wrk, oc, OA_FLAGS, 1, NULL);
649 12121
        AN(fp);
650 12121
        if (val)
651 12071
                (*fp) |= of;
652
        else
653 50
                (*fp) &= ~of;
654 12121
}
655
656
/*====================================================================
657
 * Object event subscribtion mechanism.
658
 *
659
 * XXX: it is extremely unclear what the locking circumstances are here.
660
 */
661
662
struct oev_entry {
663
        unsigned                        magic;
664
#define OEV_MAGIC                       0xb0b7c5a1
665
        unsigned                        mask;
666
        obj_event_f                     *func;
667
        void                            *priv;
668
        VTAILQ_ENTRY(oev_entry)         list;
669
};
670
671
static VTAILQ_HEAD(,oev_entry)          oev_list;
672
static pthread_rwlock_t                 oev_rwl;
673
static unsigned                         oev_mask;
674
675
/*
676
 * NB: ObjSubscribeEvents() is not atomic:
677
 * oev_mask is checked optimistically in ObjSendEvent()
678
 */
679
uintptr_t
680 975
ObjSubscribeEvents(obj_event_f *func, void *priv, unsigned mask)
681
{
682
        struct oev_entry *oev;
683
684 975
        AN(func);
685 975
        AZ(mask & ~OEV_MASK);
686
687 975
        ALLOC_OBJ(oev, OEV_MAGIC);
688 975
        AN(oev);
689 975
        oev->func = func;
690 975
        oev->priv = priv;
691 975
        oev->mask = mask;
692 975
        PTOK(pthread_rwlock_wrlock(&oev_rwl));
693 975
        VTAILQ_INSERT_TAIL(&oev_list, oev, list);
694 975
        oev_mask |= mask;
695 975
        PTOK(pthread_rwlock_unlock(&oev_rwl));
696 975
        return ((uintptr_t)oev);
697
}
698
699
void
700 25
ObjUnsubscribeEvents(uintptr_t *handle)
701
{
702 25
        struct oev_entry *oev, *oev2 = NULL;
703 25
        unsigned newmask = 0;
704
705 25
        AN(handle);
706 25
        AN(*handle);
707 25
        PTOK(pthread_rwlock_wrlock(&oev_rwl));
708 50
        VTAILQ_FOREACH(oev, &oev_list, list) {
709 25
                CHECK_OBJ_NOTNULL(oev, OEV_MAGIC);
710 25
                if ((uintptr_t)oev == *handle)
711 25
                        oev2 = oev;
712
                else
713 0
                        newmask |= oev->mask;
714 25
        }
715 25
        AN(oev2);
716 25
        VTAILQ_REMOVE(&oev_list, oev2, list);
717 25
        oev_mask = newmask;
718 25
        AZ(newmask & ~OEV_MASK);
719 25
        PTOK(pthread_rwlock_unlock(&oev_rwl));
720 25
        FREE_OBJ(oev2);
721 25
        *handle = 0;
722 25
}
723
724
void
725 78764
ObjSendEvent(struct worker *wrk, struct objcore *oc, unsigned event)
726
{
727
        struct oev_entry *oev;
728
729 78764
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
730 78764
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
731 78764
        AN(event & OEV_MASK);
732 78764
        AZ(event & ~OEV_MASK);
733 78764
        if (!(event & oev_mask))
734 76537
                return;
735
736 2227
        PTOK(pthread_rwlock_rdlock(&oev_rwl));
737 4851
        VTAILQ_FOREACH(oev, &oev_list, list) {
738 2626
                CHECK_OBJ_NOTNULL(oev, OEV_MAGIC);
739 2626
                if (event & oev->mask)
740 2625
                        oev->func(wrk, oev->priv, oc, event);
741 2626
        }
742 2225
        PTOK(pthread_rwlock_unlock(&oev_rwl));
743
744 78762
}
745
746
void
747 22197
ObjInit(void)
748
{
749 22197
        VTAILQ_INIT(&oev_list);
750 22197
        PTOK(pthread_rwlock_init(&oev_rwl, NULL));
751 22197
}