1/** 2 * \file hash.c 3 * Generic hash table. 4 * 5 * Used for display lists, texture objects, vertex/fragment programs, 6 * buffer objects, etc. The hash functions are thread-safe. 7 * 8 * \note key=0 is illegal. 9 * 10 * \author Brian Paul 11 */ 12 13/* 14 * Mesa 3-D graphics library 15 * 16 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 17 * 18 * Permission is hereby granted, free of charge, to any person obtaining a 19 * copy of this software and associated documentation files (the "Software"), 20 * to deal in the Software without restriction, including without limitation 21 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 22 * and/or sell copies of the Software, and to permit persons to whom the 23 * Software is furnished to do so, subject to the following conditions: 24 * 25 * The above copyright notice and this permission notice shall be included 26 * in all copies or substantial portions of the Software. 27 * 28 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 29 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 30 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 31 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 32 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 33 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 34 * OTHER DEALINGS IN THE SOFTWARE. 35 */ 36 37#include "errors.h" 38#include "glheader.h" 39#include "hash.h" 40#include "util/hash_table.h" 41 42 43/** 44 * Create a new hash table. 45 * 46 * \return pointer to a new, empty hash table. 47 */ 48struct _mesa_HashTable * 49_mesa_NewHashTable(void) 50{ 51 struct _mesa_HashTable *table = CALLOC_STRUCT(_mesa_HashTable); 52 53 if (table) { 54 table->ht = _mesa_hash_table_create(NULL, uint_key_hash, 55 uint_key_compare); 56 if (table->ht == NULL) { 57 free(table); 58 _mesa_error_no_memory(__func__); 59 return NULL; 60 } 61 62 _mesa_hash_table_set_deleted_key(table->ht, uint_key(DELETED_KEY_VALUE)); 63 /* 64 * Needs to be recursive, since the callback in _mesa_HashWalk() 65 * is allowed to call _mesa_HashRemove(). 66 */ 67 mtx_init(&table->Mutex, mtx_recursive); 68 } 69 else { 70 _mesa_error_no_memory(__func__); 71 } 72 73 return table; 74} 75 76 77 78/** 79 * Delete a hash table. 80 * Frees each entry on the hash table and then the hash table structure itself. 81 * Note that the caller should have already traversed the table and deleted 82 * the objects in the table (i.e. We don't free the entries' data pointer). 83 * 84 * \param table the hash table to delete. 85 */ 86void 87_mesa_DeleteHashTable(struct _mesa_HashTable *table) 88{ 89 assert(table); 90 91 if (_mesa_hash_table_next_entry(table->ht, NULL) != NULL) { 92 _mesa_problem(NULL, "In _mesa_DeleteHashTable, found non-freed data"); 93 } 94 95 _mesa_hash_table_destroy(table->ht, NULL); 96 97 mtx_destroy(&table->Mutex); 98 free(table); 99} 100 101 102 103/** 104 * Lookup an entry in the hash table, without locking. 105 * \sa _mesa_HashLookup 106 */ 107static inline void * 108_mesa_HashLookup_unlocked(struct _mesa_HashTable *table, GLuint key) 109{ 110 const struct hash_entry *entry; 111 112 assert(table); 113 assert(key); 114 115 if (key == DELETED_KEY_VALUE) 116 return table->deleted_key_data; 117 118 entry = _mesa_hash_table_search_pre_hashed(table->ht, 119 uint_hash(key), 120 uint_key(key)); 121 if (!entry) 122 return NULL; 123 124 return entry->data; 125} 126 127 128/** 129 * Lookup an entry in the hash table. 130 * 131 * \param table the hash table. 132 * \param key the key. 133 * 134 * \return pointer to user's data or NULL if key not in table 135 */ 136void * 137_mesa_HashLookup(struct _mesa_HashTable *table, GLuint key) 138{ 139 void *res; 140 _mesa_HashLockMutex(table); 141 res = _mesa_HashLookup_unlocked(table, key); 142 _mesa_HashUnlockMutex(table); 143 return res; 144} 145 146 147/** 148 * Lookup an entry in the hash table without locking the mutex. 149 * 150 * The hash table mutex must be locked manually by calling 151 * _mesa_HashLockMutex() before calling this function. 152 * 153 * \param table the hash table. 154 * \param key the key. 155 * 156 * \return pointer to user's data or NULL if key not in table 157 */ 158void * 159_mesa_HashLookupLocked(struct _mesa_HashTable *table, GLuint key) 160{ 161 return _mesa_HashLookup_unlocked(table, key); 162} 163 164 165static inline void 166_mesa_HashInsert_unlocked(struct _mesa_HashTable *table, GLuint key, void *data) 167{ 168 uint32_t hash = uint_hash(key); 169 struct hash_entry *entry; 170 171 assert(table); 172 assert(key); 173 174 if (key > table->MaxKey) 175 table->MaxKey = key; 176 177 if (key == DELETED_KEY_VALUE) { 178 table->deleted_key_data = data; 179 } else { 180 entry = _mesa_hash_table_search_pre_hashed(table->ht, hash, uint_key(key)); 181 if (entry) { 182 entry->data = data; 183 } else { 184 _mesa_hash_table_insert_pre_hashed(table->ht, hash, uint_key(key), data); 185 } 186 } 187} 188 189 190/** 191 * Insert a key/pointer pair into the hash table without locking the mutex. 192 * If an entry with this key already exists we'll replace the existing entry. 193 * 194 * The hash table mutex must be locked manually by calling 195 * _mesa_HashLockMutex() before calling this function. 196 * 197 * \param table the hash table. 198 * \param key the key (not zero). 199 * \param data pointer to user data. 200 */ 201void 202_mesa_HashInsertLocked(struct _mesa_HashTable *table, GLuint key, void *data) 203{ 204 _mesa_HashInsert_unlocked(table, key, data); 205} 206 207 208/** 209 * Insert a key/pointer pair into the hash table. 210 * If an entry with this key already exists we'll replace the existing entry. 211 * 212 * \param table the hash table. 213 * \param key the key (not zero). 214 * \param data pointer to user data. 215 */ 216void 217_mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *data) 218{ 219 _mesa_HashLockMutex(table); 220 _mesa_HashInsert_unlocked(table, key, data); 221 _mesa_HashUnlockMutex(table); 222} 223 224 225/** 226 * Remove an entry from the hash table. 227 * 228 * \param table the hash table. 229 * \param key key of entry to remove. 230 * 231 * While holding the hash table's lock, searches the entry with the matching 232 * key and unlinks it. 233 */ 234static inline void 235_mesa_HashRemove_unlocked(struct _mesa_HashTable *table, GLuint key) 236{ 237 struct hash_entry *entry; 238 239 assert(table); 240 assert(key); 241 242 /* assert if _mesa_HashRemove illegally called from _mesa_HashDeleteAll 243 * callback function. Have to check this outside of mutex lock. 244 */ 245 assert(!table->InDeleteAll); 246 247 if (key == DELETED_KEY_VALUE) { 248 table->deleted_key_data = NULL; 249 } else { 250 entry = _mesa_hash_table_search_pre_hashed(table->ht, 251 uint_hash(key), 252 uint_key(key)); 253 _mesa_hash_table_remove(table->ht, entry); 254 } 255} 256 257 258void 259_mesa_HashRemoveLocked(struct _mesa_HashTable *table, GLuint key) 260{ 261 _mesa_HashRemove_unlocked(table, key); 262} 263 264void 265_mesa_HashRemove(struct _mesa_HashTable *table, GLuint key) 266{ 267 _mesa_HashLockMutex(table); 268 _mesa_HashRemove_unlocked(table, key); 269 _mesa_HashUnlockMutex(table); 270} 271 272/** 273 * Delete all entries in a hash table, but don't delete the table itself. 274 * Invoke the given callback function for each table entry. 275 * 276 * \param table the hash table to delete 277 * \param callback the callback function 278 * \param userData arbitrary pointer to pass along to the callback 279 * (this is typically a struct gl_context pointer) 280 */ 281void 282_mesa_HashDeleteAll(struct _mesa_HashTable *table, 283 void (*callback)(GLuint key, void *data, void *userData), 284 void *userData) 285{ 286 assert(callback); 287 _mesa_HashLockMutex(table); 288 table->InDeleteAll = GL_TRUE; 289 hash_table_foreach(table->ht, entry) { 290 callback((uintptr_t)entry->key, entry->data, userData); 291 _mesa_hash_table_remove(table->ht, entry); 292 } 293 if (table->deleted_key_data) { 294 callback(DELETED_KEY_VALUE, table->deleted_key_data, userData); 295 table->deleted_key_data = NULL; 296 } 297 table->InDeleteAll = GL_FALSE; 298 _mesa_HashUnlockMutex(table); 299} 300 301 302/** 303 * Walk over all entries in a hash table, calling callback function for each. 304 * \param table the hash table to walk 305 * \param callback the callback function 306 * \param userData arbitrary pointer to pass along to the callback 307 * (this is typically a struct gl_context pointer) 308 */ 309static void 310hash_walk_unlocked(const struct _mesa_HashTable *table, 311 void (*callback)(GLuint key, void *data, void *userData), 312 void *userData) 313{ 314 assert(table); 315 assert(callback); 316 317 hash_table_foreach(table->ht, entry) { 318 callback((uintptr_t)entry->key, entry->data, userData); 319 } 320 if (table->deleted_key_data) 321 callback(DELETED_KEY_VALUE, table->deleted_key_data, userData); 322} 323 324 325void 326_mesa_HashWalk(const struct _mesa_HashTable *table, 327 void (*callback)(GLuint key, void *data, void *userData), 328 void *userData) 329{ 330 /* cast-away const */ 331 struct _mesa_HashTable *table2 = (struct _mesa_HashTable *) table; 332 333 _mesa_HashLockMutex(table2); 334 hash_walk_unlocked(table, callback, userData); 335 _mesa_HashUnlockMutex(table2); 336} 337 338void 339_mesa_HashWalkLocked(const struct _mesa_HashTable *table, 340 void (*callback)(GLuint key, void *data, void *userData), 341 void *userData) 342{ 343 hash_walk_unlocked(table, callback, userData); 344} 345 346static void 347debug_print_entry(GLuint key, void *data, void *userData) 348{ 349 _mesa_debug(NULL, "%u %p\n", key, data); 350} 351 352/** 353 * Dump contents of hash table for debugging. 354 * 355 * \param table the hash table. 356 */ 357void 358_mesa_HashPrint(const struct _mesa_HashTable *table) 359{ 360 if (table->deleted_key_data) 361 debug_print_entry(DELETED_KEY_VALUE, table->deleted_key_data, NULL); 362 _mesa_HashWalk(table, debug_print_entry, NULL); 363} 364 365 366/** 367 * Find a block of adjacent unused hash keys. 368 * 369 * \param table the hash table. 370 * \param numKeys number of keys needed. 371 * 372 * \return Starting key of free block or 0 if failure. 373 * 374 * If there are enough free keys between the maximum key existing in the table 375 * (_mesa_HashTable::MaxKey) and the maximum key possible, then simply return 376 * the adjacent key. Otherwise do a full search for a free key block in the 377 * allowable key range. 378 */ 379GLuint 380_mesa_HashFindFreeKeyBlock(struct _mesa_HashTable *table, GLuint numKeys) 381{ 382 const GLuint maxKey = ~((GLuint) 0) - 1; 383 if (maxKey - numKeys > table->MaxKey) { 384 /* the quick solution */ 385 return table->MaxKey + 1; 386 } 387 else { 388 /* the slow solution */ 389 GLuint freeCount = 0; 390 GLuint freeStart = 1; 391 GLuint key; 392 for (key = 1; key != maxKey; key++) { 393 if (_mesa_HashLookup_unlocked(table, key)) { 394 /* darn, this key is already in use */ 395 freeCount = 0; 396 freeStart = key+1; 397 } 398 else { 399 /* this key not in use, check if we've found enough */ 400 freeCount++; 401 if (freeCount == numKeys) { 402 return freeStart; 403 } 404 } 405 } 406 /* cannot allocate a block of numKeys consecutive keys */ 407 return 0; 408 } 409} 410 411 412/** 413 * Return the number of entries in the hash table. 414 */ 415GLuint 416_mesa_HashNumEntries(const struct _mesa_HashTable *table) 417{ 418 GLuint count = 0; 419 420 if (table->deleted_key_data) 421 count++; 422 423 count += _mesa_hash_table_num_entries(table->ht); 424 425 return count; 426} 427