LCOV - code coverage report
Current view: top level - lib - dynamicsizehash_concurrent.c (source / functions) Hit Total Coverage
Test: elfutils-0.190 Lines: 127 171 74.3 %
Date: 2023-11-25 17:00:17 Functions: 12 13 92.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 44 88 50.0 %

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

Generated by: LCOV version 1.16