varnish-cache/bin/varnishd/cache/cache_obj.c
1
/*-
2
 * Copyright (c) 2013-2016 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 *
28
 * Lifetime of an objcore:
29
 *      phase 0 - nonexistent
30
 *      phase 1 - created, but no stevedore associated
31
 *      phase 2 - stevedore associated, being filled out
32
 *      phase 3 - stable, no changes happening
33
 *      phase 4 - unavailable, being dismantled
34
 *      phase 5 - stevedore disassociated
35
 *      phase 6 - nonexistent
36
 *
37
 * 0->1 ObjNew()        creates objcore
38
 *
39
 * 1->2 STV_NewObject() associates a stevedore
40
 *
41
 * 2    ObjSetState()   sets state
42
 * 2    ObjWaitState()  waits for particular state
43
 *                      INVALID->REQ_DONE->STREAM->FINISHED->FAILED
44
 *
45
 * 2    ObjGetSpace()   allocates space
46
 * 2    ObjExtend()     commits content
47
 * 2    ObjWaitExtend() waits for content - used to implement ObjIterate())
48
 * 2    ObjTrimStore()  signals end of content addition
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 1713194
obj_getmethods(const struct objcore *oc)
93
{
94
95 1713194
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
96 1713194
        CHECK_OBJ_NOTNULL(oc->stobj->stevedore, STEVEDORE_MAGIC);
97 1713194
        AN(oc->stobj->stevedore->methods);
98 1713194
        return (oc->stobj->stevedore->methods);
99
}
100
101
static struct boc *
102 25757
obj_newboc(void)
103
{
104
        struct boc *boc;
105
106 25757
        ALLOC_OBJ(boc, BOC_MAGIC);
107 25757
        AN(boc);
108 25757
        Lck_New(&boc->mtx, lck_busyobj);
109 25756
        AZ(pthread_cond_init(&boc->cond, NULL));
110 25757
        boc->refcount = 1;
111 25757
        return (boc);
112
}
113
114
static void
115 23545
obj_deleteboc(struct boc **p)
116
{
117
        struct boc *boc;
118
119 23545
        AN(p);
120 23545
        boc = *p;
121 23545
        *p = NULL;
122 23545
        Lck_Delete(&boc->mtx);
123 23545
        AZ(pthread_cond_destroy(&boc->cond));
124 23545
        if (boc->vary != NULL)
125 1152
                free(boc->vary);
126 23545
        FREE_OBJ(boc);
127 23545
}
128
129
/*====================================================================
130
 * ObjNew()
131
 *
132
 */
133
134
struct objcore *
135 25757
ObjNew(const struct worker *wrk)
136
{
137
        struct objcore *oc;
138
139 25757
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
140
141 25757
        ALLOC_OBJ(oc, OBJCORE_MAGIC);
142 25757
        AN(oc);
143 25757
        wrk->stats->n_objectcore++;
144 25757
        oc->last_lru = NAN;
145 25757
        oc->flags = OC_F_BUSY;
146
147 25757
        oc->boc = obj_newboc();
148
149 25757
        return (oc);
150
}
151
152
/*====================================================================
153
 * ObjDestroy()
154
 *
155
 */
156
157
void
158 13189
ObjDestroy(const struct worker *wrk, struct objcore **p)
159
{
160
        struct objcore *oc;
161
162 13189
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
163 13189
        TAKE_OBJ_NOTNULL(oc, p, OBJCORE_MAGIC);
164 13189
        if (oc->boc != NULL)
165 349
                obj_deleteboc(&oc->boc);
166 13189
        FREE_OBJ(oc);
167 13188
        wrk->stats->n_objectcore--;
168 13188
}
169
170
/*====================================================================
171
 * ObjIterate()
172
 *
173
 */
174
175
int
176 19884
ObjIterate(struct worker *wrk, struct objcore *oc,
177
    void *priv, objiterate_f *func, int final)
