Home | History | Annotate | Download | only in main
      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 "glheader.h"
     38 #include "imports.h"
     39 #include "hash.h"
     40 #include "util/hash_table.h"
     41 
     42 /**
     43  * Magic GLuint object name that gets stored outside of the struct hash_table.
     44  *
     45  * The hash table needs a particular pointer to be the marker for a key that
     46  * was deleted from the table, along with NULL for the "never allocated in the
     47  * table" marker.  Legacy GL allows any GLuint to be used as a GL object name,
     48  * and we use a 1:1 mapping from GLuints to key pointers, so we need to be
     49  * able to track a GLuint that happens to match the deleted key outside of
     50  * struct hash_table.  We tell the hash table to use "1" as the deleted key
     51  * value, so that we test the deleted-key-in-the-table path as best we can.
     52  */
     53 #define DELETED_KEY_VALUE 1
     54 
     55 /**
     56  * The hash table data structure.
     57  */
     58 struct _mesa_HashTable {
     59    struct hash_table *ht;
     60    GLuint MaxKey;                        /**< highest key inserted so far */
     61    mtx_t Mutex;                /**< mutual exclusion lock */
     62    GLboolean InDeleteAll;                /**< Debug check */
     63    /** Value that would be in the table for DELETED_KEY_VALUE. */
     64    void *deleted_key_data;
     65 };
     66 
     67 /** @{
     68  * Mapping from our use of GLuint as both the key and the hash value to the
     69  * hash_table.h API
     70  *
     71  * There exist many integer hash functions, designed to avoid collisions when
     72  * the integers are spread across key space with some patterns.  In GL, the
     73  * pattern (in the case of glGen*()ed object IDs) is that the keys are unique
     74  * contiguous integers starting from 1.  Because of that, we just use the key
     75  * as the hash value, to minimize the cost of the hash function.  If objects
     76  * are never deleted, we will never see a collision in the table, because the
     77  * table resizes itself when it approaches full, and thus key % table_size ==
     78  * key.
     79  *
     80  * The case where we could have collisions for genned objects would be
     81  * something like: glGenBuffers(&a, 100); glDeleteBuffers(&a + 50, 50);
     82  * glGenBuffers(&b, 100), because objects 1-50 and 101-200 are allocated at
     83  * the end of that sequence, instead of 1-150.  So far it doesn't appear to be
     84  * a problem.
     85  */
     86 static bool
     87 uint_key_compare(const void *a, const void *b)
     88 {
     89    return a == b;
     90 }
     91 
     92 static uint32_t
     93 uint_hash(GLuint id)
     94 {
     95    return id;
     96 }
     97 
     98 static uint32_t
     99 uint_key_hash(const void *key)
    100 {
    101    return uint_hash((uintptr_t)key);
    102 }
    103 
    104 static void *
    105 uint_key(GLuint id)
    106 {
    107    return (void *)(uintptr_t) id;
    108 }
    109 /** @} */
    110 
    111 /**
    112  * Create a new hash table.
    113  *
    114  * \return pointer to a new, empty hash table.
    115  */
    116 struct _mesa_HashTable *
    117 _mesa_NewHashTable(void)
    118 {
    119    struct _mesa_HashTable *table = CALLOC_STRUCT(_mesa_HashTable);
    120 
    121    if (table) {
    122       table->ht = _mesa_hash_table_create(NULL, uint_key_hash,
    123                                           uint_key_compare);
    124       if (table->ht == NULL) {
    125          free(table);
    126          _mesa_error_no_memory(__func__);
    127          return NULL;
    128       }
    129 
    130       _mesa_hash_table_set_deleted_key(table->ht, uint_key(DELETED_KEY_VALUE));
    131       /*
    132        * Needs to be recursive, since the callback in _mesa_HashWalk()
    133        * is allowed to call _mesa_HashRemove().
    134        */
    135       mtx_init(&table->Mutex, mtx_recursive);
    136    }
    137    else {
    138       _mesa_error_no_memory(__func__);
    139    }
    140 
    141    return table;
    142 }
    143 
    144 
    145 
    146 /**
    147  * Delete a hash table.
    148  * Frees each entry on the hash table and then the hash table structure itself.
    149  * Note that the caller should have already traversed the table and deleted
    150  * the objects in the table (i.e. We don't free the entries' data pointer).
    151  *
    152  * \param table the hash table to delete.
    153  */
    154 void
    155 _mesa_DeleteHashTable(struct _mesa_HashTable *table)
    156 {
    157    assert(table);
    158 
    159    if (_mesa_hash_table_next_entry(table->ht, NULL) != NULL) {
    160       _mesa_problem(NULL, "In _mesa_DeleteHashTable, found non-freed data");
    161    }
    162 
    163    _mesa_hash_table_destroy(table->ht, NULL);
    164 
    165    mtx_destroy(&table->Mutex);
    166    free(table);
    167 }
    168 
    169 
    170 
    171 /**
    172  * Lookup an entry in the hash table, without locking.
    173  * \sa _mesa_HashLookup
    174  */
    175 static inline void *
    176 _mesa_HashLookup_unlocked(struct _mesa_HashTable *table, GLuint key)
    177 {
    178    const struct hash_entry *entry;
    179 
    180    assert(table);
    181    assert(key);
    182 
    183    if (key == DELETED_KEY_VALUE)
    184       return table->deleted_key_data;
    185 
    186    entry = _mesa_hash_table_search(table->ht, uint_key(key));
    187    if (!entry)
    188       return NULL;
    189 
    190    return entry->data;
    191 }
    192 
    193 
    194 /**
    195  * Lookup an entry in the hash table.
    196  *
    197  * \param table the hash table.
    198  * \param key the key.
    199  *
    200  * \return pointer to user's data or NULL if key not in table
    201  */
    202 void *
    203 _mesa_HashLookup(struct _mesa_HashTable *table, GLuint key)
    204 {
    205    void *res;
    206    assert(table);
    207    mtx_lock(&table->Mutex);
    208    res = _mesa_HashLookup_unlocked(table, key);
    209    mtx_unlock(&table->Mutex);
    210    return res;
    211 }
    212 
    213 
    214 /**
    215  * Lookup an entry in the hash table without locking the mutex.
    216  *
    217  * The hash table mutex must be locked manually by calling
    218  * _mesa_HashLockMutex() before calling this function.
    219  *
    220  * \param table the hash table.
    221  * \param key the key.
    222  *
    223  * \return pointer to user's data or NULL if key not in table
    224  */
    225 void *
    226 _mesa_HashLookupLocked(struct _mesa_HashTable *table, GLuint key)
    227 {
    228    return _mesa_HashLookup_unlocked(table, key);
    229 }
    230 
    231 
    232 /**
    233  * Lock the hash table mutex.
    234  *
    235  * This function should be used when multiple objects need
    236  * to be looked up in the hash table, to avoid having to lock
    237  * and unlock the mutex each time.
    238  *
    239  * \param table the hash table.
    240  */
    241 void
    242 _mesa_HashLockMutex(struct _mesa_HashTable *table)
    243 {
    244    assert(table);
    245    mtx_lock(&table->Mutex);
    246 }
    247 
    248 
    249 /**
    250  * Unlock the hash table mutex.
    251  *
    252  * \param table the hash table.
    253  */
    254 void
    255 _mesa_HashUnlockMutex(struct _mesa_HashTable *table)
    256 {
    257    assert(table);
    258    mtx_unlock(&table->Mutex);
    259 }
    260 
    261 
    262 static inline void
    263 _mesa_HashInsert_unlocked(struct _mesa_HashTable *table, GLuint key, void *data)
    264 {
    265    uint32_t hash = uint_hash(key);
    266    struct hash_entry *entry;
    267 
    268    assert(table);
    269    assert(key);
    270 
    271    if (key > table->MaxKey)
    272       table->MaxKey = key;
    273 
    274    if (key == DELETED_KEY_VALUE) {
    275       table->deleted_key_data = data;
    276    } else {
    277       entry = _mesa_hash_table_search_pre_hashed(table->ht, hash, uint_key(key));
    278       if (entry) {
    279          entry->data = data;
    280       } else {
    281          _mesa_hash_table_insert_pre_hashed(table->ht, hash, uint_key(key), data);
    282       }
    283    }
    284 }
    285 
    286 
    287 /**
    288  * Insert a key/pointer pair into the hash table without locking the mutex.
    289  * If an entry with this key already exists we'll replace the existing entry.
    290  *
    291  * The hash table mutex must be locked manually by calling
    292  * _mesa_HashLockMutex() before calling this function.
    293  *
    294  * \param table the hash table.
    295  * \param key the key (not zero).
    296  * \param data pointer to user data.
    297  */
    298 void
    299 _mesa_HashInsertLocked(struct _mesa_HashTable *table, GLuint key, void *data)
    300 {
    301    _mesa_HashInsert_unlocked(table, key, data);
    302 }
    303 
    304 
    305 /**
    306  * Insert a key/pointer pair into the hash table.
    307  * If an entry with this key already exists we'll replace the existing entry.
    308  *
    309  * \param table the hash table.
    310  * \param key the key (not zero).
    311  * \param data pointer to user data.
    312  */
    313 void
    314 _mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *data)
    315 {
    316    assert(table);
    317    mtx_lock(&table->Mutex);
    318    _mesa_HashInsert_unlocked(table, key, data);
    319    mtx_unlock(&table->Mutex);
    320 }
    321 
    322 
    323 /**
    324  * Remove an entry from the hash table.
    325  *
    326  * \param table the hash table.
    327  * \param key key of entry to remove.
    328  *
    329  * While holding the hash table's lock, searches the entry with the matching
    330  * key and unlinks it.
    331  */
    332 static inline void
    333 _mesa_HashRemove_unlocked(struct _mesa_HashTable *table, GLuint key)
    334 {
    335    struct hash_entry *entry;
    336 
    337    assert(table);
    338    assert(key);
    339 
    340    /* have to check this outside of mutex lock */
    341    if (table->InDeleteAll) {
    342       _mesa_problem(NULL, "_mesa_HashRemove illegally called from "
    343                     "_mesa_HashDeleteAll callback function");
    344       return;
    345    }
    346 
    347    if (key == DELETED_KEY_VALUE) {
    348       table->deleted_key_data = NULL;
    349    } else {
    350       entry = _mesa_hash_table_search(table->ht, uint_key(key));
    351       _mesa_hash_table_remove(table->ht, entry);
    352    }
    353 }
    354 
    355 
    356 void
    357 _mesa_HashRemoveLocked(struct _mesa_HashTable *table, GLuint key)
    358 {
    359    _mesa_HashRemove_unlocked(table, key);
    360 }
    361 
    362 void
    363 _mesa_HashRemove(struct _mesa_HashTable *table, GLuint key)
    364 {
    365    mtx_lock(&table->Mutex);
    366    _mesa_HashRemove_unlocked(table, key);
    367    mtx_unlock(&table->Mutex);
    368 }
    369 
    370 /**
    371  * Delete all entries in a hash table, but don't delete the table itself.
    372  * Invoke the given callback function for each table entry.
    373  *
    374  * \param table  the hash table to delete
    375  * \param callback  the callback function
    376  * \param userData  arbitrary pointer to pass along to the callback
    377  *                  (this is typically a struct gl_context pointer)
    378  */
    379 void
    380 _mesa_HashDeleteAll(struct _mesa_HashTable *table,
    381                     void (*callback)(GLuint key, void *data, void *userData),
    382                     void *userData)
    383 {
    384    struct hash_entry *entry;
    385 
    386    assert(table);
    387    assert(callback);
    388    mtx_lock(&table->Mutex);
    389    table->InDeleteAll = GL_TRUE;
    390    hash_table_foreach(table->ht, entry) {
    391       callback((uintptr_t)entry->key, entry->data, userData);
    392       _mesa_hash_table_remove(table->ht, entry);
    393    }
    394    if (table->deleted_key_data) {
    395       callback(DELETED_KEY_VALUE, table->deleted_key_data, userData);
    396       table->deleted_key_data = NULL;
    397    }
    398    table->InDeleteAll = GL_FALSE;
    399    mtx_unlock(&table->Mutex);
    400 }
    401 
    402 
    403 /**
    404  * Walk over all entries in a hash table, calling callback function for each.
    405  * \param table  the hash table to walk
    406  * \param callback  the callback function
    407  * \param userData  arbitrary pointer to pass along to the callback
    408  *                  (this is typically a struct gl_context pointer)
    409  */
    410 void
    411 _mesa_HashWalk(const struct _mesa_HashTable *table,
    412                void (*callback)(GLuint key, void *data, void *userData),
    413                void *userData)
    414 {
    415    /* cast-away const */
    416    struct _mesa_HashTable *table2 = (struct _mesa_HashTable *) table;
    417    struct hash_entry *entry;
    418 
    419    assert(table);
    420    assert(callback);
    421    mtx_lock(&table2->Mutex);
    422    hash_table_foreach(table->ht, entry) {
    423       callback((uintptr_t)entry->key, entry->data, userData);
    424    }
    425    if (table->deleted_key_data)
    426       callback(DELETED_KEY_VALUE, table->deleted_key_data, userData);
    427    mtx_unlock(&table2->Mutex);
    428 }
    429 
    430 static void
    431 debug_print_entry(GLuint key, void *data, void *userData)
    432 {
    433    _mesa_debug(NULL, "%u %p\n", key, data);
    434 }
    435 
    436 /**
    437  * Dump contents of hash table for debugging.
    438  *
    439  * \param table the hash table.
    440  */
    441 void
    442 _mesa_HashPrint(const struct _mesa_HashTable *table)
    443 {
    444    if (table->deleted_key_data)
    445       debug_print_entry(DELETED_KEY_VALUE, table->deleted_key_data, NULL);
    446    _mesa_HashWalk(table, debug_print_entry, NULL);
    447 }
    448 
    449 
    450 /**
    451  * Find a block of adjacent unused hash keys.
    452  *
    453  * \param table the hash table.
    454  * \param numKeys number of keys needed.
    455  *
    456  * \return Starting key of free block or 0 if failure.
    457  *
    458  * If there are enough free keys between the maximum key existing in the table
    459  * (_mesa_HashTable::MaxKey) and the maximum key possible, then simply return
    460  * the adjacent key. Otherwise do a full search for a free key block in the
    461  * allowable key range.
    462  */
    463 GLuint
    464 _mesa_HashFindFreeKeyBlock(struct _mesa_HashTable *table, GLuint numKeys)
    465 {
    466    const GLuint maxKey = ~((GLuint) 0) - 1;
    467    if (maxKey - numKeys > table->MaxKey) {
    468       /* the quick solution */
    469       return table->MaxKey + 1;
    470    }
    471    else {
    472       /* the slow solution */
    473       GLuint freeCount = 0;
    474       GLuint freeStart = 1;
    475       GLuint key;
    476       for (key = 1; key != maxKey; key++) {
    477 	 if (_mesa_HashLookup_unlocked(table, key)) {
    478 	    /* darn, this key is already in use */
    479 	    freeCount = 0;
    480 	    freeStart = key+1;
    481 	 }
    482 	 else {
    483 	    /* this key not in use, check if we've found enough */
    484 	    freeCount++;
    485 	    if (freeCount == numKeys) {
    486 	       return freeStart;
    487 	    }
    488 	 }
    489       }
    490       /* cannot allocate a block of numKeys consecutive keys */
    491       return 0;
    492    }
    493 }
    494 
    495 
    496 /**
    497  * Return the number of entries in the hash table.
    498  */
    499 GLuint
    500 _mesa_HashNumEntries(const struct _mesa_HashTable *table)
    501 {
    502    GLuint count = 0;
    503 
    504    if (table->deleted_key_data)
    505       count++;
    506 
    507    count += _mesa_hash_table_num_entries(table->ht);
    508 
    509    return count;
    510 }
    511