1 /*************************************************************************/ /*!
3 @Title Self scaling hash tables.
4 @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
6 Implements simple self scaling hash tables. Hash collisions are
7 handled by chaining entries together. Hash tables are increased in
8 size when they become more than (50%?) full and decreased in size
9 when less than (25%?) full. Hash tables are never decreased below
11 @License Dual MIT/GPLv2
13 The contents of this file are subject to the MIT license as set out below.
15 Permission is hereby granted, free of charge, to any person obtaining a copy
16 of this software and associated documentation files (the "Software"), to deal
17 in the Software without restriction, including without limitation the rights
18 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19 copies of the Software, and to permit persons to whom the Software is
20 furnished to do so, subject to the following conditions:
22 The above copyright notice and this permission notice shall be included in
23 all copies or substantial portions of the Software.
25 Alternatively, the contents of this file may be used under the terms of
26 the GNU General Public License Version 2 ("GPL") in which case the provisions
27 of GPL are applicable instead of those above.
29 If you wish to allow use of your version of this file only under the terms of
30 GPL, and not to allow others to use your version of this file under the terms
31 of the MIT license, indicate your decision by deleting the provisions above
32 and replace them with the notice and other provisions required by GPL as set
33 out in the file called "GPL-COPYING" included in this distribution. If you do
34 not delete the provisions above, a recipient may use your version of this file
35 under the terms of either the MIT license or GPL.
37 This License is also included in this distribution in the file called
40 EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
41 PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
42 BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
43 PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
44 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
45 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
46 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
47 */ /**************************************************************************/
51 #include "img_types.h"
52 #include "pvr_debug.h"
53 #include "pvrsrv_error.h"
55 /* services/shared/include/ */
58 /* services/client/include/ or services/server/include/ */
62 #if defined(__KERNEL__)
66 #define PRIVATE_MAX(a,b) ((a)>(b)?(a):(b))
68 #define KEY_TO_INDEX(pHash, key, uSize) \
69 ((pHash)->pfnHashFunc((pHash)->uKeySize, (key), (uSize)) % (uSize))
71 #define KEY_COMPARE(pHash, pKey1, pKey2) \
72 ((pHash)->pfnKeyComp((pHash)->uKeySize, (pKey1), (pKey2)))
74 /* Each entry in a hash table is placed into a bucket */
77 /* the next bucket on the same chain */
78 struct _BUCKET_ *pNext;
87 uintptr_t k[]; /* PRQA S 0642 */ /* override dynamic array declaration warning */
90 typedef struct _BUCKET_ BUCKET;
94 /* current size of the hash table */
97 /* number of entries currently in the hash table */
100 /* the minimum size that the hash table should be re-sized to */
101 IMG_UINT32 uMinimumSize;
103 /* size of key in bytes */
107 HASH_FUNC *pfnHashFunc;
109 /* key comparison function */
110 HASH_KEY_COMP *pfnKeyComp;
112 /* the hash table array */
113 BUCKET **ppBucketTable;
116 /*************************************************************************/ /*!
117 @Function HASH_Func_Default
118 @Description Hash function intended for hashing keys composed of
120 @Input uKeySize The size of the hash key, in bytes.
121 @Input pKey A pointer to the key to hash.
122 @Input uHashTabLen The length of the hash table.
123 @Return The hash value.
124 */ /**************************************************************************/
125 IMG_INTERNAL IMG_UINT32
126 HASH_Func_Default (size_t uKeySize, void *pKey, IMG_UINT32 uHashTabLen)
128 uintptr_t *p = (uintptr_t *)pKey;
129 IMG_UINT32 uKeyLen = uKeySize / sizeof(uintptr_t);
131 IMG_UINT32 uHashKey = 0;
133 PVR_UNREFERENCED_PARAMETER(uHashTabLen);
135 PVR_ASSERT((uKeySize % sizeof(uintptr_t)) == 0);
137 for (ui = 0; ui < uKeyLen; ui++)
139 IMG_UINT32 uHashPart = (IMG_UINT32)*p++;
141 uHashPart += (uHashPart << 12);
142 uHashPart ^= (uHashPart >> 22);
143 uHashPart += (uHashPart << 4);
144 uHashPart ^= (uHashPart >> 9);
145 uHashPart += (uHashPart << 10);
146 uHashPart ^= (uHashPart >> 2);
147 uHashPart += (uHashPart << 7);
148 uHashPart ^= (uHashPart >> 12);
150 uHashKey += uHashPart;
156 /*************************************************************************/ /*!
157 @Function HASH_Key_Comp_Default
158 @Description Compares keys composed of uintptr_t arrays.
159 @Input uKeySize The size of the hash key, in bytes.
160 @Input pKey1 Pointer to first hash key to compare.
161 @Input pKey2 Pointer to second hash key to compare.
162 @Return IMG_TRUE The keys match.
163 IMG_FALSE The keys don't match.
164 */ /**************************************************************************/
165 IMG_INTERNAL IMG_BOOL
166 HASH_Key_Comp_Default (size_t uKeySize, void *pKey1, void *pKey2)
168 uintptr_t *p1 = (uintptr_t *)pKey1;
169 uintptr_t *p2 = (uintptr_t *)pKey2;
170 IMG_UINT32 uKeyLen = uKeySize / sizeof(uintptr_t);
173 PVR_ASSERT((uKeySize % sizeof(uintptr_t)) == 0);
175 for (ui = 0; ui < uKeyLen; ui++)
184 /*************************************************************************/ /*!
185 @Function _ChainInsert
186 @Description Insert a bucket into the appropriate hash table chain.
187 @Input pBucket The bucket
188 @Input ppBucketTable The hash table
189 @Input uSize The size of the hash table
191 */ /**************************************************************************/
193 _ChainInsert (HASH_TABLE *pHash, BUCKET *pBucket, BUCKET **ppBucketTable, IMG_UINT32 uSize)
197 /* We assume that all parameters passed by the caller are valid. */
198 PVR_ASSERT (pBucket != NULL);
199 PVR_ASSERT (ppBucketTable != NULL);
200 PVR_ASSERT (uSize != 0);
202 uIndex = KEY_TO_INDEX(pHash, pBucket->k, uSize); /* PRQA S 0432,0541 */ /* ignore dynamic array warning */
203 pBucket->pNext = ppBucketTable[uIndex];
204 ppBucketTable[uIndex] = pBucket;
207 /*************************************************************************/ /*!
209 @Description Iterate over every entry in an old hash table and
210 rehash into the new table.
211 @Input ppOldTable The old hash table
212 @Input uOldSize The size of the old hash table
213 @Input ppNewTable The new hash table
214 @Input uNewSize The size of the new hash table
216 */ /**************************************************************************/
218 _Rehash (HASH_TABLE *pHash,
219 BUCKET **ppOldTable, IMG_UINT32 uOldSize,
220 BUCKET **ppNewTable, IMG_UINT32 uNewSize)
223 for (uIndex=0; uIndex< uOldSize; uIndex++)
226 pBucket = ppOldTable[uIndex];
227 while (pBucket != NULL)
229 BUCKET *pNextBucket = pBucket->pNext;
230 _ChainInsert (pHash, pBucket, ppNewTable, uNewSize);
231 pBucket = pNextBucket;
236 /*************************************************************************/ /*!
238 @Description Attempt to resize a hash table, failure to allocate a
239 new larger hash table is not considered a hard failure.
240 We simply continue and allow the table to fill up, the
241 effect is to allow hash chains to become longer.
242 @Input pHash Hash table to resize.
243 @Input uNewSize Required table size.
244 @Return IMG_TRUE Success
246 */ /**************************************************************************/
248 _Resize (HASH_TABLE *pHash, IMG_UINT32 uNewSize)
250 if (uNewSize != pHash->uSize)
255 #if defined(__linux__) && defined(__KERNEL__)
256 ppNewTable = OSAllocMemNoStats(sizeof (BUCKET *) * uNewSize);
258 ppNewTable = OSAllocMem(sizeof (BUCKET *) * uNewSize);
260 if (ppNewTable == NULL)
265 for (uIndex=0; uIndex<uNewSize; uIndex++)
266 ppNewTable[uIndex] = NULL;
268 _Rehash(pHash, pHash->ppBucketTable, pHash->uSize, ppNewTable, uNewSize);
270 #if defined(__linux__) && defined(__KERNEL__)
271 OSFreeMemNoStats(pHash->ppBucketTable);
273 OSFreeMem(pHash->ppBucketTable);
275 /*not nulling pointer, being reassigned just below*/
276 pHash->ppBucketTable = ppNewTable;
277 pHash->uSize = uNewSize;
283 /*************************************************************************/ /*!
284 @Function HASH_Create_Extended
285 @Description Create a self scaling hash table, using the supplied
286 key size, and the supplied hash and key comparsion
288 @Input uInitialLen Initial and minimum length of the
289 hash table, where the length refers to the number
290 of entries in the hash table, not its size in
292 @Input uKeySize The size of the key, in bytes.
293 @Input pfnHashFunc Pointer to hash function.
294 @Input pfnKeyComp Pointer to key comparsion function.
295 @Return NULL or hash table handle.
296 */ /**************************************************************************/
298 HASH_TABLE * HASH_Create_Extended (IMG_UINT32 uInitialLen, size_t uKeySize, HASH_FUNC *pfnHashFunc, HASH_KEY_COMP *pfnKeyComp)
303 if (uInitialLen == 0 || uKeySize == 0 || pfnHashFunc == NULL || pfnKeyComp == NULL)
305 PVR_DPF((PVR_DBG_ERROR, "HASH_Create_Extended: invalid input parameters"));
309 PVR_DPF ((PVR_DBG_MESSAGE, "HASH_Create_Extended: InitialSize=0x%x", uInitialLen));
311 #if defined(__linux__) && defined(__KERNEL__)
312 pHash = OSAllocMemNoStats(sizeof(HASH_TABLE));
314 pHash = OSAllocMem(sizeof(HASH_TABLE));
322 pHash->uSize = uInitialLen;
323 pHash->uMinimumSize = uInitialLen;
324 pHash->uKeySize = uKeySize;
325 pHash->pfnHashFunc = pfnHashFunc;
326 pHash->pfnKeyComp = pfnKeyComp;
328 #if defined(__linux__) && defined(__KERNEL__)
329 pHash->ppBucketTable = OSAllocMemNoStats(sizeof (BUCKET *) * pHash->uSize);
331 pHash->ppBucketTable = OSAllocMem(sizeof (BUCKET *) * pHash->uSize);
333 if (pHash->ppBucketTable == NULL)
335 #if defined(__linux__) && defined(__KERNEL__)
336 OSFreeMemNoStats(pHash);
340 /*not nulling pointer, out of scope*/
344 for (uIndex=0; uIndex<pHash->uSize; uIndex++)
345 pHash->ppBucketTable[uIndex] = NULL;
349 /*************************************************************************/ /*!
350 @Function HASH_Create
351 @Description Create a self scaling hash table with a key
352 consisting of a single uintptr_t, and using
353 the default hash and key comparison functions.
354 @Input uInitialLen Initial and minimum length of the
355 hash table, where the length refers to the
356 number of entries in the hash table, not its size
358 @Return NULL or hash table handle.
359 */ /**************************************************************************/
361 HASH_TABLE * HASH_Create (IMG_UINT32 uInitialLen)
363 return HASH_Create_Extended(uInitialLen, sizeof(uintptr_t),
364 &HASH_Func_Default, &HASH_Key_Comp_Default);
367 /*************************************************************************/ /*!
368 @Function HASH_Delete
369 @Description Delete a hash table created by HASH_Create_Extended or
370 HASH_Create. All entries in the table must have been
371 removed before calling this function.
372 @Input pHash Hash table
374 */ /**************************************************************************/
376 HASH_Delete (HASH_TABLE *pHash)
378 IMG_BOOL bDoCheck = IMG_TRUE;
379 #if defined(__KERNEL__) && !defined(__QNXNTO__)
380 PVRSRV_DATA *psPVRSRVData = PVRSRVGetPVRSRVData();
382 if (psPVRSRVData != NULL)
384 if (psPVRSRVData->eServicesState != PVRSRV_SERVICES_STATE_OK)
386 bDoCheck = IMG_FALSE;
389 #if defined(PVRSRV_FORCE_UNLOAD_IF_BAD_STATE)
392 bDoCheck = IMG_FALSE;
398 PVR_DPF ((PVR_DBG_MESSAGE, "HASH_Delete"));
402 PVR_ASSERT (pHash->uCount==0);
404 if(pHash->uCount != 0)
406 IMG_UINT32 uiEntriesLeft = pHash->uCount;
408 PVR_DPF ((PVR_DBG_ERROR, "%s: Leak detected in hash table!", __func__));
409 PVR_DPF ((PVR_DBG_ERROR, "%s: Likely Cause: client drivers not freeing allocations before destroying devmemcontext", __func__));
410 PVR_DPF ((PVR_DBG_ERROR, "%s: Removing remaining %u hash entries.", __func__, uiEntriesLeft));
412 for (i = 0; i < uiEntriesLeft; i++)
414 #if defined(__linux__) && defined(__KERNEL__)
415 OSFreeMemNoStats(pHash->ppBucketTable[i]);
417 OSFreeMem(pHash->ppBucketTable[i]);
421 #if defined(__linux__) && defined(__KERNEL__)
422 OSFreeMemNoStats(pHash->ppBucketTable);
424 OSFreeMem(pHash->ppBucketTable);
426 pHash->ppBucketTable = NULL;
427 #if defined(__linux__) && defined(__KERNEL__)
428 OSFreeMemNoStats(pHash);
432 /*not nulling pointer, copy on stack*/
436 /*************************************************************************/ /*!
437 @Function HASH_Insert_Extended
438 @Description Insert a key value pair into a hash table created
439 with HASH_Create_Extended.
440 @Input pHash Hash table
441 @Input pKey Pointer to the key.
442 @Input v The value associated with the key.
443 @Return IMG_TRUE - success
445 */ /**************************************************************************/
446 IMG_INTERNAL IMG_BOOL
447 HASH_Insert_Extended (HASH_TABLE *pHash, void *pKey, uintptr_t v)
451 PVR_ASSERT (pHash != NULL);
455 PVR_DPF((PVR_DBG_ERROR, "HASH_Insert_Extended: invalid parameter"));
459 #if defined(__linux__) && defined(__KERNEL__)
460 pBucket = OSAllocMemNoStats(sizeof(BUCKET) + pHash->uKeySize);
462 pBucket = OSAllocMem(sizeof(BUCKET) + pHash->uKeySize);
470 /* PRQA S 0432,0541 1 */ /* ignore warning about dynamic array k (linux)*/
471 OSCachedMemCopy(pBucket->k, pKey, pHash->uKeySize);
473 _ChainInsert (pHash, pBucket, pHash->ppBucketTable, pHash->uSize);
477 /* check if we need to think about re-balancing */
478 if (pHash->uCount << 1 > pHash->uSize)
480 /* Ignore the return code from _Resize because the hash table is
481 still in a valid state and although not ideally sized, it is still
483 _Resize (pHash, pHash->uSize << 1);
490 /*************************************************************************/ /*!
491 @Function HASH_Insert
492 @Description Insert a key value pair into a hash table created with
494 @Input pHash Hash table
495 @Input k The key value.
496 @Input v The value associated with the key.
497 @Return IMG_TRUE - success.
499 */ /**************************************************************************/
500 IMG_INTERNAL IMG_BOOL
501 HASH_Insert (HASH_TABLE *pHash, uintptr_t k, uintptr_t v)
503 return HASH_Insert_Extended(pHash, &k, v);
506 /*************************************************************************/ /*!
507 @Function HASH_Remove_Extended
508 @Description Remove a key from a hash table created with
509 HASH_Create_Extended.
510 @Input pHash Hash table
511 @Input pKey Pointer to key.
512 @Return 0 if the key is missing, or the value associated with the key.
513 */ /**************************************************************************/
514 IMG_INTERNAL uintptr_t
515 HASH_Remove_Extended(HASH_TABLE *pHash, void *pKey)
520 PVR_ASSERT (pHash != NULL);
524 PVR_DPF((PVR_DBG_ERROR, "HASH_Remove_Extended: Null hash table"));
528 uIndex = KEY_TO_INDEX(pHash, pKey, pHash->uSize);
530 for (ppBucket = &(pHash->ppBucketTable[uIndex]); *ppBucket != NULL; ppBucket = &((*ppBucket)->pNext))
532 /* PRQA S 0432,0541 1 */ /* ignore warning about dynamic array k */
533 if (KEY_COMPARE(pHash, (*ppBucket)->k, pKey))
535 BUCKET *pBucket = *ppBucket;
536 uintptr_t v = pBucket->v;
537 (*ppBucket) = pBucket->pNext;
539 #if defined(__linux__) && defined(__KERNEL__)
540 OSFreeMemNoStats(pBucket);
544 /*not nulling original pointer, already overwritten*/
548 /* check if we need to think about re-balancing */
549 if (pHash->uSize > (pHash->uCount << 2) &&
550 pHash->uSize > pHash->uMinimumSize)
552 /* Ignore the return code from _Resize because the
553 hash table is still in a valid state and although
554 not ideally sized, it is still functional */
556 PRIVATE_MAX (pHash->uSize >> 1,
557 pHash->uMinimumSize));
566 /*************************************************************************/ /*!
567 @Function HASH_Remove
568 @Description Remove a key value pair from a hash table created
570 @Input pHash Hash table
572 @Return 0 if the key is missing, or the value associated with the key.
573 */ /**************************************************************************/
574 IMG_INTERNAL uintptr_t
575 HASH_Remove (HASH_TABLE *pHash, uintptr_t k)
577 return HASH_Remove_Extended(pHash, &k);
580 /*************************************************************************/ /*!
581 @Function HASH_Retrieve_Extended
582 @Description Retrieve a value from a hash table created with
583 HASH_Create_Extended.
584 @Input pHash Hash table
585 @Input pKey Pointer to the key.
586 @Return 0 if the key is missing, or the value associated with the key.
587 */ /**************************************************************************/
588 IMG_INTERNAL uintptr_t
589 HASH_Retrieve_Extended (HASH_TABLE *pHash, void *pKey)
594 PVR_ASSERT (pHash != NULL);
598 PVR_DPF((PVR_DBG_ERROR, "HASH_Retrieve_Extended: Null hash table"));
602 uIndex = KEY_TO_INDEX(pHash, pKey, pHash->uSize);
604 for (ppBucket = &(pHash->ppBucketTable[uIndex]); *ppBucket != NULL; ppBucket = &((*ppBucket)->pNext))
606 /* PRQA S 0432,0541 1 */ /* ignore warning about dynamic array k */
607 if (KEY_COMPARE(pHash, (*ppBucket)->k, pKey))
609 BUCKET *pBucket = *ppBucket;
610 uintptr_t v = pBucket->v;
618 /*************************************************************************/ /*!
619 @Function HASH_Retrieve
620 @Description Retrieve a value from a hash table created with
622 @Input pHash Hash table
624 @Return 0 if the key is missing, or the value associated with the key.
625 */ /**************************************************************************/
626 IMG_INTERNAL uintptr_t
627 HASH_Retrieve (HASH_TABLE *pHash, uintptr_t k)
629 return HASH_Retrieve_Extended(pHash, &k);
632 /*************************************************************************/ /*!
633 @Function HASH_Iterate
634 @Description Iterate over every entry in the hash table
635 @Input pHash - Hash table to iterate
636 @Input pfnCallback - Callback to call with the key and data for each
637 entry in the hash table
638 @Return Callback error if any, otherwise PVRSRV_OK
639 */ /**************************************************************************/
640 IMG_INTERNAL PVRSRV_ERROR
641 HASH_Iterate(HASH_TABLE *pHash, HASH_pfnCallback pfnCallback)
644 for (uIndex=0; uIndex < pHash->uSize; uIndex++)
647 pBucket = pHash->ppBucketTable[uIndex];
648 while (pBucket != NULL)
651 BUCKET *pNextBucket = pBucket->pNext;
653 eError = pfnCallback((uintptr_t) ((void *) *(pBucket->k)), (uintptr_t) pBucket->v);
655 /* The callback might want us to break out early */
656 if (eError != PVRSRV_OK)
659 pBucket = pNextBucket;
666 /*************************************************************************/ /*!
668 @Description To dump the contents of a hash table in human readable
670 @Input pHash Hash table
671 */ /**************************************************************************/
673 HASH_Dump (HASH_TABLE *pHash)
676 IMG_UINT32 uMaxLength=0;
677 IMG_UINT32 uEmptyCount=0;
679 PVR_ASSERT (pHash != NULL);
680 for (uIndex=0; uIndex<pHash->uSize; uIndex++)
683 IMG_UINT32 uLength = 0;
684 if (pHash->ppBucketTable[uIndex] == NULL)
688 for (pBucket=pHash->ppBucketTable[uIndex];
690 pBucket = pBucket->pNext)
694 uMaxLength = PRIVATE_MAX (uMaxLength, uLength);
697 PVR_TRACE(("hash table: uMinimumSize=%d size=%d count=%d",
698 pHash->uMinimumSize, pHash->uSize, pHash->uCount));
699 PVR_TRACE((" empty=%d max=%d", uEmptyCount, uMaxLength));