178
{
179 19884
        const struct obj_methods *om = obj_getmethods(oc);
180
181 19884
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
182 19884
        AN(func);
183 19884
        AN(om->objiterator);
184 19884
        return (om->objiterator(wrk, oc, priv, func, final));
185
}
186
187
/*====================================================================
188
 * ObjGetSpace()
189
 *
190
 * This function returns a pointer and length of free space.  If there
191
 * is no free space, some will be added first.
192
 *
193
 * The "sz" argument is an input hint of how much space is desired.
194
 */
195
196
int
197 675938
ObjGetSpace(struct worker *wrk, struct objcore *oc, ssize_t *sz, uint8_t **ptr)
198
{
199 675938
        const struct obj_methods *om = obj_getmethods(oc);
200
201 675938
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
202 675938
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
203 675938
        AN(sz);
204 675938
        AN(ptr);
205 675938
        assert(*sz > 0);
206
207 675938
        AN(om->objgetspace);
208 675938
        return (om->objgetspace(wrk, oc, sz, ptr));
209
}
210
211
/*====================================================================
212
 * ObjExtend()
213
 *
214
 * This function extends the used part of the object a number of bytes
215
 * into the last space returned by ObjGetSpace()
216
 */
217
218
void
219 661704
ObjExtend(struct worker *wrk, struct objcore *oc, ssize_t l)
220
{
221 661704
        const struct obj_methods *om = obj_getmethods(oc);
222
223 661704
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
224 661704
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
225 661704
        assert(l > 0);
226
227 661704
        Lck_Lock(&oc->boc->mtx);
228 661704
        AN(om->objextend);
229 661704
        om->objextend(wrk, oc, l);
230 661703
        oc->boc->len_so_far += l;
231 661703
        Lck_Unlock(&oc->boc->mtx);
232 661704
        AZ(pthread_cond_broadcast(&oc->boc->cond));
233 661704
}
234
235
/*====================================================================
236
 */
237
238
uint64_t
239 17577
ObjWaitExtend(const struct worker *wrk, const struct objcore *oc, uint64_t l)
240
{
241
        uint64_t rv;
242
243 17577
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
244 17577
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
245 17577
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
246 17577
        Lck_Lock(&oc->boc->mtx);
247
        while (1) {
248 35556
                rv = oc->boc->len_so_far;
249 26567
                assert(l <= rv || oc->boc->state == BOS_FAILED);
250 26567
                if (rv > l || oc->boc->state >= BOS_FINISHED)
251
                        break;
252 8988
                (void)Lck_CondWait(&oc->boc->cond, &oc->boc->mtx, 0);
253
        }
254 17579
        rv = oc->boc->len_so_far;
255 17579
        Lck_Unlock(&oc->boc->mtx);
256 17579
        return (rv);
257
}
258
259
/*====================================================================
260
 */
261
262
void
263 56207
ObjSetState(struct worker *wrk, const struct objcore *oc,
264
    enum boc_state_e next)
265
{
266
        const struct obj_methods *om;
267
268 56207
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
269 56207
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
270 56207
        assert(next > oc->boc->state);
271
272 56207
        CHECK_OBJ_ORNULL(oc->stobj->stevedore, STEVEDORE_MAGIC);
273 56207
        assert(next != BOS_STREAM || oc->boc->state == BOS_PREP_STREAM);
274 56207
        assert(next != BOS_FINISHED || (oc->oa_present & (1 << OA_LEN)));
275
276 56207
        if (oc->stobj->stevedore != NULL) {
277 36467
                om = oc->stobj->stevedore->methods;
278 36467
                if (om->objsetstate != NULL)
279 0
                        om->objsetstate(wrk, oc, next);
280
        }
281
282 56207
        Lck_Lock(&oc->boc->mtx);
283 56205
        oc->boc->state = next;
284 56205
        AZ(pthread_cond_broadcast(&oc->boc->cond));
285 56204
        Lck_Unlock(&oc->boc->mtx);
286 56208
}
287
288
/*====================================================================
289
 */
