Cleanup: Move headers from lib/ to include/lttng/
[lttng-modules.git] / lib / prio_heap / lttng_prio_heap.c
CommitLineData
9f36eaed
MJ
1/* SPDX-License-Identifier: MIT
2 *
a88db018 3 * lttng_prio_heap.c
162769ef 4 *
7369e702 5 * Priority heap containing pointers. Based on CLRS, chapter 6.
162769ef
MD
6 *
7 * Copyright 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
f3bc08c5
MD
8 */
9
10#include <linux/slab.h>
a071f25d 11#include <lttng/prio_heap.h>
48f5e0b5 12#include <wrapper/vmalloc.h>
f3bc08c5 13
0b6d2ab3 14#ifdef DEBUG_HEAP
a88db018 15void lttng_check_heap(const struct lttng_ptr_heap *heap)
0b6d2ab3
MD
16{
17 size_t i;
18
19 if (!heap->len)
20 return;
21
22 for (i = 1; i < heap->len; i++)
23 WARN_ON_ONCE(!heap->gt(heap->ptrs[i], heap->ptrs[0]));
24}
25#endif
26
a29e892a 27static
7369e702 28size_t parent(size_t i)
c9891db2 29{
0b6d2ab3 30 return (i -1) >> 1;
7369e702
MD
31}
32
33static
34size_t left(size_t i)
35{
0b6d2ab3 36 return (i << 1) + 1;
7369e702
MD
37}
38
39static
40size_t right(size_t i)
41{
0b6d2ab3 42 return (i << 1) + 2;
7369e702
MD
43}
44
a29e892a
MD
45/*
46 * Copy of heap->ptrs pointer is invalid after heap_grow.
47 */
7369e702 48static
a88db018 49int heap_grow(struct lttng_ptr_heap *heap, size_t new_len)
7369e702
MD
50{
51 void **new_ptrs;
52
53 if (heap->alloc_len >= new_len)
54 return 0;
55
56 heap->alloc_len = max_t(size_t, new_len, heap->alloc_len << 1);
48f5e0b5 57 new_ptrs = lttng_kvmalloc(heap->alloc_len * sizeof(void *), heap->gfpmask);
7369e702 58 if (!new_ptrs)
c9891db2 59 return -ENOMEM;
7369e702
MD
60 if (heap->ptrs)
61 memcpy(new_ptrs, heap->ptrs, heap->len * sizeof(void *));
48f5e0b5 62 lttng_kvfree(heap->ptrs);
7369e702
MD
63 heap->ptrs = new_ptrs;
64 return 0;
65}
66
67static
a88db018 68int heap_set_len(struct lttng_ptr_heap *heap, size_t new_len)
7369e702
MD
69{
70 int ret;
71
72 ret = heap_grow(heap, new_len);
73 if (ret)
74 return ret;
75 heap->len = new_len;
c9891db2
MD
76 return 0;
77}
78
a88db018 79int lttng_heap_init(struct lttng_ptr_heap *heap, size_t alloc_len,
7369e702
MD
80 gfp_t gfpmask, int gt(void *a, void *b))
81{
82 heap->ptrs = NULL;
83 heap->len = 0;
84 heap->alloc_len = 0;
85 heap->gt = gt;
ff77b142 86 heap->gfpmask = gfpmask;
7369e702
MD
87 /*
88 * Minimum size allocated is 1 entry to ensure memory allocation
89 * never fails within heap_replace_max.
90 */
c8d547f0 91 return heap_grow(heap, max_t(size_t, 1, alloc_len));
7369e702
MD
92}
93
a88db018 94void lttng_heap_free(struct lttng_ptr_heap *heap)
c9891db2 95{
48f5e0b5 96 lttng_kvfree(heap->ptrs);
c9891db2 97}
f3bc08c5 98
a88db018 99static void heapify(struct lttng_ptr_heap *heap, size_t i)
f3bc08c5 100{
7369e702
MD
101 void **ptrs = heap->ptrs;
102 size_t l, r, largest;
103
104 for (;;) {
0b6d2ab3
MD
105 void *tmp;
106
7369e702
MD
107 l = left(i);
108 r = right(i);
0b6d2ab3 109 if (l < heap->len && heap->gt(ptrs[l], ptrs[i]))
7369e702
MD
110 largest = l;
111 else
112 largest = i;
0b6d2ab3 113 if (r < heap->len && heap->gt(ptrs[r], ptrs[largest]))
7369e702 114 largest = r;
0b6d2ab3 115 if (largest == i)
7369e702 116 break;
0b6d2ab3
MD
117 tmp = ptrs[i];
118 ptrs[i] = ptrs[largest];
119 ptrs[largest] = tmp;
120 i = largest;
7369e702 121 }
a88db018 122 lttng_check_heap(heap);
f3bc08c5
MD
123}
124
a88db018 125void *lttng_heap_replace_max(struct lttng_ptr_heap *heap, void *p)
f3bc08c5
MD
126{
127 void *res;
f3bc08c5 128
7369e702
MD
129 if (!heap->len) {
130 (void) heap_set_len(heap, 1);
a29e892a 131 heap->ptrs[0] = p;
a88db018 132 lttng_check_heap(heap);
f3bc08c5
MD
133 return NULL;
134 }
135
136 /* Replace the current max and heapify */
a29e892a
MD
137 res = heap->ptrs[0];
138 heap->ptrs[0] = p;
f3bc08c5
MD
139 heapify(heap, 0);
140 return res;
141}
142
a88db018 143int lttng_heap_insert(struct lttng_ptr_heap *heap, void *p)
c9891db2 144{
a29e892a
MD
145 void **ptrs;
146 size_t pos;
7369e702 147 int ret;
c9891db2 148
7369e702
MD
149 ret = heap_set_len(heap, heap->len + 1);
150 if (ret)
151 return ret;
a29e892a 152 ptrs = heap->ptrs;
a29e892a 153 pos = heap->len - 1;
0b6d2ab3
MD
154 while (pos > 0 && heap->gt(p, ptrs[parent(pos)])) {
155 /* Move parent down until we find the right spot */
156 ptrs[pos] = ptrs[parent(pos)];
157 pos = parent(pos);
a29e892a 158 }
0b6d2ab3 159 ptrs[pos] = p;
a88db018 160 lttng_check_heap(heap);
7369e702 161 return 0;
c9891db2
MD
162}
163
a88db018 164void *lttng_heap_remove(struct lttng_ptr_heap *heap)
f3bc08c5 165{
7369e702 166 switch (heap->len) {
f3bc08c5
MD
167 case 0:
168 return NULL;
169 case 1:
7369e702 170 (void) heap_set_len(heap, 0);
a29e892a 171 return heap->ptrs[0];
f3bc08c5 172 }
f3bc08c5 173 /* Shrink, replace the current max by previous last entry and heapify */
7369e702 174 heap_set_len(heap, heap->len - 1);
0b6d2ab3 175 /* len changed. previous last entry is at heap->len */
a88db018 176 return lttng_heap_replace_max(heap, heap->ptrs[heap->len]);
f3bc08c5
MD
177}
178
a88db018 179void *lttng_heap_cherrypick(struct lttng_ptr_heap *heap, void *p)
f3bc08c5 180{
7369e702 181 size_t pos, len = heap->len;
f3bc08c5 182
7369e702 183 for (pos = 0; pos < len; pos++)
a29e892a 184 if (heap->ptrs[pos] == p)
f3bc08c5
MD
185 goto found;
186 return NULL;
187found:
7369e702
MD
188 if (heap->len == 1) {
189 (void) heap_set_len(heap, 0);
a88db018 190 lttng_check_heap(heap);
a29e892a 191 return heap->ptrs[0];
f3bc08c5 192 }
7369e702
MD
193 /* Replace p with previous last entry and heapify. */
194 heap_set_len(heap, heap->len - 1);
0b6d2ab3
MD
195 /* len changed. previous last entry is at heap->len */
196 heap->ptrs[pos] = heap->ptrs[heap->len];
f3bc08c5
MD
197 heapify(heap, pos);
198 return p;
199}
This page took 0.04536 seconds and 4 git commands to generate.