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 793591
obj_getmethods(const struct objcore *oc)
93
{
94
95 793591
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
96 793591
        CHECK_OBJ_NOTNULL(oc->stobj->stevedore, STEVEDORE_MAGIC);
97 793591
        AN(oc->stobj->stevedore->methods);
98 793591
        return (oc->stobj->stevedore->methods);
99
}
100
101
static struct boc *
102 15706
obj_newboc(void)
103
{
104
        struct boc *boc;
105
106 15706
        ALLOC_OBJ(boc, BOC_MAGIC);
107 15704
        AN(boc);
108 15704
        Lck_New(&boc->mtx, lck_busyobj);
109 15704
        PTOK(pthread_cond_init(&boc->cond, NULL));
110 15704
        boc->refcount = 1;
111 15704
        boc->transit_buffer = cache_param->transit_buffer;
112 15704
        return (boc);
113
}
114
115
static void
116 14379
obj_deleteboc(struct boc **p)
117
{
118
        struct boc *boc;
119
120 14379
        TAKE_OBJ_NOTNULL(boc, p, BOC_MAGIC);
121 14379
        Lck_Delete(&boc->mtx);
122 14379
        PTOK(pthread_cond_destroy(&boc->cond));
123 14379
        free(boc->vary);
124 14379
        FREE_OBJ(boc);
125 14379
}
126
127
/*====================================================================
128
 * ObjNew()
129
 *
130
 */
131
132
struct objcore *
133 15705
ObjNew(const struct worker *wrk)
134
{
135
        struct objcore *oc;
136
137 15705
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
138
139 15705
        ALLOC_OBJ(oc, OBJCORE_MAGIC);
140 15705
        AN(oc);
141 15705
        wrk->stats->n_objectcore++;
142 15705
        oc->last_lru = NAN;
143 15705
        oc->flags = OC_F_BUSY;
144
145 15705
        oc->boc = obj_newboc();
146
147 15705
        return (oc);
148
}
149
150
/*====================================================================
151
 * ObjDestroy()
152
 *
153
 */
154
155
void
156 9152
ObjDestroy(const struct worker *wrk, struct objcore **p)
157
{
158
        struct objcore *oc;
159
160 9152
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
161 9152
        TAKE_OBJ_NOTNULL(oc, p, OBJCORE_MAGIC);
162 9152
        if (oc->boc != NULL)
163 170
                obj_deleteboc(&oc->boc);
164 9152
        FREE_OBJ(oc);
165 9152
        wrk->stats->n_objectcore--;
166 9152
}
167
168
/*====================================================================
169
 * ObjIterate()
170
 *
171
 */
172
173
int
174 11918
ObjIterate(struct worker *wrk, struct objcore *oc,
175
    void *priv, objiterate_f *func, int final)