290
291
void
292 23640
ObjWaitState(const struct objcore *oc, enum boc_state_e want)
293
{
294
295 23640
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
296 23640
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
297
298 23640
        Lck_Lock(&oc->boc->mtx);
299
        while (1) {
300 845786
                if (oc->boc->state >= want)
301 23628
                        break;
302 411085
                (void)Lck_CondWait(&oc->boc->cond, &oc->boc->mtx, 0);
303
        }
304 23628
        Lck_Unlock(&oc->boc->mtx);
305 23628
}
306
307
/*====================================================================
308
 * ObjGetlen()
309
 *
310
 * This is a separate function because it may need locking
311
 */
312
313
uint64_t
314 42189
ObjGetLen(struct worker *wrk, struct objcore *oc)
315
{
316
        uint64_t len;
317
318 42189
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
319
320 42189
        AZ(ObjGetU64(wrk, oc, OA_LEN, &len));
321 42187
        return(len);
322
}
323
324
/*====================================================================
325
 * ObjTrimStore()
326
 *
327
 * Release any surplus space allocated, we promise not to call ObjExtend()
328
 * any more.
329
 */
330
331
void
332 10739
ObjTrimStore(struct worker *wrk, struct objcore *oc)
333
{
334 10739
        const struct obj_methods *om = obj_getmethods(oc);
335
336 10740
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
337
338 10740
        assert(oc->boc == NULL || oc->boc->state < BOS_FINISHED);
339
340 10740
        if (om->objtrimstore != NULL)
341 10740
                om->objtrimstore(wrk, oc);
342 10740
}
343
344
/*====================================================================
345
 * ObjSlim()
346
 *
347
 * Free the whatever storage can be freed, without freeing the actual
348
 * object yet.
349
 */
350
351
void
352 9960
ObjSlim(struct worker *wrk, struct objcore *oc)
353
{
354 9960
        const struct obj_methods *om = obj_getmethods(oc);
355
356 9960
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
357
358 9960
        if (om->objslim != NULL)
359 9960
                om->objslim(wrk, oc);
360 9960
}
361
362
/*====================================================================
363
 * Called when the boc used to populate the objcore is going away.
364
 * Useful for releasing any leftovers from Trim.
365
 */
366
367
void
368 23196
ObjBocDone(struct worker *wrk, struct objcore *oc, struct boc **boc)
369
{
370
        const struct obj_methods *m;
371
372 23196
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
373 23196
        AN(boc);
374 23196
        CHECK_OBJ_NOTNULL(*boc, BOC_MAGIC);
375 23196
        if (oc->stobj->stevedore != NULL) {
376 22968
                m = obj_getmethods(oc);
377 22968
                if (m->objbocdone != NULL)
378 22968
                        m->objbocdone(wrk, oc, *boc);
379
        }
380 23196
        obj_deleteboc(boc);
381 23195
}
382
383
/*====================================================================
384
 */
385
void
386 12852
ObjFreeObj(struct worker *wrk, struct objcore *oc)
387
{
388 12852
        const struct obj_methods *m = obj_getmethods(oc);
389
390 12852
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
391
392 12852
        AN(m->objfree);
393 12852
        m->objfree(wrk, oc);
394 12852
        AZ(oc->stobj->stevedore);
395 12852
}
396
397
/*====================================================================
398
 * ObjHasAttr()
399
 *
400
 * Check if object has this attribute
401
 */
