Blame lib/dynamicsizehash_concurrent.c

Packit Service 97d2fb
/* Copyright (C) 2000-2019 Red Hat, Inc.
Packit Service 97d2fb
   This file is part of elfutils.
Packit Service 97d2fb
   Written by Srdan Milakovic <sm108@rice.edu>, 2019.
Packit Service 97d2fb
   Derived from Ulrich Drepper <drepper@redhat.com>, 2000.
Packit Service 97d2fb
Packit Service 97d2fb
   This file is free software; you can redistribute it and/or modify
Packit Service 97d2fb
   it under the terms of either
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU Lesser General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 3 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 2 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or both in parallel, as here.
Packit Service 97d2fb
Packit Service 97d2fb
   elfutils is distributed in the hope that it will be useful, but
Packit Service 97d2fb
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 97d2fb
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 97d2fb
   General Public License for more details.
Packit Service 97d2fb
Packit Service 97d2fb
   You should have received copies of the GNU General Public License and
Packit Service 97d2fb
   the GNU Lesser General Public License along with this program.  If
Packit Service 97d2fb
   not, see <http://www.gnu.org/licenses/>.  */
Packit Service 97d2fb
Packit Service 97d2fb
#include <assert.h>
Packit Service 97d2fb
#include <stdlib.h>
Packit Service 97d2fb
#include <system.h>
Packit Service 97d2fb
#include <pthread.h>
Packit Service 97d2fb
Packit Service 97d2fb
/* Before including this file the following macros must be defined:
Packit Service 97d2fb
Packit Service 97d2fb
   NAME      name of the hash table structure.
Packit Service 97d2fb
   TYPE      data type of the hash table entries
Packit Service 97d2fb
 */
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static size_t
Packit Service 97d2fb
lookup (NAME *htab, HASHTYPE hval)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* First hash function: simply take the modul but prevent zero.  Small values
Packit Service 97d2fb
      can skip the division, which helps performance when this is common.  */
Packit Service 97d2fb
  size_t idx = 1 + (hval < htab->size ? hval : hval % htab->size);
Packit Service 97d2fb
Packit Service 97d2fb
  HASHTYPE hash;
Packit Service 97d2fb
Packit Service 97d2fb
  hash = atomic_load_explicit(&htab->table[idx].hashval,
Packit Service 97d2fb
                              memory_order_acquire);
Packit Service 97d2fb
  if (hash == hval)
Packit Service 97d2fb
    return idx;
Packit Service 97d2fb
  else if (hash == 0)
Packit Service 97d2fb
    return 0;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Second hash function as suggested in [Knuth].  */
Packit Service 97d2fb
  HASHTYPE second_hash = 1 + hval % (htab->size - 2);
Packit Service 97d2fb
Packit Service 97d2fb
  for(;;)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (idx <= second_hash)
Packit Service 97d2fb
          idx = htab->size + idx - second_hash;
Packit Service 97d2fb
      else
Packit Service 97d2fb
          idx -= second_hash;
Packit Service 97d2fb
Packit Service 97d2fb
      hash = atomic_load_explicit(&htab->table[idx].hashval,
Packit Service 97d2fb
                                  memory_order_acquire);
Packit Service 97d2fb
      if (hash == hval)
Packit Service 97d2fb
	return idx;
Packit Service 97d2fb
      else if (hash == 0)
Packit Service 97d2fb
	return 0;
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
insert_helper (NAME *htab, HASHTYPE hval, TYPE val)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* First hash function: simply take the modul but prevent zero.  Small values
Packit Service 97d2fb
      can skip the division, which helps performance when this is common.  */
Packit Service 97d2fb
  size_t idx = 1 + (hval < htab->size ? hval : hval % htab->size);
Packit Service 97d2fb
Packit Service 97d2fb
  TYPE val_ptr;
Packit Service 97d2fb
  HASHTYPE hash;
Packit Service 97d2fb
Packit Service 97d2fb
  hash = atomic_load_explicit(&htab->table[idx].hashval,
Packit Service 97d2fb
                              memory_order_acquire);
