Add missing MIT license text to 3 files under this license
[lttng-modules.git] / lib / prio_heap / lttng_prio_heap.c
CommitLineData
f3bc08c5 1/*
a88db018 2 * lttng_prio_heap.c
162769ef 3 *
7369e702 4 * Priority heap containing pointers. Based on CLRS, chapter 6.
162769ef
MD
5 *
6 * Copyright 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
5fd8c00a
MD
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
f3bc08c5
MD
25 */
26
27#include <linux/slab.h>
a88db018 28#include "lttng_prio_heap.h"
f3bc08c5 29
0b6d2ab3 30#ifdef DEBUG_HEAP
a88db018 31void lttng_check_heap(const struct lttng_ptr_heap *heap)
0b6d2ab3
MD
32{
33 size_t i;
34
35 if (!heap->len)
36 return;
37
38 for (i = 1; i < heap->len; i++)
39 WARN_ON_ONCE(!heap->gt(heap->ptrs[i], heap->ptrs[0]));
40}
41#endif
42
a29e892a 43static
7369e702 44size_t parent(size_t i)
c9891db2 45{
0b6d2ab3 46 return (i -1) >> 1;
7369e702
MD
47}
48
49static
50size_t left(size_t i)
51{
0b6d2ab3 52 return (i << 1) + 1;
7369e702
MD
53}
54
55static
56size_t right(size_t i)
57{
0b6d2ab3 58 return (i << 1) + 2;
7369e702
MD
59}
60
a29e892a
MD
61/*
62 * Copy of heap->ptrs pointer is invalid after heap_grow.
63 */
7369e702 64static
a88db018 65int heap_grow(struct lttng_ptr_heap *heap, size_t new_len)
7369e702
MD
66{
67 void **new_ptrs;
68
69 if (heap->alloc_len >= new_len)
70 return 0;
71
72 heap->alloc_len = max_t(size_t, new_len, heap->alloc_len << 1);
73 new_ptrs = kmalloc(heap->alloc_len * sizeof(void *), heap->gfpmask);
74 if (!new_ptrs)
c9891db2 75 return -ENOMEM;
7369e702
MD
76 if (heap->ptrs)
77 memcpy(new_ptrs, heap->ptrs, heap->len * sizeof(void *));
78 kfree(heap->ptrs);
79 heap->ptrs = new_ptrs;
80 return 0;
81}
82
83static
a88db018 84int heap_set_len(struct lttng_ptr_heap *heap, size_t new_len)
7369e702
MD
85{
86 int ret;
87
88 ret = heap_grow(heap, new_len);
89 if (ret)
90 return ret;
91 heap->len = new_len;
c9891db2
MD
92 return 0;
93}
94
a88db018 95int lttng_heap_init(struct lttng_ptr_heap *heap, size_t alloc_len,
7369e702
MD
96 gfp_t gfpmask, int gt(void *a, void *b))
97{
98 heap->ptrs = NULL;
99 heap->len = 0;
100 heap->alloc_len = 0;
101 heap->gt = gt;
ff77b142 102 heap->gfpmask = gfpmask;
7369e702
MD
103 /*
104 * Minimum size allocated is 1 entry to ensure memory allocation
105 * never fails within heap_replace_max.
106 */
c8d547f0 107 return heap_grow(heap, max_t(size_t, 1, alloc_len));
7369e702
MD
108}
109
a88db018 110void lttng_heap_free(struct lttng_ptr_heap *heap)
c9891db2
MD
111{
112 kfree(heap->ptrs);
113}
f3bc08c5 114
a88db018 115static void heapify(struct lttng_ptr_heap *heap, size_t i)
f3bc08c5 116{
7369e702
MD
117 void **ptrs = heap->ptrs;
118 size_t l, r, largest;
119
120 for (;;) {
0b6d2ab3
MD
121 void *tmp;
122
7369e702
MD
123 l = left(i);
124 r = right(i);
0b6d2ab3 125 if (l < heap->len && heap->gt(ptrs[l], ptrs[i]))
7369e702
MD
126 largest = l;
127 else
128 largest = i;
0b6d2ab3 129 if (r < heap->len && heap->gt(ptrs[r], ptrs[largest]))
7369e702 130 largest = r;
0b6d2ab3 131 if (largest == i)
7369e702 132 break;
0b6d2ab3
MD
133 tmp = ptrs[i];
134 ptrs[i] = ptrs[largest];
135 ptrs[largest] = tmp;
136 i = largest;
7369e702 137 }
a88db018 138 lttng_check_heap(heap);
f3bc08c5
MD
139}
140
a88db018 141void *lttng_heap_replace_max(struct lttng_ptr_heap *heap, void *p)
f3bc08c5
MD
142{
143 void *res;
f3bc08c5 144
7369e702
MD
145 if (!heap->len) {
146 (void) heap_set_len(heap, 1);
a29e892a 147 heap->ptrs[0] = p;
a88db018 148 lttng_check_heap(heap);
f3bc08c5
MD
149 return NULL;
150 }
151
152 /* Replace the current max and heapify */
a29e892a
MD
153 res = heap->ptrs[0];
154 heap->ptrs[0] = p;
f3bc08c5
MD
155 heapify(heap, 0);
156 return res;
157}
158
a88db018 159int lttng_heap_insert(struct lttng_ptr_heap *heap, void *p)
c9891db2 160{
a29e892a
MD
161 void **ptrs;
162 size_t pos;
7369e702 163 int ret;
c9891db2 164
7369e702
MD
165 ret = heap_set_len(heap, heap->len + 1);
166 if (ret)
167 return ret;
a29e892a 168 ptrs = heap->ptrs;
a29e892a 169 pos = heap->len - 1;
0b6d2ab3
MD
170 while (pos > 0 && heap->gt(p, ptrs[parent(pos)])) {
171 /* Move parent down until we find the right spot */
172 ptrs[pos] = ptrs[parent(pos)];
173 pos = parent(pos);
a29e892a 174 }
0b6d2ab3 175 ptrs[pos] = p;
a88db018 176 lttng_check_heap(heap);
7369e702 177 return 0;
c9891db2
MD
178}
179
a88db018 180void *lttng_heap_remove(struct lttng_ptr_heap *heap)
f3bc08c5 181{
7369e702 182 switch (heap->len) {
f3bc08c5
MD
183 case 0:
184 return NULL;
185 case 1:
7369e702 186 (void) heap_set_len(heap, 0);
a29e892a 187 return heap->ptrs[0];
f3bc08c5 188 }
f3bc08c5 189 /* Shrink, replace the current max by previous last entry and heapify */
7369e702 190 heap_set_len(heap, heap->len - 1);
0b6d2ab3 191 /* len changed. previous last entry is at heap->len */
a88db018 192 return lttng_heap_replace_max(heap, heap->ptrs[heap->len]);
f3bc08c5
MD
193}
194
a88db018 195void *lttng_heap_cherrypick(struct lttng_ptr_heap *heap, void *p)
f3bc08c5 196{
7369e702 197 size_t pos, len = heap->len;
f3bc08c5 198
7369e702 199 for (pos = 0; pos < len; pos++)
a29e892a 200 if (heap->ptrs[pos] == p)
f3bc08c5
MD
201 goto found;
202 return NULL;
203found:
7369e702
MD
204 if (heap->len == 1) {
205 (void) heap_set_len(heap, 0);
a88db018 206 lttng_check_heap(heap);
a29e892a 207 return heap->ptrs[0];
f3bc08c5 208 }
7369e702
MD
209 /* Replace p with previous last entry and heapify. */
210 heap_set_len(heap, heap->len - 1);
0b6d2ab3
MD
211 /* len changed. previous last entry is at heap->len */
212 heap->ptrs[pos] = heap->ptrs[heap->len];
f3bc08c5
MD
213 heapify(heap, pos);
214 return p;
215}
This page took 0.035825 seconds and 4 git commands to generate.