402
403
int
404 60247
ObjHasAttr(struct worker *wrk, struct objcore *oc, enum obj_attr attr)
405
{
406
407 60247
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
408 60247
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
409
410 60247
        if (oc->oa_present)
411 60127
                return (oc->oa_present & (1 << attr));
412
413
        /* resurrected persistent objects don't have oa_present set */
414 120
        return (ObjGetAttr(wrk, oc, attr, NULL) != NULL ? 1 : 0);
415
}
416
417
/*====================================================================
418
 * ObjGetAttr()
419
 *
420
 * Get an attribute of the object.
421
 *
422
 * Returns NULL on unset or zero length attributes and len set to
423
 * zero. Returns Non-NULL otherwise and len is updated with the attributes
424
 * length.
425
 */
426
427
const void *
428 181424
ObjGetAttr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
429
   ssize_t *len)
430
{
431 181424
        const struct obj_methods *om = obj_getmethods(oc);
432
433 181418
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
434
435 181418
        AN(om->objgetattr);
436 181418
        return (om->objgetattr(wrk, oc, attr, len));
437
}
438
439
/*====================================================================
440
 * ObjSetAttr()
441
 *
442
 * Setting fixed size attributes always succeeds.
443
 *
444
 * Setting a variable size attribute asserts if the combined size of the
445
 * variable attributes exceeds the total variable attribute space set at
446
 * object creation. If there is space it always succeeds.
447
 *
448
 * Setting an auxiliary attribute can fail.
449
 *
450
 * Resetting any variable asserts if the new length does not match the
451
 * previous length exactly.
452
 *
453
 * If ptr is Non-NULL, it points to the new content which is copied into
454
 * the attribute.  Otherwise the caller will have to do the copying.
455
 *
456
 * Return value is non-NULL on success and NULL on failure. If ptr was
457
 * non-NULL, it is an error to use the returned pointer to set the
458
 * attribute data, it is only a success indicator in that case.
459
 */
460
461
void *
462 91161
ObjSetAttr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
463
    ssize_t len, const void *ptr)
464
{
465 91161
        const struct obj_methods *om = obj_getmethods(oc);
466
        void *r;
467
468 91162
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
469 91162
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
470
471 91162
        AN(om->objsetattr);
472 91162
        assert((int)attr < 16);
473 91162
        r = om->objsetattr(wrk, oc, attr, len, ptr);
474 91165
        if (r)
475 91165
                oc->oa_present |= (1 << attr);
476 91165
        return (r);
477
}
478
479
/*====================================================================
480
 * ObjTouch()
481
 */
482
483
void
484 26676
ObjTouch(struct worker *wrk, struct objcore *oc, double now)
485
{
486 26676
        const struct obj_methods *om = obj_getmethods(oc);
487
488 26676
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
489 26676
        if (om->objtouch != NULL)
490 26316
                om->objtouch(wrk, oc, now);
491 26675
}
492
493
/*====================================================================
494
 * Utility functions which work on top of the previous ones
495
 */
496
497
int
498 396
ObjCopyAttr(struct worker *wrk, struct objcore *oc, struct objcore *ocs,
499
    enum obj_attr attr)
500
{
501
        const void *vps;
502
        void *vpd;
503
        ssize_t l;
504
505 396
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
506 396
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
507 396
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
508 396
        CHECK_OBJ_NOTNULL(ocs, OBJCORE_MAGIC);
509
510 396
        vps = ObjGetAttr(wrk, ocs, attr, &l);
511
        // XXX: later we want to have zero-length OA's too
512 396
        if (vps == NULL || l <= 0)
513 0
                return (-1);
514 396
        vpd = ObjSetAttr(wrk, oc, attr, l, vps);
515 396
        if (vpd == NULL)
516 0
                return (-1);
517 396
        return (0);
518
}
519
520
unsigned
521 17903
ObjGetXID(struct worker *wrk, struct objcore *oc)
522
{
523
        uint32_t u;
524
525 17903
        AZ(ObjGetU32(wrk, oc, OA_VXID, &u));
526 17904
        return (u);
527
}
528
529
/*--------------------------------------------------------------------
530
 * There is no well-defined byteorder for IEEE-754 double and the
531
 * correct solution (frexp(3) and manual encoding) is more work
532
 * than our (weak) goal of being endian-agnostic requires at this point.
533
 * We give it a shot by memcpy'ing doubles over a uint64_t and then
534
 * BE encode that.
535
 */
