File Coverage

rinq.c
Criterion Covered Total %
statement 27 27 100.0
branch 14 18 77.7
condition n/a
subroutine n/a
pod n/a
total 41 45 91.1


line stmt bran cond sub pod time code
1              
2             // read "rinq" as "ring-queue"
3              
4             // Free list for recycling rinq nodes (avoids malloc/free per node)
5             //
6             // Sizing rationale: 64 entries (2x iomatrix/feer_req caches) because rinq
7             // nodes are much smaller (~24 bytes each), so 64 entries = ~1.5KB cache.
8             // Higher count handles write buffer fragmentation during high concurrency.
9             #define RINQ_FREELIST_MAX 64
10             static struct rinq *rinq_freelist = NULL;
11             static int rinq_freelist_count = 0;
12              
13             #define RINQ_IS_DETACHED(x_) ((x_)->next == (x_))
14              
15             // Allocate a rinq node, preferring the free list over malloc
16             #define RINQ_NEW(x_,ref_) do { \
17             if (rinq_freelist != NULL) { \
18             x_ = rinq_freelist; \
19             rinq_freelist = rinq_freelist->next; \
20             rinq_freelist_count--; \
21             } else { \
22             x_ = (struct rinq *)malloc(sizeof(struct rinq)); \
23             if (unlikely(!x_)) croak("Out of memory in rinq"); \
24             } \
25             x_->next = x_->prev = x_; \
26             x_->ref = ref_; \
27             } while(0)
28              
29             // Return a rinq node to the free list
30             #define RINQ_FREE(x_) do { \
31             if (rinq_freelist_count < RINQ_FREELIST_MAX) { \
32             (x_)->next = rinq_freelist; \
33             rinq_freelist = (x_); \
34             rinq_freelist_count++; \
35             } else { \
36             free(x_); \
37             } \
38             } while(0)
39              
40             #define RINQ_DETACH(x_) do { \
41             (x_)->next->prev = (x_)->prev; \
42             (x_)->prev->next = (x_)->next; \
43             (x_)->next = (x_)->prev = (x_); \
44             } while(0)
45              
46             INLINE_UNLESS_DEBUG
47             static struct rinq *
48 1369           rinq_push (struct rinq **head, void *ref)
49             {
50             struct rinq *x;
51 1369 100         RINQ_NEW(x,ref);
    50          
52              
53 1369 100         if ((*head) == NULL) {
54 1306           (*head) = x;
55             }
56             else {
57 63           x->next = (*head);
58 63           x->prev = (*head)->prev;
59 63           x->next->prev = x->prev->next = x;
60             }
61 1369           return x;
62             }
63              
64             // remove element from head of rinq
65             INLINE_UNLESS_DEBUG
66             static void *
67 1395           rinq_shift (struct rinq **head) {
68             void *ref;
69             struct rinq *x;
70              
71 1395 100         if ((*head) == NULL) return NULL;
72              
73 1335 100         if (RINQ_IS_DETACHED((*head))) {
74 1275           x = (*head);
75 1275           (*head) = NULL;
76             }
77             else {
78 60           x = (*head);
79 60           (*head) = (*head)->next;
80 60           RINQ_DETACH(x);
81             }
82              
83 1335           ref = x->ref;
84 1335 50         RINQ_FREE(x);
85 1335           return ref;
86             }
87              
88             // remove element from anywhere in the rinq
89             INLINE_UNLESS_DEBUG
90             static void
91 34           rinq_remove (struct rinq **head, struct rinq *node)
92             {
93 34 50         if (*head == node) {
94 34 100         if (node->next == node) {
95 31           *head = NULL;
96             } else {
97 3           *head = node->next;
98             }
99             }
100 34           RINQ_DETACH(node);
101 34 50         RINQ_FREE(node);
102 34           }