xref: /aosp_15_r20/external/mesa3d/src/util/sparse_array.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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