176
{
177 11918
        const struct obj_methods *om = obj_getmethods(oc);
178
179 11918
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
180 11918
        AN(func);
181 11918
        AN(om->objiterator);
182 11918
        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 289862
ObjGetSpace(struct worker *wrk, struct objcore *oc, ssize_t *sz, uint8_t **ptr)
197
{
198 289862
        const struct obj_methods *om = obj_getmethods(oc);
199
200 289862
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
201 289862
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
202 289862
        AN(sz);
203 289862
        AN(ptr);
204 289862
        assert(*sz >= 0);
205
206 289862
        AN(om->objgetspace);
207 289862
        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 282621
obj_extend_condwait(const struct objcore *oc)
222
{
223
224 282621
        if (oc->boc->transit_buffer == 0)
225 280214
                return;
226
227 2407
        assert(oc->flags & OC_F_TRANSIENT);
228 2553
        while (!(oc->flags & OC_F_CANCEL) && oc->boc->fetched_so_far >
229 2543
            oc->boc->delivered_so_far + oc->boc->transit_buffer)
230 146
                (void)Lck_CondWait(&oc->boc->cond, &oc->boc->mtx);
231 282621
}
232
233
void
234 286050
ObjExtend(struct worker *wrk, struct objcore *oc, ssize_t l, int final)
235
{
236 286050
        const struct obj_methods *om = obj_getmethods(oc);
237
238 286050
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
239 286050
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
240 286050
        AN(om->objextend);
241 286050
        assert(l >= 0);
242
243 286050
        Lck_Lock(&oc->boc->mtx);
244 286050
        if (l > 0) {
245 282621
                obj_extend_condwait(oc);
246 282621
                om->objextend(wrk, oc, l);
247 282621
                oc->boc->fetched_so_far += l;
248 282621
                PTOK(pthread_cond_broadcast(&oc->boc->cond));
249 282621
        }
250 286050
        Lck_Unlock(&oc->boc->mtx);
251
252 286050
        assert(oc->boc->state < BOS_FINISHED);
253 286050
        if (final && om->objtrimstore != NULL)
254 9303
                om->objtrimstore(wrk, oc);
255 286050
}
256
257
/*====================================================================
258
 */
259
260
uint64_t
261 10869
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 10869
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
268 10869
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
269 10869
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
270 10869
        Lck_Lock(&oc->boc->mtx);
271 16029
        while (1) {
272 16029
                rv = oc->boc->fetched_so_far;
273 16029
                assert(l <= rv || oc->boc->state == BOS_FAILED);
274 16029
                if (oc->boc->transit_buffer > 0) {
275 3168
                        assert(oc->flags & OC_F_TRANSIENT);
276
                        /* Signal the new client position */
277 3168
                        oc->boc->delivered_so_far = l;
278 3168
                        PTOK(pthread_cond_signal(&oc->boc->cond));
279 3168
                }
280 16029
                state = oc->boc->state;
281 16029
                if (rv > l || state >= BOS_FINISHED)
282 10869
                        break;
283 5160
                (void)Lck_CondWait(&oc->boc->cond, &oc->boc->mtx);
284
        }
285 10869
        Lck_Unlock(&oc->boc->mtx);
286 10869
        if (statep != NULL)
287 10869
                *statep = state;
288 10869
        return (rv);
289
}
290
/*====================================================================
291
 */
292
293
void
294 36947
ObjSetState(struct worker *wrk, const struct objcore *oc,
295
    enum boc_state_e next)
296
{
297
        const struct obj_methods *om;
298
299 36947
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
300 36947
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
301 36947
        assert(next > oc->boc->state);
302
303 36947
        CHECK_OBJ_ORNULL(oc->stobj->stevedore, STEVEDORE_MAGIC);
304 36947
        assert(next != BOS_STREAM || oc->boc->state == BOS_PREP_STREAM);
305 36947
        assert(next != BOS_FINISHED || (oc->oa_present & (1 << OA_LEN)));
306
307 36947
        if (oc->stobj->stevedore != NULL) {
308 25733
                om = oc->stobj->stevedore->methods;
309 25733
                if (om->objsetstate != NULL)
310 0
                        om->objsetstate(wrk, oc, next);
311 25733
        }
312
313 36947
        Lck_Lock(&oc->boc->mtx);
314 36947
        oc->boc->state = next;
315 36947
        PTOK(pthread_cond_broadcast(&oc->boc->cond));
316 36947
        Lck_Unlock(&oc->boc->mtx);
317 36947
}
318
319
/*====================================================================
320
 */
321
322
void
323 12863
ObjWaitState(const struct objcore *oc, enum boc_state_e want)
324
{
325
326 12863
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
327 12863
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
328
329 12863
        Lck_Lock(&oc->boc->mtx);
330
        /* wake up obj_extend_condwait() */
331 12863
        if (oc->flags & OC_F_CANCEL)
332 1740
                PTOK(pthread_cond_signal(&oc->boc->cond));
333 173223
        while (1) {
334 173223
                if (oc->boc->state >= want)
335 12863
                        break;
336 160360
                (void)Lck_CondWait(&oc->boc->cond, &oc->boc->mtx);
337
        }
338 12863
        Lck_Unlock(&oc->boc->mtx);
339 12863
}
340
341
/*====================================================================
342
 * ObjGetlen()
343
 *
344
 * This is a separate function because it may need locking
345
 */
346
347
uint64_t
348 26209
ObjGetLen(struct worker *wrk, struct objcore *oc)
349
{
350
        uint64_t len;
351
352 26209
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
353
354 26209
        AZ(ObjGetU64(wrk, oc, OA_LEN, &len));
355 26209
        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 6920
ObjSlim(struct worker *wrk, struct objcore *oc)
367
{
368 6920
        const struct obj_methods *om = obj_getmethods(oc);
369
370 6920
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
371
372 6920
        if (om->objslim != NULL)
373 6920
                om->objslim(wrk, oc);
374 6920
}
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 14210
ObjBocDone(struct worker *wrk, struct objcore *oc, struct boc **boc)
383
{
384
        const struct obj_methods *m;
385
386 14210
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
387 14210
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
388 14210
        AN(boc);
389 14210
        CHECK_OBJ_NOTNULL(*boc, BOC_MAGIC);
390 14210
        CHECK_OBJ_ORNULL(oc->stobj->stevedore, STEVEDORE_MAGIC);
391 14210
        if (oc->stobj->stevedore != NULL) {
392 13945
                m = obj_getmethods(oc);
393 13945
                if (m->objbocdone != NULL)
394 13945
                        m->objbocdone(wrk, oc, *boc);
395 13945
        }
396 14210
        obj_deleteboc(boc);
397 14210
}
398
399
/*====================================================================
400
 */
401
void
402 8822
ObjFreeObj(struct worker *wrk, struct objcore *oc)
403
{
404 8822
        const struct obj_methods *m = obj_getmethods(oc);
405
406 8822
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
407
408 8822
        AN(m->objfree);
409 8822
        m->objfree(wrk, oc);
410 8822
        AZ(oc->stobj->stevedore);
411 8822
}
412
413
/*====================================================================
414
 * ObjHasAttr()
415
 *
416
 * Check if object has this attribute
417
 */
418
419
int
420 37948
ObjHasAttr(struct worker *wrk, struct objcore *oc, enum obj_attr attr)
421
{
422
423 37948
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
424 37948
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
425
426 37948
        if (oc->oa_present)
427 37858
                return (oc->oa_present & (1 << attr));
428
429
        /* resurrected persistent objects don't have oa_present set */
430 90
        return (ObjGetAttr(wrk, oc, attr, NULL) != NULL ? 1 : 0);
431 37948
}
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 108216
ObjGetAttr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
445
   ssize_t *len)
446
{
447 108216
        const struct obj_methods *om = obj_getmethods(oc);
448
449 108216
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
450
451 108216
        AN(om->objgetattr);
452 108216
        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 52079
ObjSetAttr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
479
    ssize_t len, const void *ptr)
480
{
481 52079
        const struct obj_methods *om = obj_getmethods(oc);
482
        void *r;
483
484 52079
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
485 52079
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
486
487 52079
        AN(om->objsetattr);
488 52079
        assert((int)attr < 16);
489 52079
        r = om->objsetattr(wrk, oc, attr, len, ptr);
490 52079
        if (r)
491 52076
                oc->oa_present |= (1 << attr);
492 52085
        return (r);
493
}
494
495
/*====================================================================
496
 * ObjTouch()
497
 */
498
499
void
500 15788
ObjTouch(struct worker *wrk, struct objcore *oc, vtim_real now)
501
{
502 15788
        const struct obj_methods *om = obj_getmethods(oc);
503
504 15788
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
505 15788
        if (om->objtouch != NULL)
506 15788
                om->objtouch(wrk, oc, now);
507 15788
}
508
509
/*====================================================================
510
 * Utility functions which work on top of the previous ones
511
 */
512
513
int
514 245
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 245
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
522 245
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
523 245
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
524 245
        CHECK_OBJ_NOTNULL(ocs, OBJCORE_MAGIC);
525
526 245
        vps = ObjGetAttr(wrk, ocs, attr, &l);
527
        // XXX: later we want to have zero-length OA's too
528 245
        if (vps == NULL || l <= 0)
529 0
                return (-1);
530 245
        vpd = ObjSetAttr(wrk, oc, attr, l, vps);
531 245
        if (vpd == NULL)
532 0
                return (-1);
533 245
        return (0);
534 245
}
535
536
int
537 10899
ObjSetXID(struct worker *wrk, struct objcore *oc, vxid_t xid)
538
{
539
        uint64_t u;
540
541 10899
        u = VXID(xid);
542 10899
        AZ(ObjSetU64(wrk, oc, OA_VXID, u));
543 10899
        return (0);
544
}
545
546
547
vxid_t
548 13819
ObjGetXID(struct worker *wrk, struct objcore *oc)
549
{
550
        vxid_t u;
551
552 13819
        AZ(ObjGetU64(wrk, oc, OA_VXID, &u.vxid));
553 13819
        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 10898
ObjSetDouble(struct worker *wrk, struct objcore *oc, enum obj_attr a, double t)
566
{
567
        void *vp;
568
        uint64_t u;
569
570 10898
        assert(sizeof t == sizeof u);
571 10898
        memcpy(&u, &t, sizeof u);
572 10898
        vp = ObjSetAttr(wrk, oc, a, sizeof u, NULL);
573 10898
        if (vp == NULL)
574 0
                return (-1);
575 10898
        vbe64enc(vp, u);
576 10898
        return (0);
577 10898
}
578
579
int
580 10
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 10
        assert(sizeof *d == sizeof u);
587 10
        vp = ObjGetAttr(wrk, oc, a, &l);
588 10
        if (vp == NULL)
589 0
                return (-1);
590 10
        if (d != NULL) {
591 10
                assert(l == sizeof u);
592 10
                u = vbe64dec(vp);
593 10
                memcpy(d, &u, sizeof *d);
594 10
        }
595 10
        return (0);
596 10
}
597
598
/*--------------------------------------------------------------------
599
 */
