mesa: Restore 78-column wrapping of license text in C-style comments.
[mesa.git] / src / mesa / main / hash.c
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 * Version: 6.5.1
16 *
17 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
18 *
19 * Permission is hereby granted, free of charge, to any person obtaining a
20 * copy of this software and associated documentation files (the "Software"),
21 * to deal in the Software without restriction, including without limitation
22 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
23 * and/or sell copies of the Software, and to permit persons to whom the
24 * Software is furnished to do so, subject to the following conditions:
25 *
26 * The above copyright notice and this permission notice shall be included
27 * in all copies or substantial portions of the Software.
28 *
29 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
30 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
32 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
33 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
34 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
35 * OTHER DEALINGS IN THE SOFTWARE.
36 */
37
38 #include "glheader.h"
39 #include "imports.h"
40 #include "glapi/glthread.h"
41 #include "hash.h"
42 #include "hash_table.h"
43
44 /**
45 * Magic GLuint object name that gets stored outside of the struct hash_table.
46 *
47 * The hash table needs a particular pointer to be the marker for a key that
48 * was deleted from the table, along with NULL for the "never allocated in the
49 * table" marker. Legacy GL allows any GLuint to be used as a GL object name,
50 * and we use a 1:1 mapping from GLuints to key pointers, so we need to be
51 * able to track a GLuint that happens to match the deleted key outside of
52 * struct hash_table. We tell the hash table to use "1" as the deleted key
53 * value, so that we test the deleted-key-in-the-table path as best we can.
54 */
55 #define DELETED_KEY_VALUE 1
56
57 /**
58 * The hash table data structure.
59 */
60 struct _mesa_HashTable {
61 struct hash_table *ht;
62 GLuint MaxKey; /**< highest key inserted so far */
63 _glthread_Mutex Mutex; /**< mutual exclusion lock */
64 _glthread_Mutex WalkMutex; /**< for _mesa_HashWalk() */
65 GLboolean InDeleteAll; /**< Debug check */
66 /** Value that would be in the table for DELETED_KEY_VALUE. */
67 void *deleted_key_data;
68 };
69
70 /** @{
71 * Mapping from our use of GLuint as both the key and the hash value to the
72 * hash_table.h API
73 *
74 * There exist many integer hash functions, designed to avoid collisions when
75 * the integers are spread across key space with some patterns. In GL, the
76 * pattern (in the case of glGen*()ed object IDs) is that the keys are unique
77 * contiguous integers starting from 1. Because of that, we just use the key
78 * as the hash value, to minimize the cost of the hash function. If objects
79 * are never deleted, we will never see a collision in the table, because the
80 * table resizes itself when it approaches full, and thus key % table_size ==
81 * key.
82 *
83 * The case where we could have collisions for genned objects would be
84 * something like: glGenBuffers(&a, 100); glDeleteBuffers(&a + 50, 50);
85 * glGenBuffers(&b, 100), because objects 1-50 and 101-200 are allocated at
86 * the end of that sequence, instead of 1-150. So far it doesn't appear to be
87 * a problem.
88 */
89 static bool
90 uint_key_compare(const void *a, const void *b)
91 {
92 return a == b;
93 }
94
95 static uint32_t
96 uint_hash(GLuint id)
97 {
98 return id;
99 }
100
101 static void *
102 uint_key(GLuint id)
103 {
104 return (void *)(uintptr_t) id;
105 }
106 /** @} */
107
108 /**
109 * Create a new hash table.
110 *
111 * \return pointer to a new, empty hash table.
112 */
113 struct _mesa_HashTable *
114 _mesa_NewHashTable(void)
115 {
116 struct _mesa_HashTable *table = CALLOC_STRUCT(_mesa_HashTable);
117
118 if (table) {
119 table->ht = _mesa_hash_table_create(NULL, uint_key_compare);
120 _mesa_hash_table_set_deleted_key(table->ht, uint_key(DELETED_KEY_VALUE));
121 _glthread_INIT_MUTEX(table->Mutex);
122 _glthread_INIT_MUTEX(table->WalkMutex);
123 }
124 return table;
125 }
126
127
128
129 /**
130 * Delete a hash table.
131 * Frees each entry on the hash table and then the hash table structure itself.
132 * Note that the caller should have already traversed the table and deleted
133 * the objects in the table (i.e. We don't free the entries' data pointer).
134 *
135 * \param table the hash table to delete.
136 */
137 void
138 _mesa_DeleteHashTable(struct _mesa_HashTable *table)
139 {
140 assert(table);
141
142 if (_mesa_hash_table_next_entry(table->ht, NULL) != NULL) {
143 _mesa_problem(NULL, "In _mesa_DeleteHashTable, found non-freed data");
144 }
145
146 _mesa_hash_table_destroy(table->ht, NULL);
147
148 _glthread_DESTROY_MUTEX(table->Mutex);
149 _glthread_DESTROY_MUTEX(table->WalkMutex);
150 free(table);
151 }
152
153
154
155 /**
156 * Lookup an entry in the hash table, without locking.
157 * \sa _mesa_HashLookup
158 */
159 static inline void *
160 _mesa_HashLookup_unlocked(struct _mesa_HashTable *table, GLuint key)
161 {
162 const struct hash_entry *entry;
163
164 assert(table);
165 assert(key);
166
167 if (key == DELETED_KEY_VALUE)
168 return table->deleted_key_data;
169
170 entry = _mesa_hash_table_search(table->ht, uint_hash(key), uint_key(key));
171 if (!entry)
172 return NULL;
173
174 return entry->data;
175 }
176
177
178 /**
179 * Lookup an entry in the hash table.
180 *
181 * \param table the hash table.
182 * \param key the key.
183 *
184 * \return pointer to user's data or NULL if key not in table
185 */
186 void *
187 _mesa_HashLookup(struct _mesa_HashTable *table, GLuint key)
188 {
189 void *res;
190 assert(table);
191 _glthread_LOCK_MUTEX(table->Mutex);
192 res = _mesa_HashLookup_unlocked(table, key);
193 _glthread_UNLOCK_MUTEX(table->Mutex);
194 return res;
195 }
196
197
198 /**
199 * Insert a key/pointer pair into the hash table.
200 * If an entry with this key already exists we'll replace the existing entry.
201 *
202 * \param table the hash table.
203 * \param key the key (not zero).
204 * \param data pointer to user data.
205 */
206 void
207 _mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *data)
208 {
209 uint32_t hash = uint_hash(key);
210 struct hash_entry *entry;
211
212 assert(table);
213 assert(key);
214
215 _glthread_LOCK_MUTEX(table->Mutex);
216
217 if (key > table->MaxKey)
218 table->MaxKey = key;
219
220 if (key == DELETED_KEY_VALUE) {
221 table->deleted_key_data = data;
222 } else {
223 entry = _mesa_hash_table_search(table->ht, hash, uint_key(key));
224 if (entry) {
225 entry->data = data;
226 } else {
227 _mesa_hash_table_insert(table->ht, hash, uint_key(key), data);
228 }
229 }
230
231 _glthread_UNLOCK_MUTEX(table->Mutex);
232 }
233
234
235
236 /**
237 * Remove an entry from the hash table.
238 *
239 * \param table the hash table.
240 * \param key key of entry to remove.
241 *
242 * While holding the hash table's lock, searches the entry with the matching
243 * key and unlinks it.
244 */
245 void
246 _mesa_HashRemove(struct _mesa_HashTable *table, GLuint key)
247 {
248 struct hash_entry *entry;
249
250 assert(table);
251 assert(key);
252
253 /* have to check this outside of mutex lock */
254 if (table->InDeleteAll) {
255 _mesa_problem(NULL, "_mesa_HashRemove illegally called from "
256 "_mesa_HashDeleteAll callback function");
257 return;
258 }
259
260 _glthread_LOCK_MUTEX(table->Mutex);
261 if (key == DELETED_KEY_VALUE) {
262 table->deleted_key_data = NULL;
263 } else {
264 entry = _mesa_hash_table_search(table->ht, uint_hash(key), uint_key(key));
265 _mesa_hash_table_remove(table->ht, entry);
266 }
267 _glthread_UNLOCK_MUTEX(table->Mutex);
268 }
269
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 */
281 void
282 _mesa_HashDeleteAll(struct _mesa_HashTable *table,
283 void (*callback)(GLuint key, void *data, void *userData),
284 void *userData)
285 {
286 struct hash_entry *entry;
287
288 ASSERT(table);
289 ASSERT(callback);
290 _glthread_LOCK_MUTEX(table->Mutex);
291 table->InDeleteAll = GL_TRUE;
292 hash_table_foreach(table->ht, entry) {
293 callback((uintptr_t)entry->key, entry->data, userData);
294 _mesa_hash_table_remove(table->ht, entry);
295 }
296 if (table->deleted_key_data) {
297 callback(DELETED_KEY_VALUE, table->deleted_key_data, userData);
298 table->deleted_key_data = NULL;
299 }
300 table->InDeleteAll = GL_FALSE;
301 _glthread_UNLOCK_MUTEX(table->Mutex);
302 }
303
304
305 /**
306 * Walk over all entries in a hash table, calling callback function for each.
307 * Note: we use a separate mutex in this function to avoid a recursive
308 * locking deadlock (in case the callback calls _mesa_HashRemove()) and to
309 * prevent multiple threads/contexts from getting tangled up.
310 * A lock-less version of this function could be used when the table will
311 * not be modified.
312 * \param table the hash table to walk
313 * \param callback the callback function
314 * \param userData arbitrary pointer to pass along to the callback
315 * (this is typically a struct gl_context pointer)
316 */
317 void
318 _mesa_HashWalk(const struct _mesa_HashTable *table,
319 void (*callback)(GLuint key, void *data, void *userData),
320 void *userData)
321 {
322 /* cast-away const */
323 struct _mesa_HashTable *table2 = (struct _mesa_HashTable *) table;
324 struct hash_entry *entry;
325
326 ASSERT(table);
327 ASSERT(callback);
328 _glthread_LOCK_MUTEX(table2->WalkMutex);
329 hash_table_foreach(table->ht, entry) {
330 callback((uintptr_t)entry->key, entry->data, userData);
331 }
332 if (table->deleted_key_data)
333 callback(DELETED_KEY_VALUE, table->deleted_key_data, userData);
334 _glthread_UNLOCK_MUTEX(table2->WalkMutex);
335 }
336
337 static void
338 debug_print_entry(GLuint key, void *data, void *userData)
339 {
340 _mesa_debug(NULL, "%u %p\n", key, data);
341 }
342
343 /**
344 * Dump contents of hash table for debugging.
345 *
346 * \param table the hash table.
347 */
348 void
349 _mesa_HashPrint(const struct _mesa_HashTable *table)
350 {
351 if (table->deleted_key_data)
352 debug_print_entry(DELETED_KEY_VALUE, table->deleted_key_data, NULL);
353 _mesa_HashWalk(table, debug_print_entry, NULL);
354 }
355
356
357 /**
358 * Find a block of adjacent unused hash keys.
359 *
360 * \param table the hash table.
361 * \param numKeys number of keys needed.
362 *
363 * \return Starting key of free block or 0 if failure.
364 *
365 * If there are enough free keys between the maximum key existing in the table
366 * (_mesa_HashTable::MaxKey) and the maximum key possible, then simply return
367 * the adjacent key. Otherwise do a full search for a free key block in the
368 * allowable key range.
369 */
370 GLuint
371 _mesa_HashFindFreeKeyBlock(struct _mesa_HashTable *table, GLuint numKeys)
372 {
373 const GLuint maxKey = ~((GLuint) 0) - 1;
374 _glthread_LOCK_MUTEX(table->Mutex);
375 if (maxKey - numKeys > table->MaxKey) {
376 /* the quick solution */
377 _glthread_UNLOCK_MUTEX(table->Mutex);
378 return table->MaxKey + 1;
379 }
380 else {
381 /* the slow solution */
382 GLuint freeCount = 0;
383 GLuint freeStart = 1;
384 GLuint key;
385 for (key = 1; key != maxKey; key++) {
386 if (_mesa_HashLookup_unlocked(table, key)) {
387 /* darn, this key is already in use */
388 freeCount = 0;
389 freeStart = key+1;
390 }
391 else {
392 /* this key not in use, check if we've found enough */
393 freeCount++;
394 if (freeCount == numKeys) {
395 _glthread_UNLOCK_MUTEX(table->Mutex);
396 return freeStart;
397 }
398 }
399 }
400 /* cannot allocate a block of numKeys consecutive keys */
401 _glthread_UNLOCK_MUTEX(table->Mutex);
402 return 0;
403 }
404 }
405
406
407 /**
408 * Return the number of entries in the hash table.
409 */
410 GLuint
411 _mesa_HashNumEntries(const struct _mesa_HashTable *table)
412 {
413 struct hash_entry *entry;
414 GLuint count = 0;
415
416 if (table->deleted_key_data)
417 count++;
418
419 hash_table_foreach(table->ht, entry)
420 count++;
421
422 return count;
423 }