1848b8605Smrg/** 2848b8605Smrg * \file hash.c 3848b8605Smrg * Generic hash table. 4848b8605Smrg * 5848b8605Smrg * Used for display lists, texture objects, vertex/fragment programs, 6848b8605Smrg * buffer objects, etc. The hash functions are thread-safe. 7848b8605Smrg * 8848b8605Smrg * \note key=0 is illegal. 9848b8605Smrg * 10848b8605Smrg * \author Brian Paul 11848b8605Smrg */ 12848b8605Smrg 13848b8605Smrg/* 14848b8605Smrg * Mesa 3-D graphics library 15848b8605Smrg * 16848b8605Smrg * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 17848b8605Smrg * 18848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 19848b8605Smrg * copy of this software and associated documentation files (the "Software"), 20848b8605Smrg * to deal in the Software without restriction, including without limitation 21848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 22848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 23848b8605Smrg * Software is furnished to do so, subject to the following conditions: 24848b8605Smrg * 25848b8605Smrg * The above copyright notice and this permission notice shall be included 26848b8605Smrg * in all copies or substantial portions of the Software. 27848b8605Smrg * 28848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 29848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 30848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 31848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 32848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 33848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 34848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 35848b8605Smrg */ 36848b8605Smrg 37b8e80941Smrg#include "errors.h" 38848b8605Smrg#include "glheader.h" 39848b8605Smrg#include "hash.h" 40848b8605Smrg#include "util/hash_table.h" 41848b8605Smrg 42848b8605Smrg 43848b8605Smrg/** 44848b8605Smrg * Create a new hash table. 45848b8605Smrg * 46848b8605Smrg * \return pointer to a new, empty hash table. 47848b8605Smrg */ 48848b8605Smrgstruct _mesa_HashTable * 49848b8605Smrg_mesa_NewHashTable(void) 50848b8605Smrg{ 51848b8605Smrg struct _mesa_HashTable *table = CALLOC_STRUCT(_mesa_HashTable); 52848b8605Smrg 53848b8605Smrg if (table) { 54b8e80941Smrg table->ht = _mesa_hash_table_create(NULL, uint_key_hash, 55b8e80941Smrg uint_key_compare); 56848b8605Smrg if (table->ht == NULL) { 57848b8605Smrg free(table); 58848b8605Smrg _mesa_error_no_memory(__func__); 59848b8605Smrg return NULL; 60848b8605Smrg } 61848b8605Smrg 62848b8605Smrg _mesa_hash_table_set_deleted_key(table->ht, uint_key(DELETED_KEY_VALUE)); 63b8e80941Smrg /* 64b8e80941Smrg * Needs to be recursive, since the callback in _mesa_HashWalk() 65b8e80941Smrg * is allowed to call _mesa_HashRemove(). 66b8e80941Smrg */ 67b8e80941Smrg mtx_init(&table->Mutex, mtx_recursive); 68848b8605Smrg } 69848b8605Smrg else { 70848b8605Smrg _mesa_error_no_memory(__func__); 71848b8605Smrg } 72848b8605Smrg 73848b8605Smrg return table; 74848b8605Smrg} 75848b8605Smrg 76848b8605Smrg 77848b8605Smrg 78848b8605Smrg/** 79848b8605Smrg * Delete a hash table. 80848b8605Smrg * Frees each entry on the hash table and then the hash table structure itself. 81848b8605Smrg * Note that the caller should have already traversed the table and deleted 82848b8605Smrg * the objects in the table (i.e. We don't free the entries' data pointer). 83848b8605Smrg * 84848b8605Smrg * \param table the hash table to delete. 85848b8605Smrg */ 86848b8605Smrgvoid 87848b8605Smrg_mesa_DeleteHashTable(struct _mesa_HashTable *table) 88848b8605Smrg{ 89848b8605Smrg assert(table); 90848b8605Smrg 91848b8605Smrg if (_mesa_hash_table_next_entry(table->ht, NULL) != NULL) { 92848b8605Smrg _mesa_problem(NULL, "In _mesa_DeleteHashTable, found non-freed data"); 93848b8605Smrg } 94848b8605Smrg 95848b8605Smrg _mesa_hash_table_destroy(table->ht, NULL); 96848b8605Smrg 97848b8605Smrg mtx_destroy(&table->Mutex); 98848b8605Smrg free(table); 99848b8605Smrg} 100848b8605Smrg 101848b8605Smrg 102848b8605Smrg 103848b8605Smrg/** 104848b8605Smrg * Lookup an entry in the hash table, without locking. 105848b8605Smrg * \sa _mesa_HashLookup 106848b8605Smrg */ 107848b8605Smrgstatic inline void * 108848b8605Smrg_mesa_HashLookup_unlocked(struct _mesa_HashTable *table, GLuint key) 109848b8605Smrg{ 110848b8605Smrg const struct hash_entry *entry; 111848b8605Smrg 112848b8605Smrg assert(table); 113848b8605Smrg assert(key); 114848b8605Smrg 115848b8605Smrg if (key == DELETED_KEY_VALUE) 116848b8605Smrg return table->deleted_key_data; 117848b8605Smrg 118b8e80941Smrg entry = _mesa_hash_table_search_pre_hashed(table->ht, 119b8e80941Smrg uint_hash(key), 120b8e80941Smrg uint_key(key)); 121848b8605Smrg if (!entry) 122848b8605Smrg return NULL; 123848b8605Smrg 124848b8605Smrg return entry->data; 125848b8605Smrg} 126848b8605Smrg 127848b8605Smrg 128848b8605Smrg/** 129848b8605Smrg * Lookup an entry in the hash table. 130848b8605Smrg * 131848b8605Smrg * \param table the hash table. 132848b8605Smrg * \param key the key. 133848b8605Smrg * 134848b8605Smrg * \return pointer to user's data or NULL if key not in table 135848b8605Smrg */ 136848b8605Smrgvoid * 137848b8605Smrg_mesa_HashLookup(struct _mesa_HashTable *table, GLuint key) 138848b8605Smrg{ 139848b8605Smrg void *res; 140b8e80941Smrg _mesa_HashLockMutex(table); 141848b8605Smrg res = _mesa_HashLookup_unlocked(table, key); 142b8e80941Smrg _mesa_HashUnlockMutex(table); 143848b8605Smrg return res; 144848b8605Smrg} 145848b8605Smrg 146848b8605Smrg 147848b8605Smrg/** 148848b8605Smrg * Lookup an entry in the hash table without locking the mutex. 149848b8605Smrg * 150848b8605Smrg * The hash table mutex must be locked manually by calling 151848b8605Smrg * _mesa_HashLockMutex() before calling this function. 152848b8605Smrg * 153848b8605Smrg * \param table the hash table. 154848b8605Smrg * \param key the key. 155848b8605Smrg * 156848b8605Smrg * \return pointer to user's data or NULL if key not in table 157848b8605Smrg */ 158848b8605Smrgvoid * 159848b8605Smrg_mesa_HashLookupLocked(struct _mesa_HashTable *table, GLuint key) 160848b8605Smrg{ 161848b8605Smrg return _mesa_HashLookup_unlocked(table, key); 162848b8605Smrg} 163848b8605Smrg 164848b8605Smrg 165848b8605Smrgstatic inline void 166848b8605Smrg_mesa_HashInsert_unlocked(struct _mesa_HashTable *table, GLuint key, void *data) 167848b8605Smrg{ 168848b8605Smrg uint32_t hash = uint_hash(key); 169848b8605Smrg struct hash_entry *entry; 170848b8605Smrg 171848b8605Smrg assert(table); 172848b8605Smrg assert(key); 173848b8605Smrg 174848b8605Smrg if (key > table->MaxKey) 175848b8605Smrg table->MaxKey = key; 176848b8605Smrg 177848b8605Smrg if (key == DELETED_KEY_VALUE) { 178848b8605Smrg table->deleted_key_data = data; 179848b8605Smrg } else { 180b8e80941Smrg entry = _mesa_hash_table_search_pre_hashed(table->ht, hash, uint_key(key)); 181848b8605Smrg if (entry) { 182848b8605Smrg entry->data = data; 183848b8605Smrg } else { 184b8e80941Smrg _mesa_hash_table_insert_pre_hashed(table->ht, hash, uint_key(key), data); 185848b8605Smrg } 186848b8605Smrg } 187848b8605Smrg} 188848b8605Smrg 189848b8605Smrg 190848b8605Smrg/** 191848b8605Smrg * Insert a key/pointer pair into the hash table without locking the mutex. 192848b8605Smrg * If an entry with this key already exists we'll replace the existing entry. 193848b8605Smrg * 194848b8605Smrg * The hash table mutex must be locked manually by calling 195848b8605Smrg * _mesa_HashLockMutex() before calling this function. 196848b8605Smrg * 197848b8605Smrg * \param table the hash table. 198848b8605Smrg * \param key the key (not zero). 199848b8605Smrg * \param data pointer to user data. 200848b8605Smrg */ 201848b8605Smrgvoid 202848b8605Smrg_mesa_HashInsertLocked(struct _mesa_HashTable *table, GLuint key, void *data) 203848b8605Smrg{ 204848b8605Smrg _mesa_HashInsert_unlocked(table, key, data); 205848b8605Smrg} 206848b8605Smrg 207848b8605Smrg 208848b8605Smrg/** 209848b8605Smrg * Insert a key/pointer pair into the hash table. 210848b8605Smrg * If an entry with this key already exists we'll replace the existing entry. 211848b8605Smrg * 212848b8605Smrg * \param table the hash table. 213848b8605Smrg * \param key the key (not zero). 214848b8605Smrg * \param data pointer to user data. 215848b8605Smrg */ 216848b8605Smrgvoid 217848b8605Smrg_mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *data) 218848b8605Smrg{ 219b8e80941Smrg _mesa_HashLockMutex(table); 220848b8605Smrg _mesa_HashInsert_unlocked(table, key, data); 221b8e80941Smrg _mesa_HashUnlockMutex(table); 222848b8605Smrg} 223848b8605Smrg 224848b8605Smrg 225848b8605Smrg/** 226848b8605Smrg * Remove an entry from the hash table. 227848b8605Smrg * 228848b8605Smrg * \param table the hash table. 229848b8605Smrg * \param key key of entry to remove. 230848b8605Smrg * 231848b8605Smrg * While holding the hash table's lock, searches the entry with the matching 232848b8605Smrg * key and unlinks it. 233848b8605Smrg */ 234b8e80941Smrgstatic inline void 235b8e80941Smrg_mesa_HashRemove_unlocked(struct _mesa_HashTable *table, GLuint key) 236848b8605Smrg{ 237848b8605Smrg struct hash_entry *entry; 238848b8605Smrg 239848b8605Smrg assert(table); 240848b8605Smrg assert(key); 241848b8605Smrg 242b8e80941Smrg /* assert if _mesa_HashRemove illegally called from _mesa_HashDeleteAll 243b8e80941Smrg * callback function. Have to check this outside of mutex lock. 244b8e80941Smrg */ 245b8e80941Smrg assert(!table->InDeleteAll); 246848b8605Smrg 247848b8605Smrg if (key == DELETED_KEY_VALUE) { 248848b8605Smrg table->deleted_key_data = NULL; 249848b8605Smrg } else { 250b8e80941Smrg entry = _mesa_hash_table_search_pre_hashed(table->ht, 251b8e80941Smrg uint_hash(key), 252b8e80941Smrg uint_key(key)); 253848b8605Smrg _mesa_hash_table_remove(table->ht, entry); 254848b8605Smrg } 255848b8605Smrg} 256848b8605Smrg 257848b8605Smrg 258b8e80941Smrgvoid 259b8e80941Smrg_mesa_HashRemoveLocked(struct _mesa_HashTable *table, GLuint key) 260b8e80941Smrg{ 261b8e80941Smrg _mesa_HashRemove_unlocked(table, key); 262b8e80941Smrg} 263b8e80941Smrg 264b8e80941Smrgvoid 265b8e80941Smrg_mesa_HashRemove(struct _mesa_HashTable *table, GLuint key) 266b8e80941Smrg{ 267b8e80941Smrg _mesa_HashLockMutex(table); 268b8e80941Smrg _mesa_HashRemove_unlocked(table, key); 269b8e80941Smrg _mesa_HashUnlockMutex(table); 270b8e80941Smrg} 271848b8605Smrg 272848b8605Smrg/** 273848b8605Smrg * Delete all entries in a hash table, but don't delete the table itself. 274848b8605Smrg * Invoke the given callback function for each table entry. 275848b8605Smrg * 276848b8605Smrg * \param table the hash table to delete 277848b8605Smrg * \param callback the callback function 278848b8605Smrg * \param userData arbitrary pointer to pass along to the callback 279848b8605Smrg * (this is typically a struct gl_context pointer) 280848b8605Smrg */ 281848b8605Smrgvoid 282848b8605Smrg_mesa_HashDeleteAll(struct _mesa_HashTable *table, 283848b8605Smrg void (*callback)(GLuint key, void *data, void *userData), 284848b8605Smrg void *userData) 285848b8605Smrg{ 286b8e80941Smrg assert(callback); 287b8e80941Smrg _mesa_HashLockMutex(table); 288848b8605Smrg table->InDeleteAll = GL_TRUE; 289848b8605Smrg hash_table_foreach(table->ht, entry) { 290848b8605Smrg callback((uintptr_t)entry->key, entry->data, userData); 291848b8605Smrg _mesa_hash_table_remove(table->ht, entry); 292848b8605Smrg } 293848b8605Smrg if (table->deleted_key_data) { 294848b8605Smrg callback(DELETED_KEY_VALUE, table->deleted_key_data, userData); 295848b8605Smrg table->deleted_key_data = NULL; 296848b8605Smrg } 297848b8605Smrg table->InDeleteAll = GL_FALSE; 298b8e80941Smrg _mesa_HashUnlockMutex(table); 299848b8605Smrg} 300848b8605Smrg 301848b8605Smrg 302848b8605Smrg/** 303b8e80941Smrg * Walk over all entries in a hash table, calling callback function for each. 304b8e80941Smrg * \param table the hash table to walk 305b8e80941Smrg * \param callback the callback function 306b8e80941Smrg * \param userData arbitrary pointer to pass along to the callback 307b8e80941Smrg * (this is typically a struct gl_context pointer) 308848b8605Smrg */ 309b8e80941Smrgstatic void 310b8e80941Smrghash_walk_unlocked(const struct _mesa_HashTable *table, 311b8e80941Smrg void (*callback)(GLuint key, void *data, void *userData), 312b8e80941Smrg void *userData) 313848b8605Smrg{ 314b8e80941Smrg assert(table); 315b8e80941Smrg assert(callback); 316848b8605Smrg 317848b8605Smrg hash_table_foreach(table->ht, entry) { 318b8e80941Smrg callback((uintptr_t)entry->key, entry->data, userData); 319848b8605Smrg } 320b8e80941Smrg if (table->deleted_key_data) 321b8e80941Smrg callback(DELETED_KEY_VALUE, table->deleted_key_data, userData); 322848b8605Smrg} 323848b8605Smrg 324848b8605Smrg 325848b8605Smrgvoid 326848b8605Smrg_mesa_HashWalk(const struct _mesa_HashTable *table, 327848b8605Smrg void (*callback)(GLuint key, void *data, void *userData), 328848b8605Smrg void *userData) 329848b8605Smrg{ 330848b8605Smrg /* cast-away const */ 331848b8605Smrg struct _mesa_HashTable *table2 = (struct _mesa_HashTable *) table; 332848b8605Smrg 333b8e80941Smrg _mesa_HashLockMutex(table2); 334b8e80941Smrg hash_walk_unlocked(table, callback, userData); 335b8e80941Smrg _mesa_HashUnlockMutex(table2); 336b8e80941Smrg} 337b8e80941Smrg 338b8e80941Smrgvoid 339b8e80941Smrg_mesa_HashWalkLocked(const struct _mesa_HashTable *table, 340b8e80941Smrg void (*callback)(GLuint key, void *data, void *userData), 341b8e80941Smrg void *userData) 342b8e80941Smrg{ 343b8e80941Smrg hash_walk_unlocked(table, callback, userData); 344848b8605Smrg} 345848b8605Smrg 346848b8605Smrgstatic void 347848b8605Smrgdebug_print_entry(GLuint key, void *data, void *userData) 348848b8605Smrg{ 349848b8605Smrg _mesa_debug(NULL, "%u %p\n", key, data); 350848b8605Smrg} 351848b8605Smrg 352848b8605Smrg/** 353848b8605Smrg * Dump contents of hash table for debugging. 354848b8605Smrg * 355848b8605Smrg * \param table the hash table. 356848b8605Smrg */ 357848b8605Smrgvoid 358848b8605Smrg_mesa_HashPrint(const struct _mesa_HashTable *table) 359848b8605Smrg{ 360848b8605Smrg if (table->deleted_key_data) 361848b8605Smrg debug_print_entry(DELETED_KEY_VALUE, table->deleted_key_data, NULL); 362848b8605Smrg _mesa_HashWalk(table, debug_print_entry, NULL); 363848b8605Smrg} 364848b8605Smrg 365848b8605Smrg 366848b8605Smrg/** 367848b8605Smrg * Find a block of adjacent unused hash keys. 368848b8605Smrg * 369848b8605Smrg * \param table the hash table. 370848b8605Smrg * \param numKeys number of keys needed. 371848b8605Smrg * 372848b8605Smrg * \return Starting key of free block or 0 if failure. 373848b8605Smrg * 374848b8605Smrg * If there are enough free keys between the maximum key existing in the table 375848b8605Smrg * (_mesa_HashTable::MaxKey) and the maximum key possible, then simply return 376848b8605Smrg * the adjacent key. Otherwise do a full search for a free key block in the 377848b8605Smrg * allowable key range. 378848b8605Smrg */ 379848b8605SmrgGLuint 380848b8605Smrg_mesa_HashFindFreeKeyBlock(struct _mesa_HashTable *table, GLuint numKeys) 381848b8605Smrg{ 382848b8605Smrg const GLuint maxKey = ~((GLuint) 0) - 1; 383848b8605Smrg if (maxKey - numKeys > table->MaxKey) { 384848b8605Smrg /* the quick solution */ 385848b8605Smrg return table->MaxKey + 1; 386848b8605Smrg } 387848b8605Smrg else { 388848b8605Smrg /* the slow solution */ 389848b8605Smrg GLuint freeCount = 0; 390848b8605Smrg GLuint freeStart = 1; 391848b8605Smrg GLuint key; 392848b8605Smrg for (key = 1; key != maxKey; key++) { 393848b8605Smrg if (_mesa_HashLookup_unlocked(table, key)) { 394848b8605Smrg /* darn, this key is already in use */ 395848b8605Smrg freeCount = 0; 396848b8605Smrg freeStart = key+1; 397848b8605Smrg } 398848b8605Smrg else { 399848b8605Smrg /* this key not in use, check if we've found enough */ 400848b8605Smrg freeCount++; 401848b8605Smrg if (freeCount == numKeys) { 402848b8605Smrg return freeStart; 403848b8605Smrg } 404848b8605Smrg } 405848b8605Smrg } 406848b8605Smrg /* cannot allocate a block of numKeys consecutive keys */ 407848b8605Smrg return 0; 408848b8605Smrg } 409848b8605Smrg} 410848b8605Smrg 411848b8605Smrg 412848b8605Smrg/** 413848b8605Smrg * Return the number of entries in the hash table. 414848b8605Smrg */ 415848b8605SmrgGLuint 416848b8605Smrg_mesa_HashNumEntries(const struct _mesa_HashTable *table) 417848b8605Smrg{ 418848b8605Smrg GLuint count = 0; 419848b8605Smrg 420848b8605Smrg if (table->deleted_key_data) 421848b8605Smrg count++; 422848b8605Smrg 423b8e80941Smrg count += _mesa_hash_table_num_entries(table->ht); 424848b8605Smrg 425848b8605Smrg return count; 426848b8605Smrg} 427