Packit Service 97d2fb
  if (hash == hval)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
  else if (hash == 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      val_ptr = NULL;
Packit Service 97d2fb
      atomic_compare_exchange_strong_explicit(&htab->table[idx].val_ptr,
Packit Service 97d2fb
                                              (uintptr_t *) &val_ptr,
Packit Service 97d2fb
                                              (uintptr_t) val,
Packit Service 97d2fb
                                              memory_order_acquire,
Packit Service 97d2fb
                                              memory_order_acquire);
Packit Service 97d2fb
Packit Service 97d2fb
      if (val_ptr == NULL)
Packit Service 97d2fb
        {
Packit Service 97d2fb
          atomic_store_explicit(&htab->table[idx].hashval, hval,
Packit Service 97d2fb
                                memory_order_release);
Packit Service 97d2fb
          return 0;
Packit Service 97d2fb
        }
Packit Service 97d2fb
      else
Packit Service 97d2fb
        {
Packit Service 97d2fb
          do
Packit Service 97d2fb
            {
Packit Service 97d2fb
              hash = atomic_load_explicit(&htab->table[idx].hashval,
Packit Service 97d2fb
                                          memory_order_acquire);
Packit Service 97d2fb
            }
Packit Service 97d2fb
          while (hash == 0);
Packit Service 97d2fb
          if (hash == hval)
Packit Service 97d2fb
            return -1;
Packit Service 97d2fb
        }
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Second hash function as suggested in [Knuth].  */
Packit Service 97d2fb
  HASHTYPE second_hash = 1 + hval % (htab->size - 2);
Packit Service 97d2fb
Packit Service 97d2fb
  for(;;)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (idx <= second_hash)
Packit Service 97d2fb
          idx = htab->size + idx - second_hash;
Packit Service 97d2fb
      else
Packit Service 97d2fb
          idx -= second_hash;
Packit Service 97d2fb
Packit Service 97d2fb
      hash = atomic_load_explicit(&htab->table[idx].hashval,
Packit Service 97d2fb
                                  memory_order_acquire);
Packit Service 97d2fb
      if (hash == hval)
Packit Service 97d2fb
        return -1;
Packit Service 97d2fb
      else if (hash == 0)
Packit Service 97d2fb
        {
Packit Service 97d2fb
          val_ptr = NULL;
Packit Service 97d2fb
          atomic_compare_exchange_strong_explicit(&htab->table[idx].val_ptr,
Packit Service 97d2fb
                                                  (uintptr_t *) &val_ptr,
Packit Service 97d2fb
                                                  (uintptr_t) val,
Packit Service 97d2fb
                                                  memory_order_acquire,
Packit Service 97d2fb
                                                  memory_order_acquire);
Packit Service 97d2fb
Packit Service 97d2fb
          if (val_ptr == NULL)
Packit Service 97d2fb
            {
Packit Service 97d2fb
              atomic_store_explicit(&htab->table[idx].hashval, hval,
Packit Service 97d2fb
                                    memory_order_release);
Packit Service 97d2fb
              return 0;
Packit Service 97d2fb
            }
Packit Service 97d2fb
          else
Packit Service 97d2fb
            {
Packit Service 97d2fb
              do
Packit Service 97d2fb
                {
Packit Service 97d2fb
                  hash = atomic_load_explicit(&htab->table[idx].hashval,
Packit Service 97d2fb
                                              memory_order_acquire);
Packit Service 97d2fb
                }
Packit Service 97d2fb
              while (hash == 0);
Packit Service 97d2fb
              if (hash == hval)
Packit Service 97d2fb
                return -1;
Packit Service 97d2fb
            }
Packit Service 97d2fb
        }
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
#define NO_RESIZING 0u
Packit Service 97d2fb
#define ALLOCATING_MEMORY 1u
Packit Service 97d2fb
#define MOVING_DATA 3u
Packit Service 97d2fb
#define CLEANING 2u
Packit Service 97d2fb
Packit Service 97d2fb
#define STATE_BITS 2u
Packit Service 97d2fb
#define STATE_INCREMENT (1u << STATE_BITS)
Packit Service 97d2fb
#define STATE_MASK (STATE_INCREMENT - 1)
Packit Service 97d2fb
#define GET_STATE(A) ((A) & STATE_MASK)
Packit Service 97d2fb
Packit Service 97d2fb
#define IS_NO_RESIZE_OR_CLEANING(A) (((A) & 0x1u) == 0)
Packit Service 97d2fb
Packit Service 97d2fb
#define GET_ACTIVE_WORKERS(A) ((A) >> STATE_BITS)
Packit Service 97d2fb
Packit Service 97d2fb
#define INITIALIZATION_BLOCK_SIZE 256
Packit Service 97d2fb
#define MOVE_BLOCK_SIZE 256
Packit Service 97d2fb
#define CEIL(A, B) (((A) + (B) - 1) / (B))
Packit Service 97d2fb
Packit Service 97d2fb
/* Initializes records and copies the data from the old table.
Packit Service 97d2fb
   It can share work with other threads */
Packit Service 97d2fb
static void resize_helper(NAME *htab, int blocking)
Packit Service 97d2fb
{
Packit Service 97d2fb
  size_t num_old_blocks = CEIL(htab->old_size, MOVE_BLOCK_SIZE);
Packit Service 97d2fb
  size_t num_new_blocks = CEIL(htab->size, INITIALIZATION_BLOCK_SIZE);
Packit Service 97d2fb
Packit Service 97d2fb
  size_t my_block;
Packit Service 97d2fb
  size_t num_finished_blocks = 0;
Packit Service 97d2fb
Packit Service 97d2fb
  while ((my_block = atomic_fetch_add_explicit(&htab->next_init_block, 1,
Packit Service 97d2fb
                                                memory_order_acquire))
Packit Service 97d2fb
                                                    < num_new_blocks)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      size_t record_it = my_block * INITIALIZATION_BLOCK_SIZE;
Packit Service 97d2fb
      size_t record_end = (my_block + 1) * INITIALIZATION_BLOCK_SIZE;
Packit Service 97d2fb
      if (record_end > htab->size)
Packit Service 97d2fb
          record_end = htab->size;
Packit Service 97d2fb
Packit Service 97d2fb
      while (record_it++ != record_end)
Packit Service 97d2fb
        {
Packit Service 97d2fb
          atomic_init(&htab->table[record_it].hashval, (uintptr_t) NULL);
Packit Service 97d2fb
          atomic_init(&htab->table[record_it].val_ptr, (uintptr_t) NULL);
Packit Service 97d2fb
        }
Packit Service 97d2fb
Packit Service 97d2fb
      num_finished_blocks++;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  atomic_fetch_add_explicit(&htab->num_initialized_blocks,
Packit Service 97d2fb
                            num_finished_blocks, memory_order_release);
Packit Service 97d2fb
  while (atomic_load_explicit(&htab->num_initialized_blocks,
Packit Service 97d2fb
                              memory_order_acquire) != num_new_blocks);
Packit Service 97d2fb
Packit Service 97d2fb
  /* All block are initialized, start moving */
Packit Service 97d2fb
  num_finished_blocks = 0;
Packit Service 97d2fb
  while ((my_block = atomic_fetch_add_explicit(&htab->next_move_block, 1,
Packit Service 97d2fb
                                                memory_order_acquire))
Packit Service 97d2fb
                                                    < num_old_blocks)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      size_t record_it = my_block * MOVE_BLOCK_SIZE;
Packit Service 97d2fb
      size_t record_end = (my_block + 1) * MOVE_BLOCK_SIZE;
Packit Service 97d2fb
      if (record_end > htab->old_size)
Packit Service 97d2fb
          record_end = htab->old_size;
Packit Service 97d2fb
Packit Service 97d2fb
      while (record_it++ != record_end)
Packit Service 97d2fb
        {
Packit Service 97d2fb
          TYPE val_ptr = (TYPE) atomic_load_explicit(
Packit Service 97d2fb
              &htab->old_table[record_it].val_ptr,
Packit Service 97d2fb
              memory_order_acquire);
Packit Service 97d2fb
          if (val_ptr == NULL)
Packit Service 97d2fb
              continue;
Packit Service 97d2fb
Packit Service 97d2fb
          HASHTYPE hashval = atomic_load_explicit(
Packit Service 97d2fb
              &htab->old_table[record_it].hashval,
Packit Service 97d2fb
              memory_order_acquire);
Packit Service 97d2fb
          assert(hashval);
Packit Service 97d2fb
Packit Service 97d2fb
          insert_helper(htab, hashval, val_ptr);
Packit Service 97d2fb
        }
Packit Service 97d2fb
Packit Service 97d2fb
      num_finished_blocks++;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  atomic_fetch_add_explicit(&htab->num_moved_blocks, num_finished_blocks,
Packit Service 97d2fb
                            memory_order_release);
Packit Service 97d2fb
Packit Service 97d2fb
  if (blocking)
Packit Service 97d2fb
      while (atomic_load_explicit(&htab->num_moved_blocks,
Packit Service 97d2fb
                                  memory_order_acquire) != num_old_blocks);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
resize_master(NAME *htab)
Packit Service 97d2fb
{
Packit Service 97d2fb
  htab->old_size = htab->size;
Packit Service 97d2fb
  htab->old_table = htab->table;
Packit Service 97d2fb
Packit Service 97d2fb
  htab->size = next_prime(htab->size * 2);
Packit Service 97d2fb
  htab->table = malloc((1 + htab->size) * sizeof(htab->table[0]));
Packit Service 97d2fb
  assert(htab->table);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Change state from ALLOCATING_MEMORY to MOVING_DATA */
Packit Service 97d2fb
  atomic_fetch_xor_explicit(&htab->resizing_state,
Packit Service 97d2fb
                            ALLOCATING_MEMORY ^ MOVING_DATA,
Packit Service 97d2fb
                            memory_order_release);
Packit Service 97d2fb
Packit Service 97d2fb
  resize_helper(htab, 1);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Change state from MOVING_DATA to CLEANING */
Packit Service 97d2fb
  size_t resize_state = atomic_fetch_xor_explicit(&htab->resizing_state,
Packit Service 97d2fb
                                                  MOVING_DATA ^ CLEANING,
Packit Service 97d2fb
                                                  memory_order_acq_rel);
Packit Service 97d2fb
  while (GET_ACTIVE_WORKERS(resize_state) != 0)
Packit Service 97d2fb
      resize_state = atomic_load_explicit(&htab->resizing_state,
Packit Service 97d2fb
                                          memory_order_acquire);
Packit Service 97d2fb
Packit Service 97d2fb
  /* There are no more active workers */
Packit Service 97d2fb
  atomic_store_explicit(&htab->next_init_block, 0, memory_order_relaxed);
Packit Service 97d2fb
  atomic_store_explicit(&htab->num_initialized_blocks, 0,
Packit Service 97d2fb
                        memory_order_relaxed);
Packit Service 97d2fb
Packit Service 97d2fb
  atomic_store_explicit(&htab->next_move_block, 0, memory_order_relaxed);
Packit Service 97d2fb
  atomic_store_explicit(&htab->num_moved_blocks, 0, memory_order_relaxed);
Packit Service 97d2fb
Packit Service 97d2fb
  free(htab->old_table);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Change state to NO_RESIZING */
Packit Service 97d2fb
  atomic_fetch_xor_explicit(&htab->resizing_state, CLEANING ^ NO_RESIZING,
Packit Service 97d2fb
                            memory_order_relaxed);
Packit Service 97d2fb
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
resize_worker(NAME *htab)
Packit Service 97d2fb
{
Packit Service 97d2fb
  size_t resize_state = atomic_load_explicit(&htab->resizing_state,
Packit Service 97d2fb
                                              memory_order_acquire);
Packit Service 97d2fb
Packit Service 97d2fb
  /* If the resize has finished */
Packit Service 97d2fb
  if (IS_NO_RESIZE_OR_CLEANING(resize_state))
Packit Service 97d2fb
      return;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Register as worker and check if the resize has finished in the meantime*/
Packit Service 97d2fb
  resize_state = atomic_fetch_add_explicit(&htab->resizing_state,
Packit Service 97d2fb
                                            STATE_INCREMENT,
Packit Service 97d2fb
                                            memory_order_acquire);
Packit Service 97d2fb
  if (IS_NO_RESIZE_OR_CLEANING(resize_state))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      atomic_fetch_sub_explicit(&htab->resizing_state, STATE_INCREMENT,
Packit Service 97d2fb
                                memory_order_relaxed);
Packit Service 97d2fb
      return;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Wait while the new table is being allocated. */
Packit Service 97d2fb
  while (GET_STATE(resize_state) == ALLOCATING_MEMORY)
Packit Service 97d2fb
      resize_state = atomic_load_explicit(&htab->resizing_state,
Packit Service 97d2fb
                                          memory_order_acquire);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Check if the resize is done */
Packit Service 97d2fb
  assert(GET_STATE(resize_state) != NO_RESIZING);
Packit Service 97d2fb
  if (GET_STATE(resize_state) == CLEANING)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      atomic_fetch_sub_explicit(&htab->resizing_state, STATE_INCREMENT,
Packit Service 97d2fb
                                memory_order_relaxed);
Packit Service 97d2fb
      return;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  resize_helper(htab, 0);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Deregister worker */
Packit Service 97d2fb
  atomic_fetch_sub_explicit(&htab->resizing_state, STATE_INCREMENT,
Packit Service 97d2fb
                            memory_order_release);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
#define INIT(name) _INIT (name)
Packit Service 97d2fb
#define _INIT(name) \
Packit Service 97d2fb
  name##_init
Packit Service 97d2fb
INIT(NAME) (NAME *htab, size_t init_size)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* We need the size to be a prime.  */
Packit Service 97d2fb
  init_size = next_prime (init_size);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Initialize the data structure.  */
Packit Service 97d2fb
  htab->size = init_size;
Packit Service 97d2fb
  atomic_init(&htab->filled, 0);
Packit Service 97d2fb
  atomic_init(&htab->resizing_state, 0);
Packit Service 97d2fb
Packit Service 97d2fb
  atomic_init(&htab->next_init_block, 0);
Packit Service 97d2fb
  atomic_init(&htab->num_initialized_blocks, 0);
Packit Service 97d2fb
Packit Service 97d2fb
  atomic_init(&htab->next_move_block, 0);
Packit Service 97d2fb
  atomic_init(&htab->num_moved_blocks, 0);
Packit Service 97d2fb
Packit Service 97d2fb
  pthread_rwlock_init(&htab->resize_rwl, NULL);
Packit Service 97d2fb
Packit Service 97d2fb
  htab->table = (void *) malloc ((init_size + 1) * sizeof (htab->table[0]));
Packit Service 97d2fb
  if (htab->table == NULL)
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  for (size_t i = 0; i <= init_size; i++)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      atomic_init(&htab->table[i].hashval, (uintptr_t) NULL);
Packit Service 97d2fb
      atomic_init(&htab->table[i].val_ptr, (uintptr_t) NULL);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
#define FREE(name) _FREE (name)
Packit Service 97d2fb
#define _FREE(name) \
Packit Service 97d2fb
name##_free
Packit Service 97d2fb
FREE(NAME) (NAME *htab)
Packit Service 97d2fb
{
Packit Service 97d2fb
  pthread_rwlock_destroy(&htab->resize_rwl);
Packit Service 97d2fb
  free (htab->table);
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
#define INSERT(name) _INSERT (name)
Packit Service 97d2fb
#define _INSERT(name) \
Packit Service 97d2fb
name##_insert
Packit Service 97d2fb
INSERT(NAME) (NAME *htab, HASHTYPE hval, TYPE data)
Packit Service 97d2fb
{
Packit Service 97d2fb
  int incremented = 0;
Packit Service 97d2fb
Packit Service 97d2fb
  for(;;)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      while (pthread_rwlock_tryrdlock(&htab->resize_rwl) != 0)
Packit Service 97d2fb
          resize_worker(htab);
Packit Service 97d2fb
Packit Service 97d2fb
      size_t filled;
Packit Service 97d2fb
      if (!incremented)
Packit Service 97d2fb
        {
Packit Service 97d2fb
          filled = atomic_fetch_add_explicit(&htab->filled, 1,
Packit Service 97d2fb
                                              memory_order_acquire);
Packit Service 97d2fb
          incremented = 1;
Packit Service 97d2fb
        }
Packit Service 97d2fb
      else
Packit Service 97d2fb
        {
Packit Service 97d2fb
          filled = atomic_load_explicit(&htab->filled,
Packit Service 97d2fb
                                        memory_order_acquire);
Packit Service 97d2fb
        }
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
      if (100 * filled > 90 * htab->size)
Packit Service 97d2fb
        {
Packit Service 97d2fb
          /* Table is filled more than 90%.  Resize the table.  */
Packit Service 97d2fb
Packit Service 97d2fb
          size_t resizing_state = atomic_load_explicit(&htab->resizing_state,
Packit Service 97d2fb
                                                        memory_order_acquire);
Packit Service 97d2fb
          if (resizing_state == 0 &&
Packit Service 97d2fb
              atomic_compare_exchange_strong_explicit(&htab->resizing_state,
Packit Service 97d2fb
                                                      &resizing_state,
Packit Service 97d2fb
                                                      ALLOCATING_MEMORY,
Packit Service 97d2fb
                                                      memory_order_acquire,
Packit Service 97d2fb
                                                      memory_order_acquire))
Packit Service 97d2fb
            {
Packit Service 97d2fb
              /* Master thread */
Packit Service 97d2fb
              pthread_rwlock_unlock(&htab->resize_rwl);
Packit Service 97d2fb
Packit Service 97d2fb
              pthread_rwlock_wrlock(&htab->resize_rwl);
Packit Service 97d2fb
              resize_master(htab);
Packit Service 97d2fb
              pthread_rwlock_unlock(&htab->resize_rwl);
Packit Service 97d2fb
Packit Service 97d2fb
            }
Packit Service 97d2fb
          else
Packit Service 97d2fb
            {
Packit Service 97d2fb
              /* Worker thread */
Packit Service 97d2fb
              pthread_rwlock_unlock(&htab->resize_rwl);
Packit Service 97d2fb
              resize_worker(htab);
Packit Service 97d2fb
            }
Packit Service 97d2fb
        }
Packit Service 97d2fb
      else
Packit Service 97d2fb
        {
Packit Service 97d2fb
          /* Lock acquired, no need for resize*/
Packit Service 97d2fb
          break;
Packit Service 97d2fb
        }
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  int ret_val = insert_helper(htab, hval, data);
Packit Service 97d2fb
  if (ret_val == -1)
Packit Service 97d2fb
      atomic_fetch_sub_explicit(&htab->filled, 1, memory_order_relaxed);
Packit Service 97d2fb
  pthread_rwlock_unlock(&htab->resize_rwl);
Packit Service 97d2fb
  return ret_val;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
TYPE
Packit Service 97d2fb
#define FIND(name) _FIND (name)
Packit Service 97d2fb
#define _FIND(name) \
Packit Service 97d2fb
  name##_find
Packit Service 97d2fb
FIND(NAME) (NAME *htab, HASHTYPE hval)
Packit Service 97d2fb
{
Packit Service 97d2fb
  while (pthread_rwlock_tryrdlock(&htab->resize_rwl) != 0)
Packit Service 97d2fb
      resize_worker(htab);
Packit Service 97d2fb
Packit Service 97d2fb
  size_t idx;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Make the hash data nonzero.  */
Packit Service 97d2fb
  hval = hval ?: 1;
Packit Service 97d2fb
  idx = lookup(htab, hval);
Packit Service 97d2fb
Packit Service 97d2fb
  if (idx == 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      pthread_rwlock_unlock(&htab->resize_rwl);
Packit Service 97d2fb
      return NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* get a copy before unlocking the lock */
Packit Service 97d2fb
  TYPE ret_val = (TYPE) atomic_load_explicit(&htab->table[idx].val_ptr,
Packit Service 97d2fb
                                             memory_order_relaxed);
Packit Service 97d2fb
Packit Service 97d2fb
  pthread_rwlock_unlock(&htab->resize_rwl);
Packit Service 97d2fb
  return ret_val;
Packit Service 97d2fb
}