VirtualBox

source: vbox/trunk/src/VBox/GuestHost/OpenGL/util/hash.c@ 78493

Last change on this file since 78493 was 78341, checked in by vboxsync, 6 years ago

Config.kmk,Additions/common/crOpenGL,VBox/GuestHost/OpenGL,HostServices/SharedOpenGL: Remove CHROMIUM_THREADSAFE define and apply the current default

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.1 KB
Line 
1/* Copyright (c) 2001, Stanford University
2 * All rights reserved
3 *
4 * See the file LICENSE.txt for information on redistributing this software.
5 */
6
7#include "cr_threads.h"
8#include "cr_hash.h"
9#include "cr_mem.h"
10#include "cr_error.h"
11
12#include <iprt/list.h>
13
14#define CR_MAXUINT ((GLuint) 0xFFFFFFFF)
15#define CR_HASH_ID_MIN ((GLuint)1)
16#define CR_HASH_ID_MAX CR_MAXUINT
17
18#define CR_NUM_BUCKETS 1047
19
20typedef struct FreeElemRec {
21 RTLISTNODE Node;
22 GLuint min;
23 GLuint max;
24} FreeElem;
25
26struct CRHashIdPool {
27 RTLISTNODE freeList;
28 GLuint min;
29 GLuint max;
30};
31
32typedef struct CRHashNode {
33 unsigned long key;
34 void *data;
35 struct CRHashNode *next;
36} CRHashNode;
37
38struct CRHashTable {
39 unsigned int num_elements;
40 CRHashNode *buckets[CR_NUM_BUCKETS];
41 CRHashIdPool *idPool;
42 CRmutex mutex;
43};
44
45
46CRHashIdPool *crAllocHashIdPoolEx( GLuint min, GLuint max )
47{
48 CRHashIdPool *pool;
49 FreeElem *elem;
50 if (min < CR_HASH_ID_MIN || max > CR_HASH_ID_MAX || min >= max)
51 {
52 crWarning("invalid min man vals");
53 return NULL;
54 }
55 pool = (CRHashIdPool *) crCalloc(sizeof(CRHashIdPool));
56 elem = (FreeElem *) crCalloc(sizeof(FreeElem));
57 RTListInit(&pool->freeList);
58 elem->min = min;
59 elem->max = max;
60 RTListAppend(&pool->freeList, &elem->Node);
61 pool->min = min;
62 pool->max = max;
63 return pool;
64}
65
66CRHashIdPool *crAllocHashIdPool( void )
67{
68 return crAllocHashIdPoolEx( CR_HASH_ID_MIN, CR_HASH_ID_MAX );
69}
70
71void crFreeHashIdPool( CRHashIdPool *pool )
72{
73 FreeElem *i, *next;
74 RTListForEachSafe(&pool->freeList, i, next, FreeElem, Node)
75 {
76 crFree(i);
77 }
78
79 crFree(pool);
80}
81
82#ifdef DEBUG_misha
83static void crHashIdPoolDbgCheckConsistency(CRHashIdPool *pool)
84{
85 FreeElem *i;
86 GLuint min = 0;
87
88 /* null is a special case, it is always treated as allocated */
89 Assert(!crHashIdPoolIsIdFree(pool, 0));
90
91 /* first ensure entries have correct values */
92 RTListForEach(&pool->freeList, i, FreeElem, Node)
93 {
94 Assert(i->min >= pool->min);
95 Assert(i->max <= pool->max);
96 Assert(i->min < i->max);
97 }
98
99 /* now ensure entries do not intersect */
100 /* and that they are sorted */
101 RTListForEach(&pool->freeList, i, FreeElem, Node)
102 {
103 Assert(min < i->min);
104 min = i->max;
105 }
106}
107
108static void crHashIdPoolDbgCheckUsed( const CRHashIdPool *pool, GLuint start, GLuint count, GLboolean fUsed )
109{
110 GLuint i;
111 CRASSERT(count);
112 CRASSERT(start >= pool->min);
113 CRASSERT(start + count <= pool->max);
114 CRASSERT(start + count > start);
115 for (i = 0; i < count; ++i)
116 {
117 Assert(!fUsed == !!crHashIdPoolIsIdFree( pool, start + i ));
118 }
119}
120
121# define CR_HASH_IDPOOL_DBG_CHECK_USED(_p, _start, _count, _used) do { \
122 crHashIdPoolDbgCheckConsistency((_p)); \
123 crHashIdPoolDbgCheckUsed( (_p), (_start), (_count), (_used) ); \
124 } while (0)
125
126# define CR_HASH_IDPOOL_DBG_CHECK_CONSISTENCY(_p) do { crHashIdPoolDbgCheckConsistency((_p)); } while (0)
127#else
128# define CR_HASH_IDPOOL_DBG_CHECK_USED(_p, _start, _count, _used) do { } while (0)
129# define CR_HASH_IDPOOL_DBG_CHECK_CONSISTENCY(_p) do { } while (0)
130#endif
131
132/*
133 * Allocate a block of <count> IDs. Return index of first one.
134 * Return 0 if we fail.
135 */
136GLuint crHashIdPoolAllocBlock( CRHashIdPool *pool, GLuint count )
137{
138 FreeElem *f, *next;
139 GLuint ret;
140
141 CRASSERT(count > 0);
142 RTListForEachSafe(&pool->freeList, f, next, FreeElem, Node)
143 {
144 Assert(f->max > f->min);
145 if (f->max - f->min >= (GLuint) count)
146 {
147 /* found a sufficiently large enough block */
148 ret = f->min;
149 f->min += count;
150 if (f->min == f->max)
151 {
152 RTListNodeRemove(&f->Node);
153 crFree(f);
154 }
155
156 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, ret, count, GL_TRUE);
157 return ret;
158 }
159 }
160
161 /* failed to find free block */
162 crWarning("crHashIdPoolAllocBlock failed");
163 CR_HASH_IDPOOL_DBG_CHECK_CONSISTENCY(pool);
164 return 0;
165}
166
167
168/*
169 * Free a block of <count> IDs starting at <first>.
170 */
171void crHashIdPoolFreeBlock( CRHashIdPool *pool, GLuint first, GLuint count )
172{
173 FreeElem *f;
174 GLuint last;
175 GLuint newMax;
176 FreeElem *cur, *curNext;
177
178 /* null is a special case, it is always treated as allocated */
179 if (!first)
180 {
181 Assert(!crHashIdPoolIsIdFree(pool, 0));
182 ++first;
183 --count;
184 if (!count)
185 return;
186 }
187
188 last = first + count;
189 CRASSERT(count > 0);
190 CRASSERT(last > first);
191 CRASSERT(first >= pool->min);
192 CRASSERT(last <= pool->max);
193
194 /* the id list is sorted, first find a place to insert */
195 RTListForEach(&pool->freeList, f, FreeElem, Node)
196 {
197 Assert(f->max > f->min);
198
199 if (f->max < first)
200 continue;
201
202 if (f->min > last)
203 {
204 /* we are here because first is > than prevEntry->max
205 * otherwise the previous loop iterations should handle that */
206 FreeElem *elem = (FreeElem *) crCalloc(sizeof(FreeElem));
207 elem->min = first;
208 elem->max = last;
209 RTListNodeInsertBefore(&f->Node, &elem->Node);
210 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, first, count, GL_FALSE);
211 return;
212 }
213
214 /* now we have f->min <= last and f->max >= first,
215 * so we have either intersection */
216
217 if (f->min > first)
218 f->min = first; /* first is guaranteed not to touch any prev regions */
219
220 newMax = last;
221
222 if (f->max >= last)
223 {
224 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, first, count, GL_FALSE);
225 return;
226 }
227
228 for (cur = RTListNodeGetNext(&f->Node, FreeElem, Node),
229 curNext = RT_FROM_MEMBER(cur->Node.pNext, FreeElem, Node);
230 !RTListNodeIsDummy(&pool->freeList, cur, FreeElem, Node);
231 cur = curNext,
232 curNext = RT_FROM_MEMBER((cur)->Node.pNext, FreeElem, Node) )
233 {
234 if (cur->min > last)
235 break;
236
237 newMax = cur->max;
238 RTListNodeRemove(&cur->Node);
239 crFree(cur);
240
241 if (newMax >= last)
242 break;
243 }
244
245 f->max = newMax;
246 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, first, count, GL_FALSE);
247 return;
248 }
249
250 /* we are here because either the list is empty or because all list rande elements have smaller values */
251 f = (FreeElem *) crCalloc(sizeof(FreeElem));
252 f->min = first;
253 f->max = last;
254 RTListAppend(&pool->freeList, &f->Node);
255 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, first, count, GL_FALSE);
256}
257
258
259
260/*
261 * Mark the given Id as being allocated.
262 */
263GLboolean crHashIdPoolAllocId( CRHashIdPool *pool, GLuint id )
264{
265 FreeElem *f, *next;
266
267 if (!id)
268 {
269 /* null is a special case, it is always treated as allocated */
270 Assert(!crHashIdPoolIsIdFree(pool, 0));
271 return GL_FALSE;
272 }
273
274/* Assert(id != 2);*/
275
276 RTListForEachSafe(&pool->freeList, f, next, FreeElem, Node)
277 {
278 if (f->max <= id)
279 continue;
280 if (f->min > id)
281 {
282 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
283 return GL_FALSE;
284 }
285
286 /* f->min <= id && f->max > id */
287 if (id > f->min)
288 {
289 if (id + 1 < f->max)
290 {
291 FreeElem *elem = (FreeElem *) crCalloc(sizeof(FreeElem));
292 elem->min = id + 1;
293 elem->max = f->max;
294 RTListNodeInsertAfter(&f->Node, &elem->Node);
295 }
296 f->max = id;
297
298 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
299 }
300 else
301 {
302 Assert(id == f->min);
303 if (id + 1 < f->max)
304 {
305 f->min = id + 1;
306 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
307 }
308 else
309 {
310 RTListNodeRemove(&f->Node);
311 crFree(f);
312 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
313 }
314 }
315
316 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
317 return GL_TRUE;
318 }
319
320 /* if we get here, the ID was already allocated - that's OK */
321 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
322 return GL_FALSE;
323}
324
325
326/*
327 * Determine if the given id is free. Return GL_TRUE if so.
328 */
329GLboolean crHashIdPoolIsIdFree( const CRHashIdPool *pool, GLuint id )
330{
331 FreeElem *f;
332 CRASSERT(id <= pool->max);
333
334 RTListForEach(&pool->freeList, f, FreeElem, Node)
335 {
336 if (f->max <= id)
337 continue;
338 if (f->min > id)
339 return GL_FALSE;
340 return GL_TRUE;
341 }
342 return GL_FALSE;
343}
344
345void crHashIdWalkKeys( CRHashIdPool *pool, CRHashIdWalkKeys walkFunc , void *data)
346{
347 FreeElem *prev = NULL, *f;
348
349 RTListForEach(&pool->freeList, f, FreeElem, Node)
350 {
351 if (prev)
352 {
353 Assert(prev->max < f->min);
354 walkFunc(prev->max+1, f->min - prev->max, data);
355 }
356 else if (f->min > pool->min)
357 {
358 walkFunc(pool->min, f->min - pool->min, data);
359 }
360
361 prev = f;
362 }
363
364 Assert(prev->max <= pool->max);
365
366 if (prev->max < pool->max)
367 {
368 walkFunc(prev->max+1, pool->max - prev->max, data);
369 }
370}
371
372CRHashTable *crAllocHashtableEx( GLuint min, GLuint max )
373{
374 int i;
375 CRHashTable *hash = (CRHashTable *) crCalloc( sizeof( CRHashTable )) ;
376 hash->num_elements = 0;
377 for (i = 0 ; i < CR_NUM_BUCKETS ; i++)
378 {
379 hash->buckets[i] = NULL;
380 }
381 hash->idPool = crAllocHashIdPoolEx( min, max );
382 crInitMutex(&hash->mutex);
383 return hash;
384}
385
386CRHashTable *crAllocHashtable( void )
387{
388 return crAllocHashtableEx(CR_HASH_ID_MIN, CR_HASH_ID_MAX);
389}
390
391void crFreeHashtable( CRHashTable *hash, CRHashtableCallback deleteFunc )
392{
393 int i;
394 CRHashNode *entry, *next;
395
396 if ( !hash) return;
397
398 crLockMutex(&hash->mutex);
399 for ( i = 0; i < CR_NUM_BUCKETS; i++ )
400 {
401 entry = hash->buckets[i];
402 while (entry)
403 {
404 next = entry->next;
405 /* Clear the key in case crHashtableDelete() is called
406 * from this callback.
407 */
408 entry->key = 0;
409 if (deleteFunc && entry->data)
410 {
411 (*deleteFunc)(entry->data);
412 }
413 crFree(entry);
414 entry = next;
415
416 }
417 }
418 crFreeHashIdPool( hash->idPool );
419 crUnlockMutex(&hash->mutex);
420 crFreeMutex(&hash->mutex);
421 crFree( hash );
422}
423
424void crFreeHashtableEx(CRHashTable *hash, CRHashtableCallbackEx deleteFunc, void *pData)
425{
426 int i;
427 CRHashNode *entry, *next;
428
429 if (!hash) return;
430
431 crLockMutex(&hash->mutex);
432 for (i = 0; i < CR_NUM_BUCKETS; i++)
433 {
434 entry = hash->buckets[i];
435 while (entry)
436 {
437 next = entry->next;
438 /* Clear the key in case crHashtableDelete() is called
439 * from this callback.
440 */
441 entry->key = 0;
442 if (deleteFunc && entry->data)
443 {
444 (*deleteFunc)(entry->data, pData);
445 }
446 crFree(entry);
447 entry = next;
448
449 }
450 }
451 crFreeHashIdPool(hash->idPool);
452
453 crUnlockMutex(&hash->mutex);
454 crFreeMutex(&hash->mutex);
455 crFree(hash);
456}
457
458
459void crHashtableLock(CRHashTable *h)
460{
461 crLockMutex(&h->mutex);
462}
463
464void crHashtableUnlock(CRHashTable *h)
465{
466 crUnlockMutex(&h->mutex);
467}
468
469void crHashtableWalkUnlocked( CRHashTable *hash, CRHashtableWalkCallback walkFunc , void *dataPtr2)
470{
471 int i;
472 CRHashNode *entry, *next;
473
474 for (i = 0; i < CR_NUM_BUCKETS; i++)
475 {
476 entry = hash->buckets[i];
477 while (entry)
478 {
479 /* save next ptr here, in case walkFunc deletes this entry */
480 next = entry->next;
481 if (entry->data && walkFunc) {
482 (*walkFunc)( entry->key, entry->data, dataPtr2 );
483 }
484 entry = next;
485 }
486 }
487}
488
489void crHashtableWalk( CRHashTable *hash, CRHashtableWalkCallback walkFunc , void *dataPtr2)
490{
491 if (!hash)
492 return;
493
494 crLockMutex(&hash->mutex);
495 crHashtableWalkUnlocked(hash, walkFunc , dataPtr2);
496 crUnlockMutex(&hash->mutex);
497}
498
499static unsigned int crHash( unsigned long key )
500{
501 return key % CR_NUM_BUCKETS;
502}
503
504void crHashtableAdd( CRHashTable *h, unsigned long key, void *data )
505{
506 unsigned int index = crHash(key);
507 CRHashNode *node = (CRHashNode *) crCalloc( sizeof( CRHashNode ) );
508
509 crLockMutex(&h->mutex);
510 node->key = key;
511 node->data = data;
512 node->next = h->buckets[index];
513 h->buckets[index] = node;
514 h->num_elements++;
515 crHashIdPoolAllocId (h->idPool, key);
516 crUnlockMutex(&h->mutex);
517}
518
519GLboolean crHashtableAllocRegisterKey( CRHashTable *h, GLuint key)
520{
521 GLboolean fAllocated;
522
523 crLockMutex(&h->mutex);
524 fAllocated = crHashIdPoolAllocId (h->idPool, key);
525 crUnlockMutex(&h->mutex);
526 return fAllocated;
527}
528
529void crHashtableWalkKeys( CRHashTable *h, CRHashIdWalkKeys walkFunc , void *data)
530{
531 crLockMutex(&h->mutex);
532 crHashIdWalkKeys(h->idPool, walkFunc , data);
533 crUnlockMutex(&h->mutex);
534}
535
536GLuint crHashtableAllocKeys( CRHashTable *h, GLsizei range)
537{
538 GLuint res;
539
540 crLockMutex(&h->mutex);
541 res = crHashIdPoolAllocBlock (h->idPool, range);
542#ifdef DEBUG_misha
543 {
544 int i;
545 Assert(res);
546 for (i = 0; i < range; ++i)
547 {
548 void *search = crHashtableSearch( h, res+i );
549 Assert(!search);
550 }
551 }
552#endif
553 crUnlockMutex(&h->mutex);
554 return res;
555}
556
557void crHashtableDelete( CRHashTable *h, unsigned long key, CRHashtableCallback deleteFunc )
558{
559 unsigned int index = crHash( key );
560 CRHashNode *temp, *beftemp = NULL;
561
562 crLockMutex(&h->mutex);
563 for ( temp = h->buckets[index]; temp; temp = temp->next )
564 {
565 if ( temp->key == key )
566 break;
567 beftemp = temp;
568 }
569 if ( temp )
570 {
571 if ( beftemp )
572 beftemp->next = temp->next;
573 else
574 h->buckets[index] = temp->next;
575 h->num_elements--;
576 if (temp->data && deleteFunc) {
577 (*deleteFunc)( temp->data );
578 }
579
580 crFree( temp );
581 }
582
583 crHashIdPoolFreeBlock( h->idPool, key, 1 );
584 crUnlockMutex(&h->mutex);
585}
586
587void crHashtableDeleteEx(CRHashTable *h, unsigned long key, CRHashtableCallbackEx deleteFunc, void *pData)
588{
589 unsigned int index = crHash( key );
590 CRHashNode *temp, *beftemp = NULL;
591
592 crLockMutex(&h->mutex);
593 for (temp = h->buckets[index]; temp; temp = temp->next)
594 {
595 if (temp->key == key)
596 break;
597 beftemp = temp;
598 }
599 if (temp)
600 {
601 if (beftemp)
602 beftemp->next = temp->next;
603 else
604 h->buckets[index] = temp->next;
605 h->num_elements--;
606 if (temp->data && deleteFunc) {
607 (*deleteFunc)(temp->data, pData);
608 }
609
610 crFree(temp);
611 }
612
613 crHashIdPoolFreeBlock(h->idPool, key, 1);
614 crUnlockMutex(&h->mutex);
615}
616
617
618void crHashtableDeleteBlock( CRHashTable *h, unsigned long key, GLsizei range, CRHashtableCallback deleteFunc )
619{
620 /* XXX optimize someday */
621 GLuint i;
622 for (i = 0; i < (GLuint)range; i++) {
623 crHashtableDelete( h, key, deleteFunc );
624 }
625}
626
627void *crHashtableSearch( const CRHashTable *h, unsigned long key )
628{
629 unsigned int index = crHash( key );
630 CRHashNode *temp;
631
632 crLockMutex((CRmutex *)&h->mutex);
633 for ( temp = h->buckets[index]; temp; temp = temp->next )
634 {
635 if ( temp->key == key )
636 break;
637 }
638 crUnlockMutex((CRmutex *)&h->mutex);
639 if ( !temp )
640 {
641 return NULL;
642 }
643 return temp->data;
644}
645
646void crHashtableReplace( CRHashTable *h, unsigned long key, void *data,
647 CRHashtableCallback deleteFunc)
648{
649 unsigned int index = crHash( key );
650 CRHashNode *temp;
651
652 crLockMutex(&h->mutex);
653 for ( temp = h->buckets[index]; temp; temp = temp->next )
654 {
655 if ( temp->key == key )
656 break;
657 }
658 crUnlockMutex(&h->mutex);
659 if ( !temp )
660 {
661 crHashtableAdd( h, key, data );
662 return;
663 }
664 crLockMutex(&h->mutex);
665 if ( temp->data && deleteFunc )
666 {
667 (*deleteFunc)( temp->data );
668 }
669 temp->data = data;
670 crUnlockMutex(&h->mutex);
671}
672
673unsigned int crHashtableNumElements( const CRHashTable *h)
674{
675 if (h)
676 return h->num_elements;
677 else
678 return 0;
679}
680
681/*
682 * Determine if the given key is used. Return GL_TRUE if so.
683 */
684GLboolean crHashtableIsKeyUsed( const CRHashTable *h, GLuint id )
685{
686 return (GLboolean) !crHashIdPoolIsIdFree( h->idPool, id);
687}
688
689GLboolean crHashtableGetDataKey(CRHashTable *pHash, void *pData, unsigned long *pKey)
690{
691 int i;
692 CRHashNode *entry;
693 GLboolean rc = GL_FALSE;
694
695 if (!pHash)
696 return rc;
697
698 crLockMutex(&pHash->mutex);
699 for (i = 0; i<CR_NUM_BUCKETS && !rc; i++)
700 {
701 entry = pHash->buckets[i];
702 while (entry)
703 {
704 if (entry->data == pData) {
705 if (pKey)
706 *pKey = entry->key;
707 rc = GL_TRUE;
708 break;
709 }
710 entry = entry->next;
711 }
712 }
713
714 crUnlockMutex(&pHash->mutex);
715 return rc;
716}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette