1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright © 2019 Intel Corporation
3*61046927SAndroid Build Coastguard Worker *
4*61046927SAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining a
5*61046927SAndroid Build Coastguard Worker * copy of this software and associated documentation files (the "Software"),
6*61046927SAndroid Build Coastguard Worker * to deal in the Software without restriction, including without limitation
7*61046927SAndroid Build Coastguard Worker * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*61046927SAndroid Build Coastguard Worker * and/or sell copies of the Software, and to permit persons to whom the
9*61046927SAndroid Build Coastguard Worker * Software is furnished to do so, subject to the following conditions:
10*61046927SAndroid Build Coastguard Worker *
11*61046927SAndroid Build Coastguard Worker * The above copyright notice and this permission notice (including the next
12*61046927SAndroid Build Coastguard Worker * paragraph) shall be included in all copies or substantial portions of the
13*61046927SAndroid Build Coastguard Worker * Software.
14*61046927SAndroid Build Coastguard Worker *
15*61046927SAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*61046927SAndroid Build Coastguard Worker * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*61046927SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18*61046927SAndroid Build Coastguard Worker * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*61046927SAndroid Build Coastguard Worker * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*61046927SAndroid Build Coastguard Worker * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21*61046927SAndroid Build Coastguard Worker * IN THE SOFTWARE.
22*61046927SAndroid Build Coastguard Worker */
23*61046927SAndroid Build Coastguard Worker
24*61046927SAndroid Build Coastguard Worker #include "sparse_array.h"
25*61046927SAndroid Build Coastguard Worker #include "os_memory.h"
26*61046927SAndroid Build Coastguard Worker
27*61046927SAndroid Build Coastguard Worker /* Aligning our allocations to 64 has two advantages:
28*61046927SAndroid Build Coastguard Worker *
29*61046927SAndroid Build Coastguard Worker * 1. On x86 platforms, it means that they are cache-line aligned so we
30*61046927SAndroid Build Coastguard Worker * reduce the likelihood that one of our allocations shares a cache line
31*61046927SAndroid Build Coastguard Worker * with some other allocation.
32*61046927SAndroid Build Coastguard Worker *
33*61046927SAndroid Build Coastguard Worker * 2. It lets us use the bottom 6 bits of the pointer to store the tree level
34*61046927SAndroid Build Coastguard Worker * of the node so we can avoid some pointer indirections.
35*61046927SAndroid Build Coastguard Worker */
36*61046927SAndroid Build Coastguard Worker #define NODE_ALLOC_ALIGN 64
37*61046927SAndroid Build Coastguard Worker
38*61046927SAndroid Build Coastguard Worker void
util_sparse_array_init(struct util_sparse_array * arr,size_t elem_size,size_t node_size)39*61046927SAndroid Build Coastguard Worker util_sparse_array_init(struct util_sparse_array *arr,
40*61046927SAndroid Build Coastguard Worker size_t elem_size, size_t node_size)
41*61046927SAndroid Build Coastguard Worker {
42*61046927SAndroid Build Coastguard Worker memset(arr, 0, sizeof(*arr));
43*61046927SAndroid Build Coastguard Worker arr->elem_size = elem_size;
44*61046927SAndroid Build Coastguard Worker arr->node_size_log2 = util_logbase2_64(node_size);
45*61046927SAndroid Build Coastguard Worker assert(node_size >= 2 && node_size == (1ull << arr->node_size_log2));
46*61046927SAndroid Build Coastguard Worker }
47*61046927SAndroid Build Coastguard Worker
48*61046927SAndroid Build Coastguard Worker #define NODE_PTR_MASK (~((uintptr_t)NODE_ALLOC_ALIGN - 1))
49*61046927SAndroid Build Coastguard Worker #define NODE_LEVEL_MASK ((uintptr_t)NODE_ALLOC_ALIGN - 1)
50*61046927SAndroid Build Coastguard Worker #define NULL_NODE 0
51*61046927SAndroid Build Coastguard Worker
52*61046927SAndroid Build Coastguard Worker static inline uintptr_t
_util_sparse_array_node(void * data,unsigned level)53*61046927SAndroid Build Coastguard Worker _util_sparse_array_node(void *data, unsigned level)
54*61046927SAndroid Build Coastguard Worker {
55*61046927SAndroid Build Coastguard Worker assert(data != NULL);
56*61046927SAndroid Build Coastguard Worker assert(((uintptr_t)data & NODE_LEVEL_MASK) == 0);
57*61046927SAndroid Build Coastguard Worker assert((level & NODE_PTR_MASK) == 0);
58*61046927SAndroid Build Coastguard Worker return (uintptr_t)data | level;
59*61046927SAndroid Build Coastguard Worker }
60*61046927SAndroid Build Coastguard Worker
61*61046927SAndroid Build Coastguard Worker static inline void *
_util_sparse_array_node_data(uintptr_t handle)62*61046927SAndroid Build Coastguard Worker _util_sparse_array_node_data(uintptr_t handle)
63*61046927SAndroid Build Coastguard Worker {
64*61046927SAndroid Build Coastguard Worker return (void *)(handle & NODE_PTR_MASK);
65*61046927SAndroid Build Coastguard Worker }
66*61046927SAndroid Build Coastguard Worker
67*61046927SAndroid Build Coastguard Worker static inline unsigned
_util_sparse_array_node_level(uintptr_t handle)68*61046927SAndroid Build Coastguard Worker _util_sparse_array_node_level(uintptr_t handle)
69*61046927SAndroid Build Coastguard Worker {
70*61046927SAndroid Build Coastguard Worker return handle & NODE_LEVEL_MASK;
71*61046927SAndroid Build Coastguard Worker }
72*61046927SAndroid Build Coastguard Worker
73*61046927SAndroid Build Coastguard Worker static inline void
_util_sparse_array_node_finish(struct util_sparse_array * arr,uintptr_t node)74*61046927SAndroid Build Coastguard Worker _util_sparse_array_node_finish(struct util_sparse_array *arr,
75*61046927SAndroid Build Coastguard Worker uintptr_t node)
76*61046927SAndroid Build Coastguard Worker {
77*61046927SAndroid Build Coastguard Worker if (_util_sparse_array_node_level(node) > 0) {
78*61046927SAndroid Build Coastguard Worker uintptr_t *children = _util_sparse_array_node_data(node);
79*61046927SAndroid Build Coastguard Worker size_t node_size = 1ull << arr->node_size_log2;
80*61046927SAndroid Build Coastguard Worker for (size_t i = 0; i < node_size; i++) {
81*61046927SAndroid Build Coastguard Worker if (children[i])
82*61046927SAndroid Build Coastguard Worker _util_sparse_array_node_finish(arr, children[i]);
83*61046927SAndroid Build Coastguard Worker }
84*61046927SAndroid Build Coastguard Worker }
85*61046927SAndroid Build Coastguard Worker
86*61046927SAndroid Build Coastguard Worker os_free_aligned(_util_sparse_array_node_data(node));
87*61046927SAndroid Build Coastguard Worker }
88*61046927SAndroid Build Coastguard Worker
89*61046927SAndroid Build Coastguard Worker void
util_sparse_array_finish(struct util_sparse_array * arr)90*61046927SAndroid Build Coastguard Worker util_sparse_array_finish(struct util_sparse_array *arr)
91*61046927SAndroid Build Coastguard Worker {
92*61046927SAndroid Build Coastguard Worker if (arr->root)
93*61046927SAndroid Build Coastguard Worker _util_sparse_array_node_finish(arr, arr->root);
94*61046927SAndroid Build Coastguard Worker }
95*61046927SAndroid Build Coastguard Worker
96*61046927SAndroid Build Coastguard Worker static inline uintptr_t
_util_sparse_array_node_alloc(struct util_sparse_array * arr,unsigned level)97*61046927SAndroid Build Coastguard Worker _util_sparse_array_node_alloc(struct util_sparse_array *arr,
98*61046927SAndroid Build Coastguard Worker unsigned level)
99*61046927SAndroid Build Coastguard Worker {
100*61046927SAndroid Build Coastguard Worker size_t size;
101*61046927SAndroid Build Coastguard Worker if (level == 0) {
102*61046927SAndroid Build Coastguard Worker size = arr->elem_size << arr->node_size_log2;
103*61046927SAndroid Build Coastguard Worker } else {
104*61046927SAndroid Build Coastguard Worker size = sizeof(uintptr_t) << arr->node_size_log2;
105*61046927SAndroid Build Coastguard Worker }
106*61046927SAndroid Build Coastguard Worker
107*61046927SAndroid Build Coastguard Worker void *data = os_malloc_aligned(size, NODE_ALLOC_ALIGN);
108*61046927SAndroid Build Coastguard Worker memset(data, 0, size);
109*61046927SAndroid Build Coastguard Worker
110*61046927SAndroid Build Coastguard Worker return _util_sparse_array_node(data, level);
111*61046927SAndroid Build Coastguard Worker }
112*61046927SAndroid Build Coastguard Worker
113*61046927SAndroid Build Coastguard Worker static inline uintptr_t
_util_sparse_array_set_or_free_node(uintptr_t * node_ptr,uintptr_t cmp_node,uintptr_t node)114*61046927SAndroid Build Coastguard Worker _util_sparse_array_set_or_free_node(uintptr_t *node_ptr,
115*61046927SAndroid Build Coastguard Worker uintptr_t cmp_node,
116*61046927SAndroid Build Coastguard Worker uintptr_t node)
117*61046927SAndroid Build Coastguard Worker {
118*61046927SAndroid Build Coastguard Worker uintptr_t prev_node = p_atomic_cmpxchg(node_ptr, cmp_node, node);
119*61046927SAndroid Build Coastguard Worker
120*61046927SAndroid Build Coastguard Worker if (prev_node != cmp_node) {
121*61046927SAndroid Build Coastguard Worker /* We lost the race. Free this one and return the one that was already
122*61046927SAndroid Build Coastguard Worker * allocated.
123*61046927SAndroid Build Coastguard Worker */
124*61046927SAndroid Build Coastguard Worker os_free_aligned(_util_sparse_array_node_data(node));
125*61046927SAndroid Build Coastguard Worker return prev_node;
126*61046927SAndroid Build Coastguard Worker } else {
127*61046927SAndroid Build Coastguard Worker return node;
128*61046927SAndroid Build Coastguard Worker }
129*61046927SAndroid Build Coastguard Worker }
130*61046927SAndroid Build Coastguard Worker
131*61046927SAndroid Build Coastguard Worker void *
util_sparse_array_get(struct util_sparse_array * arr,uint64_t idx)132*61046927SAndroid Build Coastguard Worker util_sparse_array_get(struct util_sparse_array *arr, uint64_t idx)
133*61046927SAndroid Build Coastguard Worker {
134*61046927SAndroid Build Coastguard Worker const unsigned node_size_log2 = arr->node_size_log2;
135*61046927SAndroid Build Coastguard Worker uintptr_t root = p_atomic_read(&arr->root);
136*61046927SAndroid Build Coastguard Worker if (unlikely(!root)) {
137*61046927SAndroid Build Coastguard Worker unsigned root_level = 0;
138*61046927SAndroid Build Coastguard Worker uint64_t idx_iter = idx >> node_size_log2;
139*61046927SAndroid Build Coastguard Worker while (idx_iter) {
140*61046927SAndroid Build Coastguard Worker idx_iter >>= node_size_log2;
141*61046927SAndroid Build Coastguard Worker root_level++;
142*61046927SAndroid Build Coastguard Worker }
143*61046927SAndroid Build Coastguard Worker uintptr_t new_root = _util_sparse_array_node_alloc(arr, root_level);
144*61046927SAndroid Build Coastguard Worker root = _util_sparse_array_set_or_free_node(&arr->root,
145*61046927SAndroid Build Coastguard Worker NULL_NODE, new_root);
146*61046927SAndroid Build Coastguard Worker }
147*61046927SAndroid Build Coastguard Worker
148*61046927SAndroid Build Coastguard Worker while (1) {
149*61046927SAndroid Build Coastguard Worker unsigned root_level = _util_sparse_array_node_level(root);
150*61046927SAndroid Build Coastguard Worker uint64_t root_idx = idx >> (root_level * node_size_log2);
151*61046927SAndroid Build Coastguard Worker if (likely(root_idx < (1ull << node_size_log2)))
152*61046927SAndroid Build Coastguard Worker break;
153*61046927SAndroid Build Coastguard Worker
154*61046927SAndroid Build Coastguard Worker /* In this case, we have a root but its level is low enough that the
155*61046927SAndroid Build Coastguard Worker * requested index is out-of-bounds.
156*61046927SAndroid Build Coastguard Worker */
157*61046927SAndroid Build Coastguard Worker uintptr_t new_root = _util_sparse_array_node_alloc(arr, root_level + 1);
158*61046927SAndroid Build Coastguard Worker
159*61046927SAndroid Build Coastguard Worker uintptr_t *new_root_children = _util_sparse_array_node_data(new_root);
160*61046927SAndroid Build Coastguard Worker new_root_children[0] = root;
161*61046927SAndroid Build Coastguard Worker
162*61046927SAndroid Build Coastguard Worker /* We only add one at a time instead of the whole tree because it's
163*61046927SAndroid Build Coastguard Worker * easier to ensure correctness of both the tree building and the
164*61046927SAndroid Build Coastguard Worker * clean-up path. Because we're only adding one node we never have to
165*61046927SAndroid Build Coastguard Worker * worry about trying to free multiple things without freeing the old
166*61046927SAndroid Build Coastguard Worker * things.
167*61046927SAndroid Build Coastguard Worker */
168*61046927SAndroid Build Coastguard Worker root = _util_sparse_array_set_or_free_node(&arr->root, root, new_root);
169*61046927SAndroid Build Coastguard Worker }
170*61046927SAndroid Build Coastguard Worker
171*61046927SAndroid Build Coastguard Worker void *node_data = _util_sparse_array_node_data(root);
172*61046927SAndroid Build Coastguard Worker unsigned node_level = _util_sparse_array_node_level(root);
173*61046927SAndroid Build Coastguard Worker while (node_level > 0) {
174*61046927SAndroid Build Coastguard Worker uint64_t child_idx = (idx >> (node_level * node_size_log2)) &
175*61046927SAndroid Build Coastguard Worker ((1ull << node_size_log2) - 1);
176*61046927SAndroid Build Coastguard Worker
177*61046927SAndroid Build Coastguard Worker uintptr_t *children = node_data;
178*61046927SAndroid Build Coastguard Worker uintptr_t child = p_atomic_read(&children[child_idx]);
179*61046927SAndroid Build Coastguard Worker
180*61046927SAndroid Build Coastguard Worker if (unlikely(!child)) {
181*61046927SAndroid Build Coastguard Worker child = _util_sparse_array_node_alloc(arr, node_level - 1);
182*61046927SAndroid Build Coastguard Worker child = _util_sparse_array_set_or_free_node(&children[child_idx],
183*61046927SAndroid Build Coastguard Worker NULL_NODE, child);
184*61046927SAndroid Build Coastguard Worker }
185*61046927SAndroid Build Coastguard Worker
186*61046927SAndroid Build Coastguard Worker node_data = _util_sparse_array_node_data(child);
187*61046927SAndroid Build Coastguard Worker node_level = _util_sparse_array_node_level(child);
188*61046927SAndroid Build Coastguard Worker }
189*61046927SAndroid Build Coastguard Worker
190*61046927SAndroid Build Coastguard Worker uint64_t elem_idx = idx & ((1ull << node_size_log2) - 1);
191*61046927SAndroid Build Coastguard Worker return (void *)((char *)node_data + (elem_idx * arr->elem_size));
192*61046927SAndroid Build Coastguard Worker }
193*61046927SAndroid Build Coastguard Worker
194*61046927SAndroid Build Coastguard Worker static void
validate_node_level(struct util_sparse_array * arr,uintptr_t node,unsigned level)195*61046927SAndroid Build Coastguard Worker validate_node_level(struct util_sparse_array *arr,
196*61046927SAndroid Build Coastguard Worker uintptr_t node, unsigned level)
197*61046927SAndroid Build Coastguard Worker {
198*61046927SAndroid Build Coastguard Worker assert(_util_sparse_array_node_level(node) == level);
199*61046927SAndroid Build Coastguard Worker
200*61046927SAndroid Build Coastguard Worker if (_util_sparse_array_node_level(node) > 0) {
201*61046927SAndroid Build Coastguard Worker uintptr_t *children = _util_sparse_array_node_data(node);
202*61046927SAndroid Build Coastguard Worker size_t node_size = 1ull << arr->node_size_log2;
203*61046927SAndroid Build Coastguard Worker for (size_t i = 0; i < node_size; i++) {
204*61046927SAndroid Build Coastguard Worker if (children[i])
205*61046927SAndroid Build Coastguard Worker validate_node_level(arr, children[i], level - 1);
206*61046927SAndroid Build Coastguard Worker }
207*61046927SAndroid Build Coastguard Worker }
208*61046927SAndroid Build Coastguard Worker }
209*61046927SAndroid Build Coastguard Worker
210*61046927SAndroid Build Coastguard Worker void
util_sparse_array_validate(struct util_sparse_array * arr)211*61046927SAndroid Build Coastguard Worker util_sparse_array_validate(struct util_sparse_array *arr)
212*61046927SAndroid Build Coastguard Worker {
213*61046927SAndroid Build Coastguard Worker uintptr_t root = p_atomic_read(&arr->root);
214*61046927SAndroid Build Coastguard Worker validate_node_level(arr, root, _util_sparse_array_node_level(root));
215*61046927SAndroid Build Coastguard Worker }
216*61046927SAndroid Build Coastguard Worker
217*61046927SAndroid Build Coastguard Worker void
util_sparse_array_free_list_init(struct util_sparse_array_free_list * fl,struct util_sparse_array * arr,uint32_t sentinel,uint32_t next_offset)218*61046927SAndroid Build Coastguard Worker util_sparse_array_free_list_init(struct util_sparse_array_free_list *fl,
219*61046927SAndroid Build Coastguard Worker struct util_sparse_array *arr,
220*61046927SAndroid Build Coastguard Worker uint32_t sentinel,
221*61046927SAndroid Build Coastguard Worker uint32_t next_offset)
222*61046927SAndroid Build Coastguard Worker {
223*61046927SAndroid Build Coastguard Worker fl->head = sentinel;
224*61046927SAndroid Build Coastguard Worker fl->arr = arr;
225*61046927SAndroid Build Coastguard Worker fl->sentinel = sentinel;
226*61046927SAndroid Build Coastguard Worker fl->next_offset = next_offset;
227*61046927SAndroid Build Coastguard Worker }
228*61046927SAndroid Build Coastguard Worker
229*61046927SAndroid Build Coastguard Worker static uint64_t
free_list_head(uint64_t old,uint32_t next)230*61046927SAndroid Build Coastguard Worker free_list_head(uint64_t old, uint32_t next)
231*61046927SAndroid Build Coastguard Worker {
232*61046927SAndroid Build Coastguard Worker return ((old & 0xffffffff00000000ull) + 0x100000000ull) | next;
233*61046927SAndroid Build Coastguard Worker }
234*61046927SAndroid Build Coastguard Worker
235*61046927SAndroid Build Coastguard Worker void
util_sparse_array_free_list_push(struct util_sparse_array_free_list * fl,uint32_t * items,unsigned num_items)236*61046927SAndroid Build Coastguard Worker util_sparse_array_free_list_push(struct util_sparse_array_free_list *fl,
237*61046927SAndroid Build Coastguard Worker uint32_t *items, unsigned num_items)
238*61046927SAndroid Build Coastguard Worker {
239*61046927SAndroid Build Coastguard Worker assert(num_items > 0);
240*61046927SAndroid Build Coastguard Worker assert(items[0] != fl->sentinel);
241*61046927SAndroid Build Coastguard Worker void *last_elem = util_sparse_array_get(fl->arr, items[0]);
242*61046927SAndroid Build Coastguard Worker uint32_t *last_next = (uint32_t *)((char *)last_elem + fl->next_offset);
243*61046927SAndroid Build Coastguard Worker for (unsigned i = 1; i < num_items; i++) {
244*61046927SAndroid Build Coastguard Worker p_atomic_set(last_next, items[i]);
245*61046927SAndroid Build Coastguard Worker assert(items[i] != fl->sentinel);
246*61046927SAndroid Build Coastguard Worker last_elem = util_sparse_array_get(fl->arr, items[i]);
247*61046927SAndroid Build Coastguard Worker last_next = (uint32_t *)((char *)last_elem + fl->next_offset);
248*61046927SAndroid Build Coastguard Worker }
249*61046927SAndroid Build Coastguard Worker
250*61046927SAndroid Build Coastguard Worker uint64_t current_head, old_head;
251*61046927SAndroid Build Coastguard Worker old_head = p_atomic_read(&fl->head);
252*61046927SAndroid Build Coastguard Worker do {
253*61046927SAndroid Build Coastguard Worker current_head = old_head;
254*61046927SAndroid Build Coastguard Worker p_atomic_set(last_next, (uint32_t)current_head); /* Index is the bottom 32 bits */
255*61046927SAndroid Build Coastguard Worker uint64_t new_head = free_list_head(current_head, items[0]);
256*61046927SAndroid Build Coastguard Worker old_head = p_atomic_cmpxchg(&fl->head, current_head, new_head);
257*61046927SAndroid Build Coastguard Worker } while (old_head != current_head);
258*61046927SAndroid Build Coastguard Worker }
259*61046927SAndroid Build Coastguard Worker
260*61046927SAndroid Build Coastguard Worker uint32_t
util_sparse_array_free_list_pop_idx(struct util_sparse_array_free_list * fl)261*61046927SAndroid Build Coastguard Worker util_sparse_array_free_list_pop_idx(struct util_sparse_array_free_list *fl)
262*61046927SAndroid Build Coastguard Worker {
263*61046927SAndroid Build Coastguard Worker uint64_t current_head;
264*61046927SAndroid Build Coastguard Worker
265*61046927SAndroid Build Coastguard Worker current_head = p_atomic_read(&fl->head);
266*61046927SAndroid Build Coastguard Worker while (1) {
267*61046927SAndroid Build Coastguard Worker if ((uint32_t)current_head == fl->sentinel)
268*61046927SAndroid Build Coastguard Worker return fl->sentinel;
269*61046927SAndroid Build Coastguard Worker
270*61046927SAndroid Build Coastguard Worker uint32_t head_idx = current_head; /* Index is the bottom 32 bits */
271*61046927SAndroid Build Coastguard Worker void *head_elem = util_sparse_array_get(fl->arr, head_idx);
272*61046927SAndroid Build Coastguard Worker uint32_t *head_next = (uint32_t *)((char *)head_elem + fl->next_offset);
273*61046927SAndroid Build Coastguard Worker uint64_t new_head = free_list_head(current_head, p_atomic_read(head_next));
274*61046927SAndroid Build Coastguard Worker uint64_t old_head = p_atomic_cmpxchg(&fl->head, current_head, new_head);
275*61046927SAndroid Build Coastguard Worker if (old_head == current_head)
276*61046927SAndroid Build Coastguard Worker return head_idx;
277*61046927SAndroid Build Coastguard Worker current_head = old_head;
278*61046927SAndroid Build Coastguard Worker }
279*61046927SAndroid Build Coastguard Worker }
280*61046927SAndroid Build Coastguard Worker
281*61046927SAndroid Build Coastguard Worker void *
util_sparse_array_free_list_pop_elem(struct util_sparse_array_free_list * fl)282*61046927SAndroid Build Coastguard Worker util_sparse_array_free_list_pop_elem(struct util_sparse_array_free_list *fl)
283*61046927SAndroid Build Coastguard Worker {
284*61046927SAndroid Build Coastguard Worker uint64_t current_head;
285*61046927SAndroid Build Coastguard Worker
286*61046927SAndroid Build Coastguard Worker current_head = p_atomic_read(&fl->head);
287*61046927SAndroid Build Coastguard Worker while (1) {
288*61046927SAndroid Build Coastguard Worker if ((uint32_t)current_head == fl->sentinel)
289*61046927SAndroid Build Coastguard Worker return NULL;
290*61046927SAndroid Build Coastguard Worker
291*61046927SAndroid Build Coastguard Worker uint32_t head_idx = current_head; /* Index is the bottom 32 bits */
292*61046927SAndroid Build Coastguard Worker void *head_elem = util_sparse_array_get(fl->arr, head_idx);
293*61046927SAndroid Build Coastguard Worker uint32_t *head_next = (uint32_t *)((char *)head_elem + fl->next_offset);
294*61046927SAndroid Build Coastguard Worker uint64_t new_head = free_list_head(current_head, p_atomic_read(head_next));
295*61046927SAndroid Build Coastguard Worker uint64_t old_head = p_atomic_cmpxchg(&fl->head, current_head, new_head);
296*61046927SAndroid Build Coastguard Worker if (old_head == current_head)
297*61046927SAndroid Build Coastguard Worker return head_elem;
298*61046927SAndroid Build Coastguard Worker current_head = old_head;
299*61046927SAndroid Build Coastguard Worker }
300*61046927SAndroid Build Coastguard Worker }
301