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