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 void
48 1196           rinq_push (struct rinq **head, void *ref)
49             {
50             struct rinq *x;
51 1196 100         RINQ_NEW(x,ref);
    50          
52              
53 1196 100         if ((*head) == NULL) {
54 1144           (*head) = x;
55             }
56             else {
57 52           x->next = (*head);
58 52           x->prev = (*head)->prev;
59 52           x->next->prev = x->prev->next = x;
60             }
61 1196           }
62              
63             // remove element from head of rinq
64             INLINE_UNLESS_DEBUG
65             static void *
66 1253           rinq_shift (struct rinq **head) {
67             void *ref;
68             struct rinq *x;
69              
70 1253 100         if ((*head) == NULL) return NULL;
71              
72 1197 100         if (RINQ_IS_DETACHED((*head))) {
73 1144           x = (*head);
74 1144           (*head) = NULL;
75             }
76             else {
77 53           x = (*head);
78 53           (*head) = (*head)->next;
79 53           RINQ_DETACH(x);
80             }
81              
82 1197           ref = x->ref;
83 1197 50         RINQ_FREE(x);
84 1197           return ref;
85             }
86              
87             // remove element from anywhere in the rinq
88             INLINE_UNLESS_DEBUG
89             static void
90 24           rinq_remove (struct rinq **head, struct rinq *node)
91             {
92 24 50         if (*head == node) {
93 24 100         if (node->next == node) {
94 22           *head = NULL;
95             } else {
96 2           *head = node->next;
97             }
98             }
99 24           RINQ_DETACH(node);
100 24 50         RINQ_FREE(node);
101 24           }