| 1 | /* Fully-inline hash table, used mainly for managing TLS descriptors. | 
| 2 |    Copyright (C) 1999-2023 Free Software Foundation, Inc. | 
| 3 |    This file is part of the GNU C Library. | 
| 4 |  | 
| 5 |    This file is derived from a 2003's version of libiberty's | 
| 6 |    hashtab.c, contributed by Vladimir Makarov (vmakarov@cygnus.com), | 
| 7 |    but with most adaptation points and support for deleting elements | 
| 8 |    removed. | 
| 9 |  | 
| 10 |    The GNU C Library is free software; you can redistribute it and/or | 
| 11 |    modify it under the terms of the GNU Lesser General Public | 
| 12 |    License as published by the Free Software Foundation; either | 
| 13 |    version 2.1 of the License, or (at your option) any later version. | 
| 14 |  | 
| 15 |    The GNU C Library is distributed in the hope that it will be useful, | 
| 16 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| 17 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
| 18 |    Lesser General Public License for more details. | 
| 19 |  | 
| 20 |    You should have received a copy of the GNU Lesser General Public | 
| 21 |    License along with the GNU C Library; if not, see | 
| 22 |    <https://www.gnu.org/licenses/>.  */ | 
| 23 |  | 
| 24 | #ifndef INLINE_HASHTAB_H | 
| 25 | # define INLINE_HASHTAB_H 1 | 
| 26 |  | 
| 27 | struct hashtab | 
| 28 | { | 
| 29 |   /* Table itself.  */ | 
| 30 |   void **entries; | 
| 31 |  | 
| 32 |   /* Current size (in entries) of the hash table */ | 
| 33 |   size_t size; | 
| 34 |  | 
| 35 |   /* Current number of elements.  */ | 
| 36 |   size_t n_elements; | 
| 37 |  | 
| 38 |   /* Free function for the entries array.  This may vary depending on | 
| 39 |      how early the array was allocated.  If it is NULL, then the array | 
| 40 |      can't be freed.  */ | 
| 41 |   void (*free) (void *ptr); | 
| 42 | }; | 
| 43 |  | 
| 44 | inline static struct hashtab * | 
| 45 | htab_create (void) | 
| 46 | { | 
| 47 |   struct hashtab *ht = malloc (sizeof (struct hashtab)); | 
| 48 |  | 
| 49 |   if (! ht) | 
| 50 |     return NULL; | 
| 51 |   ht->size = 3; | 
| 52 |   ht->entries = malloc (sizeof (void *) * ht->size); | 
| 53 |   ht->free = __rtld_free; | 
| 54 |   if (! ht->entries) | 
| 55 |     { | 
| 56 |       free (ht); | 
| 57 |       return NULL; | 
| 58 |     } | 
| 59 |  | 
| 60 |   ht->n_elements = 0; | 
| 61 |  | 
| 62 |   memset (ht->entries, 0, sizeof (void *) * ht->size); | 
| 63 |  | 
| 64 |   return ht; | 
| 65 | } | 
| 66 |  | 
| 67 | /* This is only called from _dl_unmap, so it's safe to call | 
| 68 |    free().  */ | 
| 69 | inline static void | 
| 70 | htab_delete (struct hashtab *htab) | 
| 71 | { | 
| 72 |   int i; | 
| 73 |  | 
| 74 |   for (i = htab->size - 1; i >= 0; i--) | 
| 75 |     free (htab->entries[i]); | 
| 76 |  | 
| 77 |   htab->free (htab->entries); | 
| 78 |   free (htab); | 
| 79 | } | 
| 80 |  | 
| 81 | /* Similar to htab_find_slot, but without several unwanted side effects: | 
| 82 |     - Does not call htab->eq_f when it finds an existing entry. | 
| 83 |     - Does not change the count of elements/searches/collisions in the | 
| 84 |       hash table. | 
| 85 |    This function also assumes there are no deleted entries in the table. | 
| 86 |    HASH is the hash value for the element to be inserted.  */ | 
| 87 |  | 
| 88 | inline static void ** | 
| 89 | find_empty_slot_for_expand (struct hashtab *htab, int hash) | 
| 90 | { | 
| 91 |   size_t size = htab->size; | 
| 92 |   unsigned int index = hash % size; | 
| 93 |   void **slot = htab->entries + index; | 
| 94 |   int hash2; | 
| 95 |  | 
| 96 |   if (! *slot) | 
| 97 |     return slot; | 
| 98 |  | 
| 99 |   hash2 = 1 + hash % (size - 2); | 
| 100 |   for (;;) | 
| 101 |     { | 
| 102 |       index += hash2; | 
| 103 |       if (index >= size) | 
| 104 | 	index -= size; | 
| 105 |  | 
| 106 |       slot = htab->entries + index; | 
| 107 |       if (! *slot) | 
| 108 | 	return slot; | 
| 109 |     } | 
| 110 | } | 
| 111 |  | 
| 112 | /* The following function changes size of memory allocated for the | 
| 113 |    entries and repeatedly inserts the table elements.  The occupancy | 
| 114 |    of the table after the call will be about 50%.  Naturally the hash | 
| 115 |    table must already exist.  Remember also that the place of the | 
| 116 |    table entries is changed.  If memory allocation failures are allowed, | 
| 117 |    this function will return zero, indicating that the table could not be | 
| 118 |    expanded.  If all goes well, it will return a non-zero value.  */ | 
| 119 |  | 
| 120 | inline static int | 
| 121 | htab_expand (struct hashtab *htab, int (*hash_fn) (void *)) | 
| 122 | { | 
| 123 |   void **oentries; | 
| 124 |   void **olimit; | 
| 125 |   void **p; | 
| 126 |   void **nentries; | 
| 127 |   size_t nsize; | 
| 128 |  | 
| 129 |   oentries = htab->entries; | 
| 130 |   olimit = oentries + htab->size; | 
| 131 |  | 
| 132 |   /* Resize only when table after removal of unused elements is either | 
| 133 |      too full or too empty.  */ | 
| 134 |   if (htab->n_elements * 2 > htab->size) | 
| 135 |     nsize = _dl_higher_prime_number (htab->n_elements * 2); | 
| 136 |   else | 
| 137 |     nsize = htab->size; | 
| 138 |  | 
| 139 |   nentries = calloc (sizeof (void *), nsize); | 
| 140 |   if (nentries == NULL) | 
| 141 |     return 0; | 
| 142 |   htab->entries = nentries; | 
| 143 |   htab->size = nsize; | 
| 144 |  | 
| 145 |   p = oentries; | 
| 146 |   do | 
| 147 |     { | 
| 148 |       if (*p) | 
| 149 | 	*find_empty_slot_for_expand (htab, hash_fn (*p)) | 
| 150 | 	  = *p; | 
| 151 |  | 
| 152 |       p++; | 
| 153 |     } | 
| 154 |   while (p < olimit); | 
| 155 |  | 
| 156 |   /* Without recording the free corresponding to the malloc used to | 
| 157 |      allocate the table, we couldn't tell whether this was allocated | 
| 158 |      by the malloc() built into ld.so or the one in the main | 
| 159 |      executable or libc.  Calling free() for something that was | 
| 160 |      allocated by the early malloc(), rather than the final run-time | 
| 161 |      malloc() could do Very Bad Things (TM).  We will waste memory | 
| 162 |      allocated early as long as there's no corresponding free(), but | 
| 163 |      this isn't so much memory as to be significant.  */ | 
| 164 |  | 
| 165 |   htab->free (oentries); | 
| 166 |  | 
| 167 |   /* Use the free() corresponding to the malloc() above to free this | 
| 168 |      up.  */ | 
| 169 |   htab->free = __rtld_free; | 
| 170 |  | 
| 171 |   return 1; | 
| 172 | } | 
| 173 |  | 
| 174 | /* This function searches for a hash table slot containing an entry | 
| 175 |    equal to the given element.  To delete an entry, call this with | 
| 176 |    INSERT = 0, then call htab_clear_slot on the slot returned (possibly | 
| 177 |    after doing some checks).  To insert an entry, call this with | 
| 178 |    INSERT = 1, then write the value you want into the returned slot. | 
| 179 |    When inserting an entry, NULL may be returned if memory allocation | 
| 180 |    fails.  */ | 
| 181 |  | 
| 182 | inline static void ** | 
| 183 | htab_find_slot (struct hashtab *htab, void *ptr, int insert, | 
| 184 | 		int (*hash_fn)(void *), int (*eq_fn)(void *, void *)) | 
| 185 | { | 
| 186 |   unsigned int index; | 
| 187 |   int hash, hash2; | 
| 188 |   size_t size; | 
| 189 |   void **entry; | 
| 190 |  | 
| 191 |   if (htab->size * 3 <= htab->n_elements * 4 | 
| 192 |       && htab_expand (htab, hash_fn) == 0) | 
| 193 |     return NULL; | 
| 194 |  | 
| 195 |   hash = hash_fn (ptr); | 
| 196 |  | 
| 197 |   size = htab->size; | 
| 198 |   index = hash % size; | 
| 199 |  | 
| 200 |   entry = &htab->entries[index]; | 
| 201 |   if (!*entry) | 
| 202 |     goto empty_entry; | 
| 203 |   else if (eq_fn (*entry, ptr)) | 
| 204 |     return entry; | 
| 205 |  | 
| 206 |   hash2 = 1 + hash % (size - 2); | 
| 207 |   for (;;) | 
| 208 |     { | 
| 209 |       index += hash2; | 
| 210 |       if (index >= size) | 
| 211 | 	index -= size; | 
| 212 |  | 
| 213 |       entry = &htab->entries[index]; | 
| 214 |       if (!*entry) | 
| 215 | 	goto empty_entry; | 
| 216 |       else if (eq_fn (*entry, ptr)) | 
| 217 | 	return entry; | 
| 218 |     } | 
| 219 |  | 
| 220 |  empty_entry: | 
| 221 |   if (!insert) | 
| 222 |     return NULL; | 
| 223 |  | 
| 224 |   htab->n_elements++; | 
| 225 |   return entry; | 
| 226 | } | 
| 227 |  | 
| 228 | #endif /* INLINE_HASHTAB_H */ | 
| 229 |  |