536
537
int
538 19619
ObjSetDouble(struct worker *wrk, struct objcore *oc, enum obj_attr a, double t)
539
{
540
        void *vp;
541
        uint64_t u;
542
543
        assert(sizeof t == sizeof u);
544 19619
        memcpy(&u, &t, sizeof u);
545 19619
        vp = ObjSetAttr(wrk, oc, a, sizeof u, NULL);
546 19620
        if (vp == NULL)
547 1
                return (-1);
548 19619
        vbe64enc(vp, u);
549 19619
        return (0);
550
}
551
552
int
553 24
ObjGetDouble(struct worker *wrk, struct objcore *oc, enum obj_attr a, double *d)
554
{
555
        const void *vp;
556
        uint64_t u;
557
        ssize_t l;
558
559
        assert(sizeof *d == sizeof u);
560 24
        vp = ObjGetAttr(wrk, oc, a, &l);
561 24
        if (vp == NULL)
562 0
                return (-1);
563 24
        if (d != NULL) {
564 24
                assert(l == sizeof u);
565 24
                u = vbe64dec(vp);
566 24
                memcpy(d, &u, sizeof *d);
567
        }
568 24
        return (0);
569
}
570
571
/*--------------------------------------------------------------------
572
 */
573
574
int
575 22188
ObjSetU64(struct worker *wrk, struct objcore *oc, enum obj_attr a, uint64_t t)
576
{
577
        void *vp;
578
579 22188
        vp = ObjSetAttr(wrk, oc, a, sizeof t, NULL);
580 22187
        if (vp == NULL)
581 0
                return (-1);
582 22187
        vbe64enc(vp, t);
583 22188
        return (0);
584
}
585
586
int
587 42188
ObjGetU64(struct worker *wrk, struct objcore *oc, enum obj_attr a, uint64_t *d)
588
{
589
        const void *vp;
590
        ssize_t l;
591
592 42188
        vp = ObjGetAttr(wrk, oc, a, &l);
593 42188
        if (vp == NULL || l != sizeof *d)
594 0
                return (-1);
595 42188
        if (d != NULL)
596 42188
                *d = vbe64dec(vp);
597 42187
        return (0);
598
}
599
600
int
601 19620
ObjSetU32(struct worker *wrk, struct objcore *oc, enum obj_attr a, uint32_t t)
602
{
603
        void *vp;
604
605 19620
        vp = ObjSetAttr(wrk, oc, a, sizeof t, NULL);
606 19619
        if (vp == NULL)
607 0
                return (-1);
608 19619
        vbe32enc(vp, t);
609 19619
        return (0);
610
}
611
612
int
613 17904
ObjGetU32(struct worker *wrk, struct objcore *oc, enum obj_attr a, uint32_t *d)
614
{
615
        const void *vp;
616
        ssize_t l;
617
618 17904
        vp = ObjGetAttr(wrk, oc, a, &l);
619 17904
        if (vp == NULL || l != sizeof *d)
620 0
                return (-1);
621 17904
        if (d != NULL)
622 17904
                *d = vbe32dec(vp);
623 17904
        return (0);
624
}
625
626
/*--------------------------------------------------------------------
627
 */
628
629
int
630 59062
ObjCheckFlag(struct worker *wrk, struct objcore *oc, enum obj_flags of)
631
{
632
        const uint8_t *fp;
633
634 59062
        fp = ObjGetAttr(wrk, oc, OA_FLAGS, NULL);
635 59064
        AN(fp);
636 59064
        return ((*fp) & of);
637
}
638
639
void
640 4092
ObjSetFlag(struct worker *wrk, struct objcore *oc, enum obj_flags of, int val)
641
{
642
        uint8_t *fp;
643
644 4092
        fp = ObjSetAttr(wrk, oc, OA_FLAGS, 1, NULL);
645 4092
        AN(fp);
646 4092
        if (val)
647 4092
                (*fp) |= of;
648
        else
649 0
                (*fp) &= ~of;
650 4092
}
651
652
/*====================================================================
653
 * Object event subscribtion mechanism.
654
 *
655
 * XXX: it is extremely unclear what the locking circumstances are here.
656
 */