600
601
int
602 24299
ObjSetU64(struct worker *wrk, struct objcore *oc, enum obj_attr a, uint64_t t)
603
{
604
        void *vp;
605
606 24299
        vp = ObjSetAttr(wrk, oc, a, sizeof t, NULL);
607 24299
        if (vp == NULL)
608 0
                return (-1);
609 24299
        vbe64enc(vp, t);
610 24299
        return (0);
611 24299
}
612
613
int
614 40045
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 40045
        vp = ObjGetAttr(wrk, oc, a, &l);
620 40045
        if (vp == NULL || l != sizeof *d)
621 8
                return (-1);
622 40045
        if (d != NULL)
623 40041
                *d = vbe64dec(vp);
624 40045
        return (0);
625 40041
}
626
627
/*--------------------------------------------------------------------
628
 */
629
630
int
631 35286
ObjCheckFlag(struct worker *wrk, struct objcore *oc, enum obj_flags of)
632
{
633
        const uint8_t *fp;
634
635 35286
        fp = ObjGetAttr(wrk, oc, OA_FLAGS, NULL);
636 35286
        AN(fp);
637 35286
        return ((*fp) & of);
638
}
639
640
void
641 2450
ObjSetFlag(struct worker *wrk, struct objcore *oc, enum obj_flags of, int val)
642
{
643
        uint8_t *fp;
644
645 2450
        fp = ObjSetAttr(wrk, oc, OA_FLAGS, 1, NULL);
646 2450
        AN(fp);
647 2450
        if (val)
648 2440
                (*fp) |= of;
649
        else
650 10
                (*fp) &= ~of;
651 2450
}
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 195
ObjSubscribeEvents(obj_event_f *func, void *priv, unsigned mask)
678
{
679
        struct oev_entry *oev;
680
681 195
        AN(func);
682 195
        AZ(mask & ~OEV_MASK);
683
684 195
        ALLOC_OBJ(oev, OEV_MAGIC);
685 195
        AN(oev);
686 195
        oev->func = func;
687 195
        oev->priv = priv;
688 195
        oev->mask = mask;
689 195
        PTOK(pthread_rwlock_wrlock(&oev_rwl));
690 195
        VTAILQ_INSERT_TAIL(&oev_list, oev, list);
691 195
        oev_mask |= mask;
692 195
        PTOK(pthread_rwlock_unlock(&oev_rwl));
693 195
        return ((uintptr_t)oev);
694
}
695
696
void
697 5
ObjUnsubscribeEvents(uintptr_t *handle)
698
{
699 5
        struct oev_entry *oev, *oev2 = NULL;
700 5
        unsigned newmask = 0;
701
702 5
        AN(handle);
703 5
        AN(*handle);
704 5
        PTOK(pthread_rwlock_wrlock(&oev_rwl));
705 10
        VTAILQ_FOREACH(oev, &oev_list, list) {
706 5
                CHECK_OBJ_NOTNULL(oev, OEV_MAGIC);
707 5
                if ((uintptr_t)oev == *handle)
708 5
                        oev2 = oev;
709
                else
710 0
                        newmask |= oev->mask;
711 5
        }
712 5
        AN(oev2);
713 5
        VTAILQ_REMOVE(&oev_list, oev2, list);
714 5
        oev_mask = newmask;
715 5
        AZ(newmask & ~OEV_MASK);
716 5
        PTOK(pthread_rwlock_unlock(&oev_rwl));
717 5
        FREE_OBJ(oev2);
718 5
        *handle = 0;
719 5
}
720
721
void
722 16112
ObjSendEvent(struct worker *wrk, struct objcore *oc, unsigned event)
723
{
724
        struct oev_entry *oev;
725
726 16112
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
727 16112
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
728 16112
        AN(event & OEV_MASK);
729 16112
        AZ(event & ~OEV_MASK);
730 16112
        if (!(event & oev_mask))
731 15667
                return;
732
733 445
        PTOK(pthread_rwlock_rdlock(&oev_rwl));
734 970
        VTAILQ_FOREACH(oev, &oev_list, list) {
735 525
                CHECK_OBJ_NOTNULL(oev, OEV_MAGIC);
736 525
                if (event & oev->mask)
737 525
                        oev->func(wrk, oev->priv, oc, event);
738 525
        }
739 445
        PTOK(pthread_rwlock_unlock(&oev_rwl));
740
741 16112
}
742
743
void
744 4613
ObjInit(void)
745
{
746 4613
        VTAILQ_INIT(&oev_list);
747 4613
        PTOK(pthread_rwlock_init(&oev_rwl, NULL));
748 4613
}