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 #include "util/u_memory.h"
42 #include "util/u_idalloc.h"
43
44
45 /**
46 * Create a new hash table.
47 *
48 * \return pointer to a new, empty hash table.
49 */
50 struct _mesa_HashTable *
_mesa_NewHashTable(void)51 _mesa_NewHashTable(void)
52 {
53 struct _mesa_HashTable *table = CALLOC_STRUCT(_mesa_HashTable);
54
55 if (table) {
56 table->ht = _mesa_hash_table_create(NULL, uint_key_hash,
57 uint_key_compare);
58 if (table->ht == NULL) {
59 free(table);
60 _mesa_error_no_memory(__func__);
61 return NULL;
62 }
63
64 _mesa_hash_table_set_deleted_key(table->ht, uint_key(DELETED_KEY_VALUE));
65 /*
66 * Needs to be recursive, since the callback in _mesa_HashWalk()
67 * is allowed to call _mesa_HashRemove().
68 */
69 mtx_init(&table->Mutex, mtx_recursive);
70 }
71 else {
72 _mesa_error_no_memory(__func__);
73 }
74
75 return table;
76 }
77
78
79
80 /**
81 * Delete a hash table.
82 * Frees each entry on the hash table and then the hash table structure itself.
83 * Note that the caller should have already traversed the table and deleted
84 * the objects in the table (i.e. We don't free the entries' data pointer).
85 *
86 * \param table the hash table to delete.
87 */
88 void
_mesa_DeleteHashTable(struct _mesa_HashTable * table)89 _mesa_DeleteHashTable(struct _mesa_HashTable *table)
90 {
91 assert(table);
92
93 if (_mesa_hash_table_next_entry(table->ht, NULL) != NULL) {
94 _mesa_problem(NULL, "In _mesa_DeleteHashTable, found non-freed data");
95 }
96
97 _mesa_hash_table_destroy(table->ht, NULL);
98 if (table->id_alloc) {
99 util_idalloc_fini(table->id_alloc);
100 free(table->id_alloc);
101 }
102
103 mtx_destroy(&table->Mutex);
104 free(table);
105 }
106
107 void
_mesa_HashEnableNameReuse(struct _mesa_HashTable * table)108 _mesa_HashEnableNameReuse(struct _mesa_HashTable *table)
109 {
110 _mesa_HashLockMutex(table);
111 assert(_mesa_hash_table_num_entries(table->ht) == 0);
112 table->id_alloc = MALLOC_STRUCT(util_idalloc);
113 util_idalloc_init(table->id_alloc);
114 util_idalloc_resize(table->id_alloc, 8);
115 ASSERTED GLuint reserve0 = util_idalloc_alloc(table->id_alloc);
116 assert (reserve0 == 0);
117 _mesa_HashUnlockMutex(table);
118 }
119
120
121 /**
122 * Lookup an entry in the hash table, without locking.
123 * \sa _mesa_HashLookup
124 */
125 static inline void *
_mesa_HashLookup_unlocked(struct _mesa_HashTable * table,GLuint key)126 _mesa_HashLookup_unlocked(struct _mesa_HashTable *table, GLuint key)
127 {
128 const struct hash_entry *entry;
129
130 assert(table);
131 assert(key);
132
133 if (key == DELETED_KEY_VALUE)
134 return table->deleted_key_data;
135
136 entry = _mesa_hash_table_search_pre_hashed(table->ht,
137 uint_hash(key),
138 uint_key(key));
139 if (!entry)
140 return NULL;
141
142 return entry->data;
143 }
144
145
146 /**
147 * Lookup an entry in the hash table.
148 *
149 * \param table the hash table.
150 * \param key the key.
151 *
152 * \return pointer to user's data or NULL if key not in table
153 */
154 void *
_mesa_HashLookup(struct _mesa_HashTable * table,GLuint key)155 _mesa_HashLookup(struct _mesa_HashTable *table, GLuint key)
156 {
157 void *res;
158 _mesa_HashLockMutex(table);
159 res = _mesa_HashLookup_unlocked(table, key);
160 _mesa_HashUnlockMutex(table);
161 return res;
162 }
163
164
165 /**
166 * Lookup an entry in the hash table without locking the mutex.
167 *
168 * The hash table mutex must be locked manually by calling
169 * _mesa_HashLockMutex() before calling this function.
170 *
171 * \param table the hash table.
172 * \param key the key.
173 *
174 * \return pointer to user's data or NULL if key not in table
175 */
176 void *
_mesa_HashLookupLocked(struct _mesa_HashTable * table,GLuint key)177 _mesa_HashLookupLocked(struct _mesa_HashTable *table, GLuint key)
178 {
179 return _mesa_HashLookup_unlocked(table, key);
180 }
181
182
183 static inline void
_mesa_HashInsert_unlocked(struct _mesa_HashTable * table,GLuint key,void * data)184 _mesa_HashInsert_unlocked(struct _mesa_HashTable *table, GLuint key, void *data)
185 {
186 uint32_t hash = uint_hash(key);
187 struct hash_entry *entry;
188
189 assert(table);
190 assert(key);
191
192 if (key > table->MaxKey)
193 table->MaxKey = key;
194
195 if (key == DELETED_KEY_VALUE) {
196 table->deleted_key_data = data;
197 } else {
198 entry = _mesa_hash_table_search_pre_hashed(table->ht, hash, uint_key(key));
199 if (entry) {
200 entry->data = data;
201 } else {
202 _mesa_hash_table_insert_pre_hashed(table->ht, hash, uint_key(key), data);
203 }
204 }
205 }
206
207
208 /**
209 * Insert a key/pointer pair into the hash table without locking the mutex.
210 * If an entry with this key already exists we'll replace the existing entry.
211 *
212 * The hash table mutex must be locked manually by calling
213 * _mesa_HashLockMutex() before calling this function.
214 *
215 * \param table the hash table.
216 * \param key the key (not zero).
217 * \param data pointer to user data.
218 * \param isGenName true if the key has been generated by a HashFindFreeKey* function
219 */
220 void
_mesa_HashInsertLocked(struct _mesa_HashTable * table,GLuint key,void * data,GLboolean isGenName)221 _mesa_HashInsertLocked(struct _mesa_HashTable *table, GLuint key, void *data,
222 GLboolean isGenName)
223 {
224 _mesa_HashInsert_unlocked(table, key, data);
225 if (!isGenName && table->id_alloc)
226 util_idalloc_reserve(table->id_alloc, key);
227 }
228
229
230 /**
231 * Insert a key/pointer pair into the hash table.
232 * If an entry with this key already exists we'll replace the existing entry.
233 *
234 * \param table the hash table.
235 * \param key the key (not zero).
236 * \param data pointer to user data.
237 * \param isGenName true if the key has been generated by a HashFindFreeKey* function
238 */
239 void
_mesa_HashInsert(struct _mesa_HashTable * table,GLuint key,void * data,GLboolean isGenName)240 _mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *data,
241 GLboolean isGenName)
242 {
243 _mesa_HashLockMutex(table);
244 _mesa_HashInsert_unlocked(table, key, data);
245 if (!isGenName && table->id_alloc)
246 util_idalloc_reserve(table->id_alloc, key);
247 _mesa_HashUnlockMutex(table);
248 }
249
250
251 /**
252 * Remove an entry from the hash table.
253 *
254 * \param table the hash table.
255 * \param key key of entry to remove.
256 *
257 * While holding the hash table's lock, searches the entry with the matching
258 * key and unlinks it.
259 */
260 static inline void
_mesa_HashRemove_unlocked(struct _mesa_HashTable * table,GLuint key)261 _mesa_HashRemove_unlocked(struct _mesa_HashTable *table, GLuint key)
262 {
263 struct hash_entry *entry;
264
265 assert(table);
266 assert(key);
267
268 /* assert if _mesa_HashRemove illegally called from _mesa_HashDeleteAll
269 * callback function. Have to check this outside of mutex lock.
270 */
271 assert(!table->InDeleteAll);
272
273 if (key == DELETED_KEY_VALUE) {
274 table->deleted_key_data = NULL;
275 } else {
276 entry = _mesa_hash_table_search_pre_hashed(table->ht,
277 uint_hash(key),
278 uint_key(key));
279 _mesa_hash_table_remove(table->ht, entry);
280 }
281
282 if (table->id_alloc)
283 util_idalloc_free(table->id_alloc, key);
284 }
285
286
287 void
_mesa_HashRemoveLocked(struct _mesa_HashTable * table,GLuint key)288 _mesa_HashRemoveLocked(struct _mesa_HashTable *table, GLuint key)
289 {
290 _mesa_HashRemove_unlocked(table, key);
291 }
292
293 void
_mesa_HashRemove(struct _mesa_HashTable * table,GLuint key)294 _mesa_HashRemove(struct _mesa_HashTable *table, GLuint key)
295 {
296 _mesa_HashLockMutex(table);
297 _mesa_HashRemove_unlocked(table, key);
298 _mesa_HashUnlockMutex(table);
299 }
300
301 /**
302 * Delete all entries in a hash table, but don't delete the table itself.
303 * Invoke the given callback function for each table entry.
304 *
305 * \param table the hash table to delete
306 * \param callback the callback function
307 * \param userData arbitrary pointer to pass along to the callback
308 * (this is typically a struct gl_context pointer)
309 */
310 void
_mesa_HashDeleteAll(struct _mesa_HashTable * table,void (* callback)(void * data,void * userData),void * userData)311 _mesa_HashDeleteAll(struct _mesa_HashTable *table,
312 void (*callback)(void *data, void *userData),
313 void *userData)
314 {
315 assert(callback);
316 _mesa_HashLockMutex(table);
317 table->InDeleteAll = GL_TRUE;
318 hash_table_foreach(table->ht, entry) {
319 callback(entry->data, userData);
320 _mesa_hash_table_remove(table->ht, entry);
321 }
322 if (table->deleted_key_data) {
323 callback(table->deleted_key_data, userData);
324 table->deleted_key_data = NULL;
325 }
326 table->InDeleteAll = GL_FALSE;
327 if (table->id_alloc) {
328 util_idalloc_fini(table->id_alloc);
329 free(table->id_alloc);
330 _mesa_HashEnableNameReuse(table);
331 }
332 table->MaxKey = 0;
333 _mesa_HashUnlockMutex(table);
334 }
335
336
337 /**
338 * Walk over all entries in a hash table, calling callback function for each.
339 * \param table the hash table to walk
340 * \param callback the callback function
341 * \param userData arbitrary pointer to pass along to the callback
342 * (this is typically a struct gl_context pointer)
343 */
344 static void
hash_walk_unlocked(const struct _mesa_HashTable * table,void (* callback)(void * data,void * userData),void * userData)345 hash_walk_unlocked(const struct _mesa_HashTable *table,
346 void (*callback)(void *data, void *userData),
347 void *userData)
348 {
349 assert(table);
350 assert(callback);
351
352 hash_table_foreach(table->ht, entry) {
353 callback(entry->data, userData);
354 }
355 if (table->deleted_key_data)
356 callback(table->deleted_key_data, userData);
357 }
358
359
360 void
_mesa_HashWalk(const struct _mesa_HashTable * table,void (* callback)(void * data,void * userData),void * userData)361 _mesa_HashWalk(const struct _mesa_HashTable *table,
362 void (*callback)(void *data, void *userData),
363 void *userData)
364 {
365 /* cast-away const */
366 struct _mesa_HashTable *table2 = (struct _mesa_HashTable *) table;
367
368 _mesa_HashLockMutex(table2);
369 hash_walk_unlocked(table, callback, userData);
370 _mesa_HashUnlockMutex(table2);
371 }
372
373 void
_mesa_HashWalkLocked(const struct _mesa_HashTable * table,void (* callback)(void * data,void * userData),void * userData)374 _mesa_HashWalkLocked(const struct _mesa_HashTable *table,
375 void (*callback)(void *data, void *userData),
376 void *userData)
377 {
378 hash_walk_unlocked(table, callback, userData);
379 }
380
381 /**
382 * Dump contents of hash table for debugging.
383 *
384 * \param table the hash table.
385 */
386 void
_mesa_HashPrint(const struct _mesa_HashTable * table)387 _mesa_HashPrint(const struct _mesa_HashTable *table)
388 {
389 if (table->deleted_key_data)
390 _mesa_debug(NULL, "%u %p\n", DELETED_KEY_VALUE, table->deleted_key_data);
391
392 hash_table_foreach(table->ht, entry) {
393 _mesa_debug(NULL, "%u %p\n", (unsigned)(uintptr_t) entry->key,
394 entry->data);
395 }
396 }
397
398
399 /**
400 * Find a block of adjacent unused hash keys.
401 *
402 * \param table the hash table.
403 * \param numKeys number of keys needed.
404 *
405 * \return Starting key of free block or 0 if failure.
406 *
407 * If there are enough free keys between the maximum key existing in the table
408 * (_mesa_HashTable::MaxKey) and the maximum key possible, then simply return
409 * the adjacent key. Otherwise do a full search for a free key block in the
410 * allowable key range.
411 */
412 GLuint
_mesa_HashFindFreeKeyBlock(struct _mesa_HashTable * table,GLuint numKeys)413 _mesa_HashFindFreeKeyBlock(struct _mesa_HashTable *table, GLuint numKeys)
414 {
415 const GLuint maxKey = ~((GLuint) 0) - 1;
416 if (table->id_alloc && numKeys == 1) {
417 return util_idalloc_alloc(table->id_alloc);
418 } else if (maxKey - numKeys > table->MaxKey) {
419 /* the quick solution */
420 return table->MaxKey + 1;
421 }
422 else {
423 /* the slow solution */
424 GLuint freeCount = 0;
425 GLuint freeStart = 1;
426 GLuint key;
427 for (key = 1; key != maxKey; key++) {
428 if (_mesa_HashLookup_unlocked(table, key)) {
429 /* darn, this key is already in use */
430 freeCount = 0;
431 freeStart = key+1;
432 }
433 else {
434 /* this key not in use, check if we've found enough */
435 freeCount++;
436 if (freeCount == numKeys) {
437 return freeStart;
438 }
439 }
440 }
441 /* cannot allocate a block of numKeys consecutive keys */
442 return 0;
443 }
444 }
445
446
447 bool
_mesa_HashFindFreeKeys(struct _mesa_HashTable * table,GLuint * keys,GLuint numKeys)448 _mesa_HashFindFreeKeys(struct _mesa_HashTable *table, GLuint* keys, GLuint numKeys)
449 {
450 if (!table->id_alloc) {
451 GLuint first = _mesa_HashFindFreeKeyBlock(table, numKeys);
452 for (int i = 0; i < numKeys; i++) {
453 keys[i] = first + i;
454 }
455 return first != 0;
456 }
457
458 for (int i = 0; i < numKeys; i++) {
459 keys[i] = util_idalloc_alloc(table->id_alloc);
460 }
461
462 return true;
463 }
464
465
466 /**
467 * Return the number of entries in the hash table.
468 */
469 GLuint
_mesa_HashNumEntries(const struct _mesa_HashTable * table)470 _mesa_HashNumEntries(const struct _mesa_HashTable *table)
471 {
472 GLuint count = 0;
473
474 if (table->deleted_key_data)
475 count++;
476
477 count += _mesa_hash_table_num_entries(table->ht);
478
479 return count;
480 }
481