657
658
struct oev_entry {
659
        unsigned                        magic;
660
#define OEV_MAGIC                       0xb0b7c5a1
661
        unsigned                        mask;
662
        obj_event_f                     *func;
663
        void                            *priv;
664
        VTAILQ_ENTRY(oev_entry)         list;
665
};
666
667
static VTAILQ_HEAD(,oev_entry)          oev_list;
668
static pthread_rwlock_t                 oev_rwl;
669
static unsigned                         oev_mask;
670
671
uintptr_t
672 468
ObjSubscribeEvents(obj_event_f *func, void *priv, unsigned mask)
673
{
674
        struct oev_entry *oev;
675
676 468
        AN(func);
677 468
        AZ(mask & ~OEV_MASK);
678
679 468
        ALLOC_OBJ(oev, OEV_MAGIC);
680 468
        AN(oev);
681 468
        oev->func = func;
682 468
        oev->priv = priv;
683 468
        oev->mask = mask;
684 468
        AZ(pthread_rwlock_wrlock(&oev_rwl));
685 468
        VTAILQ_INSERT_TAIL(&oev_list, oev, list);
686 468
        oev_mask |= mask;
687 468
        AZ(pthread_rwlock_unlock(&oev_rwl));
688 468
        return ((uintptr_t)oev);
689
}
690
691
void
692 12
ObjUnsubscribeEvents(uintptr_t *handle)
693
{
694 12
        struct oev_entry *oev, *oev2 = NULL;
695 12
        unsigned newmask = 0;
696
697 12
        AN(handle);
698 12
        AN(*handle);
699 12
        AZ(pthread_rwlock_wrlock(&oev_rwl));
700 24
        VTAILQ_FOREACH(oev, &oev_list, list) {
701 12
                CHECK_OBJ_NOTNULL(oev, OEV_MAGIC);
702 12
                if ((uintptr_t)oev == *handle)
703 12
                        oev2 = oev;
704
                else
705 0
                        newmask |= oev->mask;
706
        }
707 12
        AN(oev2);
708 12
        VTAILQ_REMOVE(&oev_list, oev2, list);
709 12
        oev_mask = newmask;
710 12
        AZ(newmask & ~OEV_MASK);
711 12
        AZ(pthread_rwlock_unlock(&oev_rwl));
712 12
        FREE_OBJ(oev2);
713 12
        *handle = 0;
714 12
}
715
716
void
717 30396
ObjSendEvent(struct worker *wrk, struct objcore *oc, unsigned event)
718
{
719
        struct oev_entry *oev;
720
721 30396
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
722 30396
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
723 30396
        AN(event & OEV_MASK);
724 30396
        AZ(event & ~OEV_MASK);
725 30396
        if (!(event & oev_mask))
726 29352
                return;
727
728 1044
        AZ(pthread_rwlock_rdlock(&oev_rwl));
729 2280
        VTAILQ_FOREACH(oev, &oev_list, list) {
730 1236
                CHECK_OBJ_NOTNULL(oev, OEV_MAGIC);
731 1236
                if (event & oev->mask)
732 1236
                        oev->func(wrk, oev->priv, oc, event);
733
        }
734 1044
        AZ(pthread_rwlock_unlock(&oev_rwl));
735
736
}
737
738
void
739 8220
ObjInit(void)
740
{
741 8220
        VTAILQ_INIT(&oev_list);
742 8220
        AZ(pthread_rwlock_init(&oev_rwl, NULL));
743 8220
}