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