X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Fhash.c;h=72d924dcc38ef222a4c9bea6ace6b5e99217446a;hb=d9e591391d490c83ce301aa568a2e0afe4cc3c0a;hp=2d5bcc3e01e9c0f28fb555d881978d05d13376d5;hpb=bfb2729f9ef6cba2b1351826ac83932ab0ed6a5f;p=mesa.git diff --git a/src/mesa/main/hash.c b/src/mesa/main/hash.c index 2d5bcc3e01e..72d924dcc38 100644 --- a/src/mesa/main/hash.c +++ b/src/mesa/main/hash.c @@ -37,7 +37,7 @@ #include "glheader.h" #include "imports.h" -#include "glthread.h" +#include "glapi/glthread.h" #include "hash.h" @@ -63,6 +63,7 @@ struct _mesa_HashTable { struct HashEntry *Table[TABLE_SIZE]; /**< the lookup table */ GLuint MaxKey; /**< highest key inserted so far */ _glthread_Mutex Mutex; /**< mutual exclusion lock */ + _glthread_Mutex WalkMutex; /**< for _mesa_HashWalk() */ GLboolean InDeleteAll; /**< Debug check */ }; @@ -79,6 +80,7 @@ _mesa_NewHashTable(void) struct _mesa_HashTable *table = CALLOC_STRUCT(_mesa_HashTable); if (table) { _glthread_INIT_MUTEX(table->Mutex); + _glthread_INIT_MUTEX(table->WalkMutex); } return table; } @@ -106,26 +108,23 @@ _mesa_DeleteHashTable(struct _mesa_HashTable *table) _mesa_problem(NULL, "In _mesa_DeleteHashTable, found non-freed data"); } - _mesa_free(entry); + free(entry); entry = next; } } _glthread_DESTROY_MUTEX(table->Mutex); - _mesa_free(table); + _glthread_DESTROY_MUTEX(table->WalkMutex); + free(table); } /** - * Lookup an entry in the hash table. - * - * \param table the hash table. - * \param key the key. - * - * \return pointer to user's data or NULL if key not in table + * Lookup an entry in the hash table, without locking. + * \sa _mesa_HashLookup */ -void * -_mesa_HashLookup(const struct _mesa_HashTable *table, GLuint key) +static INLINE void * +_mesa_HashLookup_unlocked(struct _mesa_HashTable *table, GLuint key) { GLuint pos; const struct HashEntry *entry; @@ -137,7 +136,7 @@ _mesa_HashLookup(const struct _mesa_HashTable *table, GLuint key) entry = table->Table[pos]; while (entry) { if (entry->Key == key) { - return entry->Data; + return entry->Data; } entry = entry->Next; } @@ -145,6 +144,25 @@ _mesa_HashLookup(const struct _mesa_HashTable *table, GLuint key) } +/** + * Lookup an entry in the hash table. + * + * \param table the hash table. + * \param key the key. + * + * \return pointer to user's data or NULL if key not in table + */ +void * +_mesa_HashLookup(struct _mesa_HashTable *table, GLuint key) +{ + void *res; + assert(table); + _glthread_LOCK_MUTEX(table->Mutex); + res = _mesa_HashLookup_unlocked(table, key); + _glthread_UNLOCK_MUTEX(table->Mutex); + return res; +} + /** * Insert a key/pointer pair into the hash table. @@ -188,10 +206,12 @@ _mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *data) /* alloc and insert new table entry */ entry = MALLOC_STRUCT(HashEntry); - entry->Key = key; - entry->Data = data; - entry->Next = table->Table[pos]; - table->Table[pos] = entry; + if (entry) { + entry->Key = key; + entry->Data = data; + entry->Next = table->Table[pos]; + table->Table[pos] = entry; + } _glthread_UNLOCK_MUTEX(table->Mutex); } @@ -237,7 +257,7 @@ _mesa_HashRemove(struct _mesa_HashTable *table, GLuint key) else { table->Table[pos] = entry->Next; } - _mesa_free(entry); + free(entry); _glthread_UNLOCK_MUTEX(table->Mutex); return; } @@ -257,7 +277,7 @@ _mesa_HashRemove(struct _mesa_HashTable *table, GLuint key) * \param table the hash table to delete * \param callback the callback function * \param userData arbitrary pointer to pass along to the callback - * (this is typically a GLcontext pointer) + * (this is typically a struct gl_context pointer) */ void _mesa_HashDeleteAll(struct _mesa_HashTable *table, @@ -274,7 +294,7 @@ _mesa_HashDeleteAll(struct _mesa_HashTable *table, for (entry = table->Table[pos]; entry; entry = next) { callback(entry->Key, entry->Data, userData); next = entry->Next; - _mesa_free(entry); + free(entry); } table->Table[pos] = NULL; } @@ -285,10 +305,15 @@ _mesa_HashDeleteAll(struct _mesa_HashTable *table, /** * Walk over all entries in a hash table, calling callback function for each. + * Note: we use a separate mutex in this function to avoid a recursive + * locking deadlock (in case the callback calls _mesa_HashRemove()) and to + * prevent multiple threads/contexts from getting tangled up. + * A lock-less version of this function could be used when the table will + * not be modified. * \param table the hash table to walk * \param callback the callback function * \param userData arbitrary pointer to pass along to the callback - * (this is typically a GLcontext pointer) + * (this is typically a struct gl_context pointer) */ void _mesa_HashWalk(const struct _mesa_HashTable *table, @@ -300,14 +325,16 @@ _mesa_HashWalk(const struct _mesa_HashTable *table, GLuint pos; ASSERT(table); ASSERT(callback); - _glthread_UNLOCK_MUTEX(table2->Mutex); + _glthread_LOCK_MUTEX(table2->WalkMutex); for (pos = 0; pos < TABLE_SIZE; pos++) { - struct HashEntry *entry; - for (entry = table->Table[pos]; entry; entry = entry->Next) { + struct HashEntry *entry, *next; + for (entry = table->Table[pos]; entry; entry = next) { + /* save 'next' pointer now in case the callback deletes the entry */ + next = entry->Next; callback(entry->Key, entry->Data, userData); } } - _glthread_UNLOCK_MUTEX(table2->Mutex); + _glthread_UNLOCK_MUTEX(table2->WalkMutex); } @@ -432,7 +459,7 @@ _mesa_HashFindFreeKeyBlock(struct _mesa_HashTable *table, GLuint numKeys) GLuint freeStart = 1; GLuint key; for (key = 1; key != maxKey; key++) { - if (_mesa_HashLookup(table, key)) { + if (_mesa_HashLookup_unlocked(table, key)) { /* darn, this key is already in use */ freeCount = 0; freeStart = key+1;