xref: /aosp_15_r20/external/elfutils/lib/dynamicsizehash_concurrent.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
1*7304104dSAndroid Build Coastguard Worker /* Copyright (C) 2000-2019 Red Hat, Inc.
2*7304104dSAndroid Build Coastguard Worker    This file is part of elfutils.
3*7304104dSAndroid Build Coastguard Worker    Written by Srdan Milakovic <[email protected]>, 2019.
4*7304104dSAndroid Build Coastguard Worker    Derived from Ulrich Drepper <[email protected]>, 2000.
5*7304104dSAndroid Build Coastguard Worker 
6*7304104dSAndroid Build Coastguard Worker    This file is free software; you can redistribute it and/or modify
7*7304104dSAndroid Build Coastguard Worker    it under the terms of either
8*7304104dSAndroid Build Coastguard Worker 
9*7304104dSAndroid Build Coastguard Worker      * the GNU Lesser General Public License as published by the Free
10*7304104dSAndroid Build Coastguard Worker        Software Foundation; either version 3 of the License, or (at
11*7304104dSAndroid Build Coastguard Worker        your option) any later version
12*7304104dSAndroid Build Coastguard Worker 
13*7304104dSAndroid Build Coastguard Worker    or
14*7304104dSAndroid Build Coastguard Worker 
15*7304104dSAndroid Build Coastguard Worker      * the GNU General Public License as published by the Free
16*7304104dSAndroid Build Coastguard Worker        Software Foundation; either version 2 of the License, or (at
17*7304104dSAndroid Build Coastguard Worker        your option) any later version
18*7304104dSAndroid Build Coastguard Worker 
19*7304104dSAndroid Build Coastguard Worker    or both in parallel, as here.
20*7304104dSAndroid Build Coastguard Worker 
21*7304104dSAndroid Build Coastguard Worker    elfutils is distributed in the hope that it will be useful, but
22*7304104dSAndroid Build Coastguard Worker    WITHOUT ANY WARRANTY; without even the implied warranty of
23*7304104dSAndroid Build Coastguard Worker    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24*7304104dSAndroid Build Coastguard Worker    General Public License for more details.
25*7304104dSAndroid Build Coastguard Worker 
26*7304104dSAndroid Build Coastguard Worker    You should have received copies of the GNU General Public License and
27*7304104dSAndroid Build Coastguard Worker    the GNU Lesser General Public License along with this program.  If
28*7304104dSAndroid Build Coastguard Worker    not, see <http://www.gnu.org/licenses/>.  */
29*7304104dSAndroid Build Coastguard Worker 
30*7304104dSAndroid Build Coastguard Worker #include <assert.h>
31*7304104dSAndroid Build Coastguard Worker #include <stdlib.h>
32*7304104dSAndroid Build Coastguard Worker #include <system.h>
33*7304104dSAndroid Build Coastguard Worker #include <pthread.h>
34*7304104dSAndroid Build Coastguard Worker 
35*7304104dSAndroid Build Coastguard Worker /* Before including this file the following macros must be defined:
36*7304104dSAndroid Build Coastguard Worker 
37*7304104dSAndroid Build Coastguard Worker    NAME      name of the hash table structure.
38*7304104dSAndroid Build Coastguard Worker    TYPE      data type of the hash table entries
39*7304104dSAndroid Build Coastguard Worker  */
40*7304104dSAndroid Build Coastguard Worker 
41*7304104dSAndroid Build Coastguard Worker 
42*7304104dSAndroid Build Coastguard Worker static size_t
lookup(NAME * htab,HASHTYPE hval)43*7304104dSAndroid Build Coastguard Worker lookup (NAME *htab, HASHTYPE hval)
44*7304104dSAndroid Build Coastguard Worker {
45*7304104dSAndroid Build Coastguard Worker   /* First hash function: simply take the modulus but prevent zero.  Small values
46*7304104dSAndroid Build Coastguard Worker       can skip the division, which helps performance when this is common.  */
47*7304104dSAndroid Build Coastguard Worker   size_t idx = 1 + (hval < htab->size ? hval : hval % htab->size);
48*7304104dSAndroid Build Coastguard Worker 
49*7304104dSAndroid Build Coastguard Worker   HASHTYPE hash;
50*7304104dSAndroid Build Coastguard Worker 
51*7304104dSAndroid Build Coastguard Worker   hash = atomic_load_explicit(&htab->table[idx].hashval,
52*7304104dSAndroid Build Coastguard Worker                               memory_order_acquire);
53*7304104dSAndroid Build Coastguard Worker   if (hash == hval)
54*7304104dSAndroid Build Coastguard Worker     return idx;
55*7304104dSAndroid Build Coastguard Worker   else if (hash == 0)
56*7304104dSAndroid Build Coastguard Worker     return 0;
57*7304104dSAndroid Build Coastguard Worker 
58*7304104dSAndroid Build Coastguard Worker   /* Second hash function as suggested in [Knuth].  */
59*7304104dSAndroid Build Coastguard Worker   HASHTYPE second_hash = 1 + hval % (htab->size - 2);
60*7304104dSAndroid Build Coastguard Worker 
61*7304104dSAndroid Build Coastguard Worker   for(;;)
62*7304104dSAndroid Build Coastguard Worker     {
63*7304104dSAndroid Build Coastguard Worker       if (idx <= second_hash)
64*7304104dSAndroid Build Coastguard Worker           idx = htab->size + idx - second_hash;
65*7304104dSAndroid Build Coastguard Worker       else
66*7304104dSAndroid Build Coastguard Worker           idx -= second_hash;
67*7304104dSAndroid Build Coastguard Worker 
68*7304104dSAndroid Build Coastguard Worker       hash = atomic_load_explicit(&htab->table[idx].hashval,
69*7304104dSAndroid Build Coastguard Worker                                   memory_order_acquire);
70*7304104dSAndroid Build Coastguard Worker       if (hash == hval)
71*7304104dSAndroid Build Coastguard Worker 	return idx;
72*7304104dSAndroid Build Coastguard Worker       else if (hash == 0)
73*7304104dSAndroid Build Coastguard Worker 	return 0;
74*7304104dSAndroid Build Coastguard Worker     }
75*7304104dSAndroid Build Coastguard Worker }
76*7304104dSAndroid Build Coastguard Worker 
77*7304104dSAndroid Build Coastguard Worker static int
insert_helper(NAME * htab,HASHTYPE hval,TYPE val)78*7304104dSAndroid Build Coastguard Worker insert_helper (NAME *htab, HASHTYPE hval, TYPE val)
79*7304104dSAndroid Build Coastguard Worker {
80*7304104dSAndroid Build Coastguard Worker   /* First hash function: simply take the modulus but prevent zero.  Small values
81*7304104dSAndroid Build Coastguard Worker       can skip the division, which helps performance when this is common.  */
82*7304104dSAndroid Build Coastguard Worker   size_t idx = 1 + (hval < htab->size ? hval : hval % htab->size);
83*7304104dSAndroid Build Coastguard Worker 
84*7304104dSAndroid Build Coastguard Worker   TYPE val_ptr;
85*7304104dSAndroid Build Coastguard Worker   HASHTYPE hash;
86*7304104dSAndroid Build Coastguard Worker 
87*7304104dSAndroid Build Coastguard Worker   hash = atomic_load_explicit(&htab->table[idx].hashval,
88*7304104dSAndroid Build Coastguard Worker                               memory_order_acquire);
89*7304104dSAndroid Build Coastguard Worker   if (hash == hval)
90*7304104dSAndroid Build Coastguard Worker     return -1;
91*7304104dSAndroid Build Coastguard Worker   else if (hash == 0)
92*7304104dSAndroid Build Coastguard Worker     {
93*7304104dSAndroid Build Coastguard Worker       val_ptr = NULL;
94*7304104dSAndroid Build Coastguard Worker       atomic_compare_exchange_strong_explicit(&htab->table[idx].val_ptr,
95*7304104dSAndroid Build Coastguard Worker                                               (uintptr_t *) &val_ptr,
96*7304104dSAndroid Build Coastguard Worker                                               (uintptr_t) val,
97*7304104dSAndroid Build Coastguard Worker                                               memory_order_acquire,
98*7304104dSAndroid Build Coastguard Worker                                               memory_order_acquire);
99*7304104dSAndroid Build Coastguard Worker 
100*7304104dSAndroid Build Coastguard Worker       if (val_ptr == NULL)
101*7304104dSAndroid Build Coastguard Worker         {
102*7304104dSAndroid Build Coastguard Worker           atomic_store_explicit(&htab->table[idx].hashval, hval,
103*7304104dSAndroid Build Coastguard Worker                                 memory_order_release);
104*7304104dSAndroid Build Coastguard Worker           return 0;
105*7304104dSAndroid Build Coastguard Worker         }
106*7304104dSAndroid Build Coastguard Worker       else
107*7304104dSAndroid Build Coastguard Worker         {
108*7304104dSAndroid Build Coastguard Worker           do
109*7304104dSAndroid Build Coastguard Worker             {
110*7304104dSAndroid Build Coastguard Worker               hash = atomic_load_explicit(&htab->table[idx].hashval,
111*7304104dSAndroid Build Coastguard Worker                                           memory_order_acquire);
112*7304104dSAndroid Build Coastguard Worker             }
113*7304104dSAndroid Build Coastguard Worker           while (hash == 0);
114*7304104dSAndroid Build Coastguard Worker           if (hash == hval)
115*7304104dSAndroid Build Coastguard Worker             return -1;
116*7304104dSAndroid Build Coastguard Worker         }
117*7304104dSAndroid Build Coastguard Worker     }
118*7304104dSAndroid Build Coastguard Worker 
119*7304104dSAndroid Build Coastguard Worker   /* Second hash function as suggested in [Knuth].  */
120*7304104dSAndroid Build Coastguard Worker   HASHTYPE second_hash = 1 + hval % (htab->size - 2);
121*7304104dSAndroid Build Coastguard Worker 
122*7304104dSAndroid Build Coastguard Worker   for(;;)
123*7304104dSAndroid Build Coastguard Worker     {
124*7304104dSAndroid Build Coastguard Worker       if (idx <= second_hash)
125*7304104dSAndroid Build Coastguard Worker           idx = htab->size + idx - second_hash;
126*7304104dSAndroid Build Coastguard Worker       else
127*7304104dSAndroid Build Coastguard Worker           idx -= second_hash;
128*7304104dSAndroid Build Coastguard Worker 
129*7304104dSAndroid Build Coastguard Worker       hash = atomic_load_explicit(&htab->table[idx].hashval,
130*7304104dSAndroid Build Coastguard Worker                                   memory_order_acquire);
131*7304104dSAndroid Build Coastguard Worker       if (hash == hval)
132*7304104dSAndroid Build Coastguard Worker         return -1;
133*7304104dSAndroid Build Coastguard Worker       else if (hash == 0)
134*7304104dSAndroid Build Coastguard Worker         {
135*7304104dSAndroid Build Coastguard Worker           val_ptr = NULL;
136*7304104dSAndroid Build Coastguard Worker           atomic_compare_exchange_strong_explicit(&htab->table[idx].val_ptr,
137*7304104dSAndroid Build Coastguard Worker                                                   (uintptr_t *) &val_ptr,
138*7304104dSAndroid Build Coastguard Worker                                                   (uintptr_t) val,
139*7304104dSAndroid Build Coastguard Worker                                                   memory_order_acquire,
140*7304104dSAndroid Build Coastguard Worker                                                   memory_order_acquire);
141*7304104dSAndroid Build Coastguard Worker 
142*7304104dSAndroid Build Coastguard Worker           if (val_ptr == NULL)
143*7304104dSAndroid Build Coastguard Worker             {
144*7304104dSAndroid Build Coastguard Worker               atomic_store_explicit(&htab->table[idx].hashval, hval,
145*7304104dSAndroid Build Coastguard Worker                                     memory_order_release);
146*7304104dSAndroid Build Coastguard Worker               return 0;
147*7304104dSAndroid Build Coastguard Worker             }
148*7304104dSAndroid Build Coastguard Worker           else
149*7304104dSAndroid Build Coastguard Worker             {
150*7304104dSAndroid Build Coastguard Worker               do
151*7304104dSAndroid Build Coastguard Worker                 {
152*7304104dSAndroid Build Coastguard Worker                   hash = atomic_load_explicit(&htab->table[idx].hashval,
153*7304104dSAndroid Build Coastguard Worker                                               memory_order_acquire);
154*7304104dSAndroid Build Coastguard Worker                 }
155*7304104dSAndroid Build Coastguard Worker               while (hash == 0);
156*7304104dSAndroid Build Coastguard Worker               if (hash == hval)
157*7304104dSAndroid Build Coastguard Worker                 return -1;
158*7304104dSAndroid Build Coastguard Worker             }
159*7304104dSAndroid Build Coastguard Worker         }
160*7304104dSAndroid Build Coastguard Worker     }
161*7304104dSAndroid Build Coastguard Worker }
162*7304104dSAndroid Build Coastguard Worker 
163*7304104dSAndroid Build Coastguard Worker #define NO_RESIZING 0u
164*7304104dSAndroid Build Coastguard Worker #define ALLOCATING_MEMORY 1u
165*7304104dSAndroid Build Coastguard Worker #define MOVING_DATA 3u
166*7304104dSAndroid Build Coastguard Worker #define CLEANING 2u
167*7304104dSAndroid Build Coastguard Worker 
168*7304104dSAndroid Build Coastguard Worker #define STATE_BITS 2u
169*7304104dSAndroid Build Coastguard Worker #define STATE_INCREMENT (1u << STATE_BITS)
170*7304104dSAndroid Build Coastguard Worker #define STATE_MASK (STATE_INCREMENT - 1)
171*7304104dSAndroid Build Coastguard Worker #define GET_STATE(A) ((A) & STATE_MASK)
172*7304104dSAndroid Build Coastguard Worker 
173*7304104dSAndroid Build Coastguard Worker #define IS_NO_RESIZE_OR_CLEANING(A) (((A) & 0x1u) == 0)
174*7304104dSAndroid Build Coastguard Worker 
175*7304104dSAndroid Build Coastguard Worker #define GET_ACTIVE_WORKERS(A) ((A) >> STATE_BITS)
176*7304104dSAndroid Build Coastguard Worker 
177*7304104dSAndroid Build Coastguard Worker #define INITIALIZATION_BLOCK_SIZE 256
178*7304104dSAndroid Build Coastguard Worker #define MOVE_BLOCK_SIZE 256
179*7304104dSAndroid Build Coastguard Worker #define CEIL(A, B) (((A) + (B) - 1) / (B))
180*7304104dSAndroid Build Coastguard Worker 
181*7304104dSAndroid Build Coastguard Worker /* Initializes records and copies the data from the old table.
182*7304104dSAndroid Build Coastguard Worker    It can share work with other threads.  Only the coordinator
183*7304104dSAndroid Build Coastguard Worker    will pass blocking as 1, other worker threads pass 0.  */
resize_helper(NAME * htab,int blocking)184*7304104dSAndroid Build Coastguard Worker static void resize_helper(NAME *htab, int blocking)
185*7304104dSAndroid Build Coastguard Worker {
186*7304104dSAndroid Build Coastguard Worker   size_t num_old_blocks = CEIL(htab->old_size, MOVE_BLOCK_SIZE);
187*7304104dSAndroid Build Coastguard Worker   size_t num_new_blocks = CEIL(htab->size, INITIALIZATION_BLOCK_SIZE);
188*7304104dSAndroid Build Coastguard Worker 
189*7304104dSAndroid Build Coastguard Worker   size_t my_block;
190*7304104dSAndroid Build Coastguard Worker   size_t num_finished_blocks = 0;
191*7304104dSAndroid Build Coastguard Worker 
192*7304104dSAndroid Build Coastguard Worker   while ((my_block = atomic_fetch_add_explicit(&htab->next_init_block, 1,
193*7304104dSAndroid Build Coastguard Worker                                                 memory_order_acquire))
194*7304104dSAndroid Build Coastguard Worker                                                     < num_new_blocks)
195*7304104dSAndroid Build Coastguard Worker     {
196*7304104dSAndroid Build Coastguard Worker       size_t record_it = my_block * INITIALIZATION_BLOCK_SIZE;
197*7304104dSAndroid Build Coastguard Worker       size_t record_end = (my_block + 1) * INITIALIZATION_BLOCK_SIZE;
198*7304104dSAndroid Build Coastguard Worker       if (record_end > htab->size)
199*7304104dSAndroid Build Coastguard Worker           record_end = htab->size;
200*7304104dSAndroid Build Coastguard Worker 
201*7304104dSAndroid Build Coastguard Worker       while (record_it++ != record_end)
202*7304104dSAndroid Build Coastguard Worker         {
203*7304104dSAndroid Build Coastguard Worker           atomic_init(&htab->table[record_it].hashval, (uintptr_t) NULL);
204*7304104dSAndroid Build Coastguard Worker           atomic_init(&htab->table[record_it].val_ptr, (uintptr_t) NULL);
205*7304104dSAndroid Build Coastguard Worker         }
206*7304104dSAndroid Build Coastguard Worker 
207*7304104dSAndroid Build Coastguard Worker       num_finished_blocks++;
208*7304104dSAndroid Build Coastguard Worker     }
209*7304104dSAndroid Build Coastguard Worker 
210*7304104dSAndroid Build Coastguard Worker   atomic_fetch_add_explicit(&htab->num_initialized_blocks,
211*7304104dSAndroid Build Coastguard Worker                             num_finished_blocks, memory_order_release);
212*7304104dSAndroid Build Coastguard Worker   while (atomic_load_explicit(&htab->num_initialized_blocks,
213*7304104dSAndroid Build Coastguard Worker                               memory_order_acquire) != num_new_blocks);
214*7304104dSAndroid Build Coastguard Worker 
215*7304104dSAndroid Build Coastguard Worker   /* All block are initialized, start moving */
216*7304104dSAndroid Build Coastguard Worker   num_finished_blocks = 0;
217*7304104dSAndroid Build Coastguard Worker   while ((my_block = atomic_fetch_add_explicit(&htab->next_move_block, 1,
218*7304104dSAndroid Build Coastguard Worker                                                 memory_order_acquire))
219*7304104dSAndroid Build Coastguard Worker                                                     < num_old_blocks)
220*7304104dSAndroid Build Coastguard Worker     {
221*7304104dSAndroid Build Coastguard Worker       size_t record_it = my_block * MOVE_BLOCK_SIZE;
222*7304104dSAndroid Build Coastguard Worker       size_t record_end = (my_block + 1) * MOVE_BLOCK_SIZE;
223*7304104dSAndroid Build Coastguard Worker       if (record_end > htab->old_size)
224*7304104dSAndroid Build Coastguard Worker           record_end = htab->old_size;
225*7304104dSAndroid Build Coastguard Worker 
226*7304104dSAndroid Build Coastguard Worker       while (record_it++ != record_end)
227*7304104dSAndroid Build Coastguard Worker         {
228*7304104dSAndroid Build Coastguard Worker           TYPE val_ptr = (TYPE) atomic_load_explicit(
229*7304104dSAndroid Build Coastguard Worker               &htab->old_table[record_it].val_ptr,
230*7304104dSAndroid Build Coastguard Worker               memory_order_acquire);
231*7304104dSAndroid Build Coastguard Worker           if (val_ptr == NULL)
232*7304104dSAndroid Build Coastguard Worker               continue;
233*7304104dSAndroid Build Coastguard Worker 
234*7304104dSAndroid Build Coastguard Worker           HASHTYPE hashval = atomic_load_explicit(
235*7304104dSAndroid Build Coastguard Worker               &htab->old_table[record_it].hashval,
236*7304104dSAndroid Build Coastguard Worker               memory_order_acquire);
237*7304104dSAndroid Build Coastguard Worker           assert(hashval);
238*7304104dSAndroid Build Coastguard Worker 
239*7304104dSAndroid Build Coastguard Worker           insert_helper(htab, hashval, val_ptr);
240*7304104dSAndroid Build Coastguard Worker         }
241*7304104dSAndroid Build Coastguard Worker 
242*7304104dSAndroid Build Coastguard Worker       num_finished_blocks++;
243*7304104dSAndroid Build Coastguard Worker     }
244*7304104dSAndroid Build Coastguard Worker 
245*7304104dSAndroid Build Coastguard Worker   atomic_fetch_add_explicit(&htab->num_moved_blocks, num_finished_blocks,
246*7304104dSAndroid Build Coastguard Worker                             memory_order_release);
247*7304104dSAndroid Build Coastguard Worker 
248*7304104dSAndroid Build Coastguard Worker   /* The coordinating thread will block here waiting for all blocks to
249*7304104dSAndroid Build Coastguard Worker      be moved.  */
250*7304104dSAndroid Build Coastguard Worker   if (blocking)
251*7304104dSAndroid Build Coastguard Worker       while (atomic_load_explicit(&htab->num_moved_blocks,
252*7304104dSAndroid Build Coastguard Worker                                   memory_order_acquire) != num_old_blocks);
253*7304104dSAndroid Build Coastguard Worker }
254*7304104dSAndroid Build Coastguard Worker 
255*7304104dSAndroid Build Coastguard Worker /* Called by the main thread holding the htab->resize_rwl lock to
256*7304104dSAndroid Build Coastguard Worker    coordinate the moving of hash table data. Allocates the new hash
257*7304104dSAndroid Build Coastguard Worker    table and frees the old one when moving all data is done.  */
258*7304104dSAndroid Build Coastguard Worker static void
resize_coordinator(NAME * htab)259*7304104dSAndroid Build Coastguard Worker resize_coordinator(NAME *htab)
260*7304104dSAndroid Build Coastguard Worker {
261*7304104dSAndroid Build Coastguard Worker   htab->old_size = htab->size;
262*7304104dSAndroid Build Coastguard Worker   htab->old_table = htab->table;
263*7304104dSAndroid Build Coastguard Worker 
264*7304104dSAndroid Build Coastguard Worker   htab->size = next_prime(htab->size * 2);
265*7304104dSAndroid Build Coastguard Worker   htab->table = malloc((1 + htab->size) * sizeof(htab->table[0]));
266*7304104dSAndroid Build Coastguard Worker   assert(htab->table);
267*7304104dSAndroid Build Coastguard Worker 
268*7304104dSAndroid Build Coastguard Worker   /* Change state from ALLOCATING_MEMORY to MOVING_DATA */
269*7304104dSAndroid Build Coastguard Worker   atomic_fetch_xor_explicit(&htab->resizing_state,
270*7304104dSAndroid Build Coastguard Worker                             ALLOCATING_MEMORY ^ MOVING_DATA,
271*7304104dSAndroid Build Coastguard Worker                             memory_order_release);
272*7304104dSAndroid Build Coastguard Worker 
273*7304104dSAndroid Build Coastguard Worker   resize_helper(htab, 1);
274*7304104dSAndroid Build Coastguard Worker 
275*7304104dSAndroid Build Coastguard Worker   /* Change state from MOVING_DATA to CLEANING */
276*7304104dSAndroid Build Coastguard Worker   size_t resize_state = atomic_fetch_xor_explicit(&htab->resizing_state,
277*7304104dSAndroid Build Coastguard Worker                                                   MOVING_DATA ^ CLEANING,
278*7304104dSAndroid Build Coastguard Worker                                                   memory_order_acq_rel);
279*7304104dSAndroid Build Coastguard Worker   while (GET_ACTIVE_WORKERS(resize_state) != 0)
280*7304104dSAndroid Build Coastguard Worker       resize_state = atomic_load_explicit(&htab->resizing_state,
281*7304104dSAndroid Build Coastguard Worker                                           memory_order_acquire);
282*7304104dSAndroid Build Coastguard Worker 
283*7304104dSAndroid Build Coastguard Worker   /* There are no more active workers */
284*7304104dSAndroid Build Coastguard Worker   atomic_store_explicit(&htab->next_init_block, 0, memory_order_relaxed);
285*7304104dSAndroid Build Coastguard Worker   atomic_store_explicit(&htab->num_initialized_blocks, 0,
286*7304104dSAndroid Build Coastguard Worker                         memory_order_relaxed);
287*7304104dSAndroid Build Coastguard Worker 
288*7304104dSAndroid Build Coastguard Worker   atomic_store_explicit(&htab->next_move_block, 0, memory_order_relaxed);
289*7304104dSAndroid Build Coastguard Worker   atomic_store_explicit(&htab->num_moved_blocks, 0, memory_order_relaxed);
290*7304104dSAndroid Build Coastguard Worker 
291*7304104dSAndroid Build Coastguard Worker   free(htab->old_table);
292*7304104dSAndroid Build Coastguard Worker 
293*7304104dSAndroid Build Coastguard Worker   /* Change state to NO_RESIZING */
294*7304104dSAndroid Build Coastguard Worker   atomic_fetch_xor_explicit(&htab->resizing_state, CLEANING ^ NO_RESIZING,
295*7304104dSAndroid Build Coastguard Worker                             memory_order_relaxed);
296*7304104dSAndroid Build Coastguard Worker 
297*7304104dSAndroid Build Coastguard Worker }
298*7304104dSAndroid Build Coastguard Worker 
299*7304104dSAndroid Build Coastguard Worker /* Called by any thread that wants to do an insert or find operation
300*7304104dSAndroid Build Coastguard Worker    but notices it cannot get the htab->resize_rwl lock because another
301*7304104dSAndroid Build Coastguard Worker    thread is resizing the hash table.  Try to help out by moving table
302*7304104dSAndroid Build Coastguard Worker    data if still necessary.  */
303*7304104dSAndroid Build Coastguard Worker static void
resize_worker(NAME * htab)304*7304104dSAndroid Build Coastguard Worker resize_worker(NAME *htab)
305*7304104dSAndroid Build Coastguard Worker {
306*7304104dSAndroid Build Coastguard Worker   size_t resize_state = atomic_load_explicit(&htab->resizing_state,
307*7304104dSAndroid Build Coastguard Worker                                               memory_order_acquire);
308*7304104dSAndroid Build Coastguard Worker 
309*7304104dSAndroid Build Coastguard Worker   /* If the resize has finished */
310*7304104dSAndroid Build Coastguard Worker   if (IS_NO_RESIZE_OR_CLEANING(resize_state))
311*7304104dSAndroid Build Coastguard Worker       return;
312*7304104dSAndroid Build Coastguard Worker 
313*7304104dSAndroid Build Coastguard Worker   /* Register as worker and check if the resize has finished in the meantime*/
314*7304104dSAndroid Build Coastguard Worker   resize_state = atomic_fetch_add_explicit(&htab->resizing_state,
315*7304104dSAndroid Build Coastguard Worker                                             STATE_INCREMENT,
316*7304104dSAndroid Build Coastguard Worker                                             memory_order_acquire);
317*7304104dSAndroid Build Coastguard Worker   if (IS_NO_RESIZE_OR_CLEANING(resize_state))
318*7304104dSAndroid Build Coastguard Worker     {
319*7304104dSAndroid Build Coastguard Worker       atomic_fetch_sub_explicit(&htab->resizing_state, STATE_INCREMENT,
320*7304104dSAndroid Build Coastguard Worker                                 memory_order_relaxed);
321*7304104dSAndroid Build Coastguard Worker       return;
322*7304104dSAndroid Build Coastguard Worker     }
323*7304104dSAndroid Build Coastguard Worker 
324*7304104dSAndroid Build Coastguard Worker   /* Wait while the new table is being allocated. */
325*7304104dSAndroid Build Coastguard Worker   while (GET_STATE(resize_state) == ALLOCATING_MEMORY)
326*7304104dSAndroid Build Coastguard Worker       resize_state = atomic_load_explicit(&htab->resizing_state,
327*7304104dSAndroid Build Coastguard Worker                                           memory_order_acquire);
328*7304104dSAndroid Build Coastguard Worker 
329*7304104dSAndroid Build Coastguard Worker   /* Check if the resize is done */
330*7304104dSAndroid Build Coastguard Worker   assert(GET_STATE(resize_state) != NO_RESIZING);
331*7304104dSAndroid Build Coastguard Worker   if (GET_STATE(resize_state) == CLEANING)
332*7304104dSAndroid Build Coastguard Worker     {
333*7304104dSAndroid Build Coastguard Worker       atomic_fetch_sub_explicit(&htab->resizing_state, STATE_INCREMENT,
334*7304104dSAndroid Build Coastguard Worker                                 memory_order_relaxed);
335*7304104dSAndroid Build Coastguard Worker       return;
336*7304104dSAndroid Build Coastguard Worker     }
337*7304104dSAndroid Build Coastguard Worker 
338*7304104dSAndroid Build Coastguard Worker   resize_helper(htab, 0);
339*7304104dSAndroid Build Coastguard Worker 
340*7304104dSAndroid Build Coastguard Worker   /* Deregister worker */
341*7304104dSAndroid Build Coastguard Worker   atomic_fetch_sub_explicit(&htab->resizing_state, STATE_INCREMENT,
342*7304104dSAndroid Build Coastguard Worker                             memory_order_release);
343*7304104dSAndroid Build Coastguard Worker }
344*7304104dSAndroid Build Coastguard Worker 
345*7304104dSAndroid Build Coastguard Worker 
346*7304104dSAndroid Build Coastguard Worker int
347*7304104dSAndroid Build Coastguard Worker #define INIT(name) _INIT (name)
348*7304104dSAndroid Build Coastguard Worker #define _INIT(name) \
349*7304104dSAndroid Build Coastguard Worker   name##_init
INIT(NAME)350*7304104dSAndroid Build Coastguard Worker INIT(NAME) (NAME *htab, size_t init_size)
351*7304104dSAndroid Build Coastguard Worker {
352*7304104dSAndroid Build Coastguard Worker   /* We need the size to be a prime.  */
353*7304104dSAndroid Build Coastguard Worker   init_size = next_prime (init_size);
354*7304104dSAndroid Build Coastguard Worker 
355*7304104dSAndroid Build Coastguard Worker   /* Initialize the data structure.  */
356*7304104dSAndroid Build Coastguard Worker   htab->size = init_size;
357*7304104dSAndroid Build Coastguard Worker   atomic_init(&htab->filled, 0);
358*7304104dSAndroid Build Coastguard Worker   atomic_init(&htab->resizing_state, 0);
359*7304104dSAndroid Build Coastguard Worker 
360*7304104dSAndroid Build Coastguard Worker   atomic_init(&htab->next_init_block, 0);
361*7304104dSAndroid Build Coastguard Worker   atomic_init(&htab->num_initialized_blocks, 0);
362*7304104dSAndroid Build Coastguard Worker 
363*7304104dSAndroid Build Coastguard Worker   atomic_init(&htab->next_move_block, 0);
364*7304104dSAndroid Build Coastguard Worker   atomic_init(&htab->num_moved_blocks, 0);
365*7304104dSAndroid Build Coastguard Worker 
366*7304104dSAndroid Build Coastguard Worker   pthread_rwlock_init(&htab->resize_rwl, NULL);
367*7304104dSAndroid Build Coastguard Worker 
368*7304104dSAndroid Build Coastguard Worker   htab->table = malloc ((init_size + 1) * sizeof (htab->table[0]));
369*7304104dSAndroid Build Coastguard Worker   if (htab->table == NULL)
370*7304104dSAndroid Build Coastguard Worker       return -1;
371*7304104dSAndroid Build Coastguard Worker 
372*7304104dSAndroid Build Coastguard Worker   for (size_t i = 0; i <= init_size; i++)
373*7304104dSAndroid Build Coastguard Worker     {
374*7304104dSAndroid Build Coastguard Worker       atomic_init(&htab->table[i].hashval, (uintptr_t) NULL);
375*7304104dSAndroid Build Coastguard Worker       atomic_init(&htab->table[i].val_ptr, (uintptr_t) NULL);
376*7304104dSAndroid Build Coastguard Worker     }
377*7304104dSAndroid Build Coastguard Worker 
378*7304104dSAndroid Build Coastguard Worker   return 0;
379*7304104dSAndroid Build Coastguard Worker }
380*7304104dSAndroid Build Coastguard Worker 
381*7304104dSAndroid Build Coastguard Worker 
382*7304104dSAndroid Build Coastguard Worker int
383*7304104dSAndroid Build Coastguard Worker #define FREE(name) _FREE (name)
384*7304104dSAndroid Build Coastguard Worker #define _FREE(name) \
385*7304104dSAndroid Build Coastguard Worker name##_free
FREE(NAME)386*7304104dSAndroid Build Coastguard Worker FREE(NAME) (NAME *htab)
387*7304104dSAndroid Build Coastguard Worker {
388*7304104dSAndroid Build Coastguard Worker   pthread_rwlock_destroy(&htab->resize_rwl);
389*7304104dSAndroid Build Coastguard Worker   free (htab->table);
390*7304104dSAndroid Build Coastguard Worker   return 0;
391*7304104dSAndroid Build Coastguard Worker }
392*7304104dSAndroid Build Coastguard Worker 
393*7304104dSAndroid Build Coastguard Worker 
394*7304104dSAndroid Build Coastguard Worker int
395*7304104dSAndroid Build Coastguard Worker #define INSERT(name) _INSERT (name)
396*7304104dSAndroid Build Coastguard Worker #define _INSERT(name) \
397*7304104dSAndroid Build Coastguard Worker name##_insert
INSERT(NAME)398*7304104dSAndroid Build Coastguard Worker INSERT(NAME) (NAME *htab, HASHTYPE hval, TYPE data)
399*7304104dSAndroid Build Coastguard Worker {
400*7304104dSAndroid Build Coastguard Worker   int incremented = 0;
401*7304104dSAndroid Build Coastguard Worker 
402*7304104dSAndroid Build Coastguard Worker   for(;;)
403*7304104dSAndroid Build Coastguard Worker     {
404*7304104dSAndroid Build Coastguard Worker       /* If we cannot get the resize_rwl lock someone is resizing
405*7304104dSAndroid Build Coastguard Worker 	 hash table, try to help out by moving table data.  */
406*7304104dSAndroid Build Coastguard Worker       while (pthread_rwlock_tryrdlock(&htab->resize_rwl) != 0)
407*7304104dSAndroid Build Coastguard Worker           resize_worker(htab);
408*7304104dSAndroid Build Coastguard Worker 
409*7304104dSAndroid Build Coastguard Worker       size_t filled;
410*7304104dSAndroid Build Coastguard Worker       if (!incremented)
411*7304104dSAndroid Build Coastguard Worker         {
412*7304104dSAndroid Build Coastguard Worker           filled = atomic_fetch_add_explicit(&htab->filled, 1,
413*7304104dSAndroid Build Coastguard Worker                                               memory_order_acquire);
414*7304104dSAndroid Build Coastguard Worker           incremented = 1;
415*7304104dSAndroid Build Coastguard Worker         }
416*7304104dSAndroid Build Coastguard Worker       else
417*7304104dSAndroid Build Coastguard Worker         {
418*7304104dSAndroid Build Coastguard Worker           filled = atomic_load_explicit(&htab->filled,
419*7304104dSAndroid Build Coastguard Worker                                         memory_order_acquire);
420*7304104dSAndroid Build Coastguard Worker         }
421*7304104dSAndroid Build Coastguard Worker 
422*7304104dSAndroid Build Coastguard Worker 
423*7304104dSAndroid Build Coastguard Worker       if (100 * filled > 90 * htab->size)
424*7304104dSAndroid Build Coastguard Worker         {
425*7304104dSAndroid Build Coastguard Worker           /* Table is filled more than 90%.  Resize the table.  */
426*7304104dSAndroid Build Coastguard Worker 
427*7304104dSAndroid Build Coastguard Worker           size_t resizing_state = atomic_load_explicit(&htab->resizing_state,
428*7304104dSAndroid Build Coastguard Worker                                                         memory_order_acquire);
429*7304104dSAndroid Build Coastguard Worker           if (resizing_state == 0 &&
430*7304104dSAndroid Build Coastguard Worker               atomic_compare_exchange_strong_explicit(&htab->resizing_state,
431*7304104dSAndroid Build Coastguard Worker                                                       &resizing_state,
432*7304104dSAndroid Build Coastguard Worker                                                       ALLOCATING_MEMORY,
433*7304104dSAndroid Build Coastguard Worker                                                       memory_order_acquire,
434*7304104dSAndroid Build Coastguard Worker                                                       memory_order_acquire))
435*7304104dSAndroid Build Coastguard Worker             {
436*7304104dSAndroid Build Coastguard Worker               /* Main resizing thread, will coordinate moving data.  */
437*7304104dSAndroid Build Coastguard Worker               pthread_rwlock_unlock(&htab->resize_rwl);
438*7304104dSAndroid Build Coastguard Worker 
439*7304104dSAndroid Build Coastguard Worker               pthread_rwlock_wrlock(&htab->resize_rwl);
440*7304104dSAndroid Build Coastguard Worker               resize_coordinator(htab);
441*7304104dSAndroid Build Coastguard Worker               pthread_rwlock_unlock(&htab->resize_rwl);
442*7304104dSAndroid Build Coastguard Worker 
443*7304104dSAndroid Build Coastguard Worker             }
444*7304104dSAndroid Build Coastguard Worker           else
445*7304104dSAndroid Build Coastguard Worker             {
446*7304104dSAndroid Build Coastguard Worker               /* Worker thread, will help moving data.  */
447*7304104dSAndroid Build Coastguard Worker               pthread_rwlock_unlock(&htab->resize_rwl);
448*7304104dSAndroid Build Coastguard Worker               resize_worker(htab);
449*7304104dSAndroid Build Coastguard Worker             }
450*7304104dSAndroid Build Coastguard Worker         }
451*7304104dSAndroid Build Coastguard Worker       else
452*7304104dSAndroid Build Coastguard Worker         {
453*7304104dSAndroid Build Coastguard Worker           /* Lock acquired, no need for resize*/
454*7304104dSAndroid Build Coastguard Worker           break;
455*7304104dSAndroid Build Coastguard Worker         }
456*7304104dSAndroid Build Coastguard Worker     }
457*7304104dSAndroid Build Coastguard Worker 
458*7304104dSAndroid Build Coastguard Worker   int ret_val = insert_helper(htab, hval, data);
459*7304104dSAndroid Build Coastguard Worker   if (ret_val == -1)
460*7304104dSAndroid Build Coastguard Worker       atomic_fetch_sub_explicit(&htab->filled, 1, memory_order_relaxed);
461*7304104dSAndroid Build Coastguard Worker   pthread_rwlock_unlock(&htab->resize_rwl);
462*7304104dSAndroid Build Coastguard Worker   return ret_val;
463*7304104dSAndroid Build Coastguard Worker }
464*7304104dSAndroid Build Coastguard Worker 
465*7304104dSAndroid Build Coastguard Worker 
466*7304104dSAndroid Build Coastguard Worker 
467*7304104dSAndroid Build Coastguard Worker TYPE
468*7304104dSAndroid Build Coastguard Worker #define FIND(name) _FIND (name)
469*7304104dSAndroid Build Coastguard Worker #define _FIND(name) \
470*7304104dSAndroid Build Coastguard Worker   name##_find
FIND(NAME)471*7304104dSAndroid Build Coastguard Worker FIND(NAME) (NAME *htab, HASHTYPE hval)
472*7304104dSAndroid Build Coastguard Worker {
473*7304104dSAndroid Build Coastguard Worker   /* If we cannot get the resize_rwl lock someone is resizing
474*7304104dSAndroid Build Coastguard Worker      the hash table, try to help out by moving table data.  */
475*7304104dSAndroid Build Coastguard Worker   while (pthread_rwlock_tryrdlock(&htab->resize_rwl) != 0)
476*7304104dSAndroid Build Coastguard Worker     resize_worker(htab);
477*7304104dSAndroid Build Coastguard Worker 
478*7304104dSAndroid Build Coastguard Worker   size_t idx;
479*7304104dSAndroid Build Coastguard Worker 
480*7304104dSAndroid Build Coastguard Worker   /* Make the hash data nonzero.  */
481*7304104dSAndroid Build Coastguard Worker   hval = hval ?: 1;
482*7304104dSAndroid Build Coastguard Worker   idx = lookup(htab, hval);
483*7304104dSAndroid Build Coastguard Worker 
484*7304104dSAndroid Build Coastguard Worker   if (idx == 0)
485*7304104dSAndroid Build Coastguard Worker     {
486*7304104dSAndroid Build Coastguard Worker       pthread_rwlock_unlock(&htab->resize_rwl);
487*7304104dSAndroid Build Coastguard Worker       return NULL;
488*7304104dSAndroid Build Coastguard Worker     }
489*7304104dSAndroid Build Coastguard Worker 
490*7304104dSAndroid Build Coastguard Worker   /* get a copy before unlocking the lock */
491*7304104dSAndroid Build Coastguard Worker   TYPE ret_val = (TYPE) atomic_load_explicit(&htab->table[idx].val_ptr,
492*7304104dSAndroid Build Coastguard Worker                                              memory_order_relaxed);
493*7304104dSAndroid Build Coastguard Worker 
494*7304104dSAndroid Build Coastguard Worker   pthread_rwlock_unlock(&htab->resize_rwl);
495*7304104dSAndroid Build Coastguard Worker   return ret_val;
496*7304104dSAndroid Build Coastguard Worker }
497