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