VirtualBox

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

Last change on this file since 37986 was 37986, checked in by vboxsync, 13 years ago

Wddm/3d: fix thread sync issues

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 12.8 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#define CR_MAXUINT ((GLuint) 0xFFFFFFFF)
13
14#define CR_NUM_BUCKETS 1047
15
16typedef struct FreeElemRec {
17 GLuint min;
18 GLuint max;
19 struct FreeElemRec *next;
20 struct FreeElemRec *prev;
21} FreeElem;
22
23typedef struct CRHashIdPoolRec {
24 FreeElem *freeList;
25} CRHashIdPool;
26
27typedef struct CRHashNode {
28 unsigned long key;
29 void *data;
30 struct CRHashNode *next;
31} CRHashNode;
32
33struct CRHashTable {
34 unsigned int num_elements;
35 CRHashNode *buckets[CR_NUM_BUCKETS];
36 CRHashIdPool *idPool;
37#ifdef CHROMIUM_THREADSAFE
38 CRmutex mutex;
39#endif
40};
41
42
43static CRHashIdPool *crAllocHashIdPool( void )
44{
45 CRHashIdPool *pool = (CRHashIdPool *) crCalloc(sizeof(CRHashIdPool));
46 pool->freeList = (FreeElem *) crCalloc(sizeof(FreeElem));
47 pool->freeList->min = 1;
48 pool->freeList->max = CR_MAXUINT;
49 pool->freeList->next = NULL;
50 pool->freeList->prev = NULL;
51 return pool;
52}
53
54static void crFreeHashIdPool( CRHashIdPool *pool )
55{
56 FreeElem *i, *next;
57 for (i = pool->freeList; i; i = next)
58 {
59 next = i->next;
60 crFree(i);
61 }
62 crFree(pool);
63}
64
65/*
66 * Allocate a block of <count> IDs. Return index of first one.
67 * Return 0 if we fail.
68 */
69static GLuint crHashIdPoolAllocBlock( CRHashIdPool *pool, GLuint count )
70{
71 FreeElem *f;
72 GLuint ret;
73
74 CRASSERT(count > 0);
75
76 f = pool->freeList;
77 while (f)
78 {
79 if (f->max - f->min + 1 >= (GLuint) count)
80 {
81 /* found a sufficiently large enough block */
82 ret = f->min;
83 f->min += count;
84
85 if (f->min == f->max)
86 {
87 /* remove this block from linked list */
88 if (f == pool->freeList)
89 {
90 /* remove from head */
91 pool->freeList = pool->freeList->next;
92 pool->freeList->prev = NULL;
93 }
94 else
95 {
96 /* remove from elsewhere */
97 f->prev->next = f->next;
98 f->next->prev = f->prev;
99 }
100 crFree(f);
101 }
102
103#ifdef DEBUG
104 /* make sure the IDs really are allocated */
105 {
106 GLuint i;
107 for (i = 0; i < count; i++)
108 {
109 //CRASSERT(crHashIdPoolIsIdUsed(pool, ret + i));
110 }
111 }
112#endif
113
114 return ret;
115 }
116 else {
117 f = f->next;
118 }
119 }
120
121 /* failed to find free block */
122 crDebug("crHashIdPoolAllocBlock failed");
123 return 0;
124}
125
126
127/*
128 * Free a block of <count> IDs starting at <first>.
129 */
130static void crHashIdPoolFreeBlock( CRHashIdPool *pool, GLuint first, GLuint count )
131{
132 FreeElem *i;
133 FreeElem *newelem;
134
135 /*********************************/
136 /* Add the name to the freeList */
137 /* Find the bracketing sequences */
138
139 for (i = pool->freeList; i && i->next && i->next->min < first; i = i->next)
140 {
141 /* EMPTY BODY */
142 }
143
144 /* j will always be valid */
145 if (!i) {
146 return;
147 }
148 if (!i->next && i->max == first) {
149 return;
150 }
151
152 /* Case: j:(~,first-1) */
153 if (i->max + 1 == first)
154 {
155 i->max += count;
156 if (i->next && i->max+1 >= i->next->min)
157 {
158 /* Collapse */
159 i->next->min = i->min;
160 i->next->prev = i->prev;
161 if (i->prev)
162 {
163 i->prev->next = i->next;
164 }
165 if (i == pool->freeList)
166 {
167 pool->freeList = i->next;
168 }
169 crFree(i);
170 }
171 return;
172 }
173
174 /* Case: j->next: (first+1, ~) */
175 if (i->next && i->next->min - count == first)
176 {
177 i->next->min -= count;
178 if (i->max + 1 >= i->next->min)
179 {
180 /* Collapse */
181 i->next->min = i->min;
182 i->next->prev = i->prev;
183 if (i->prev)
184 {
185 i->prev->next = i->next;
186 }
187 if (i == pool->freeList)
188 {
189 pool->freeList = i->next;
190 }
191 crFree(i);
192 }
193 return;
194 }
195
196 /* Case: j: (first+1, ~) j->next: null */
197 if (!i->next && i->min - count == first)
198 {
199 i->min -= count;
200 return;
201 }
202
203 /* allocate a new FreeElem node */
204 newelem = (FreeElem *) crCalloc(sizeof(FreeElem));
205 newelem->min = first;
206 newelem->max = first + count - 1;
207
208 /* Case: j: (~,first-(2+)) j->next: (first+(2+), ~) or null */
209 if (first > i->max)
210 {
211 newelem->prev = i;
212 newelem->next = i->next;
213 if (i->next)
214 {
215 i->next->prev = newelem;
216 }
217 i->next = newelem;
218 return;
219 }
220
221 /* Case: j: (first+(2+), ~) */
222 /* Can only happen if j = t->freeList! */
223 if (i == pool->freeList && i->min > first)
224 {
225 newelem->next = i;
226 newelem->prev = i->prev;
227 i->prev = newelem;
228 pool->freeList = newelem;
229 return;
230 }
231}
232
233
234
235/*
236 * Mark the given Id as being allocated.
237 */
238static void crHashIdPoolAllocId( CRHashIdPool *pool, GLuint id )
239{
240 FreeElem *f;
241
242 f = pool->freeList;
243 while (f)
244 {
245 if (id >= f->min && id <= f->max)
246 {
247 /* found the block */
248 if (id == f->min)
249 {
250 f->min++;
251 }
252 else if (id == f->max)
253 {
254 f->max--;
255 }
256 else
257 {
258 /* somewhere in the middle - split the block */
259 FreeElem *newelem = (FreeElem *) crCalloc(sizeof(FreeElem));
260 newelem->min = id + 1;
261 newelem->max = f->max;
262 f->max = id - 1;
263 newelem->next = f->next;
264 if (f->next)
265 f->next->prev = newelem;
266 newelem->prev = f;
267 f->next = newelem;
268 }
269 return;
270 }
271 f = f->next;
272 }
273
274 /* if we get here, the ID was already allocated - that's OK */
275}
276
277
278/*
279 * Determine if the given id is free. Return GL_TRUE if so.
280 */
281static GLboolean crHashIdPoolIsIdFree( const CRHashIdPool *pool, GLuint id )
282{
283 FreeElem *i;
284
285 /* First find which region it fits in */
286 for (i = pool->freeList; i && !(i->min <= id && id <= i->max); i=i->next)
287 {
288 /* EMPTY BODY */
289 }
290
291 if (i)
292 return GL_TRUE;
293 else
294 return GL_FALSE;
295}
296
297
298
299CRHashTable *crAllocHashtable( void )
300{
301 int i;
302 CRHashTable *hash = (CRHashTable *) crCalloc( sizeof( CRHashTable )) ;
303 hash->num_elements = 0;
304 for (i = 0 ; i < CR_NUM_BUCKETS ; i++)
305 {
306 hash->buckets[i] = NULL;
307 }
308 hash->idPool = crAllocHashIdPool();
309#ifdef CHROMIUM_THREADSAFE
310 crInitMutex(&hash->mutex);
311#endif
312 return hash;
313}
314
315void crFreeHashtable( CRHashTable *hash, CRHashtableCallback deleteFunc )
316{
317 int i;
318 CRHashNode *entry, *next;
319
320 if ( !hash) return;
321
322#ifdef CHROMIUM_THREADSAFE
323 crLockMutex(&hash->mutex);
324#endif
325
326 for ( i = 0; i < CR_NUM_BUCKETS; i++ )
327 {
328 entry = hash->buckets[i];
329 while (entry)
330 {
331 next = entry->next;
332 /* Clear the key in case crHashtableDelete() is called
333 * from this callback.
334 */
335 entry->key = 0;
336 if (deleteFunc && entry->data)
337 {
338 (*deleteFunc)(entry->data);
339 }
340 crFree(entry);
341 entry = next;
342
343 }
344 }
345 crFreeHashIdPool( hash->idPool );
346
347#ifdef CHROMIUM_THREADSAFE
348 crUnlockMutex(&hash->mutex);
349 crFreeMutex(&hash->mutex);
350#endif
351
352 crFree( hash );
353}
354
355void crHashtableLock(CRHashTable *h)
356{
357#ifdef CHROMIUM_THREADSAFE
358 crLockMutex(&h->mutex);
359#endif
360}
361
362void crHashtableUnlock(CRHashTable *h)
363{
364#ifdef CHROMIUM_THREADSAFE
365 crUnlockMutex(&h->mutex);
366#endif
367}
368
369void crHashtableWalk( CRHashTable *hash, CRHashtableWalkCallback walkFunc , void *dataPtr2)
370{
371 int i;
372 CRHashNode *entry, *next;
373
374 if (!hash)
375 return;
376
377#ifdef CHROMIUM_THREADSAFE
378 crLockMutex(&hash->mutex);
379#endif
380 for (i = 0; i < CR_NUM_BUCKETS; i++)
381 {
382 entry = hash->buckets[i];
383 while (entry)
384 {
385 /* save next ptr here, in case walkFunc deletes this entry */
386 next = entry->next;
387 if (entry->data && walkFunc) {
388 (*walkFunc)( entry->key, entry->data, dataPtr2 );
389 }
390 entry = next;
391 }
392 }
393#ifdef CHROMIUM_THREADSAFE
394 crUnlockMutex(&hash->mutex);
395#endif
396}
397
398static unsigned int crHash( unsigned long key )
399{
400 return key % CR_NUM_BUCKETS;
401}
402
403void crHashtableAdd( CRHashTable *h, unsigned long key, void *data )
404{
405 CRHashNode *node = (CRHashNode *) crCalloc( sizeof( CRHashNode ) );
406#ifdef CHROMIUM_THREADSAFE
407 crLockMutex(&h->mutex);
408#endif
409 node->key = key;
410 node->data = data;
411 node->next = h->buckets[crHash( key )];
412 h->buckets[ crHash( key ) ] = node;
413 h->num_elements++;
414 crHashIdPoolAllocId (h->idPool, key);
415#ifdef CHROMIUM_THREADSAFE
416 crUnlockMutex(&h->mutex);
417#endif
418}
419
420GLuint crHashtableAllocKeys( CRHashTable *h, GLsizei range)
421{
422 GLuint res;
423 int i;
424
425#ifdef CHROMIUM_THREADSAFE
426 crLockMutex(&h->mutex);
427#endif
428 res = crHashIdPoolAllocBlock (h->idPool, range);
429#ifdef CHROMIUM_THREADSAFE
430 crUnlockMutex(&h->mutex);
431#endif
432 return res;
433}
434
435void crHashtableDelete( CRHashTable *h, unsigned long key, CRHashtableCallback deleteFunc )
436{
437 unsigned int index = crHash( key );
438 CRHashNode *temp, *beftemp = NULL;
439
440#ifdef CHROMIUM_THREADSAFE
441 crLockMutex(&h->mutex);
442#endif
443 for ( temp = h->buckets[index]; temp; temp = temp->next )
444 {
445 if ( temp->key == key )
446 break;
447 beftemp = temp;
448 }
449 if ( !temp ) {
450#ifdef CHROMIUM_THREADSAFE
451 crUnlockMutex(&h->mutex);
452#endif
453 return; /* not an error */
454 }
455 if ( beftemp )
456 beftemp->next = temp->next;
457 else
458 h->buckets[index] = temp->next;
459 h->num_elements--;
460 if (temp->data && deleteFunc) {
461 (*deleteFunc)( temp->data );
462 }
463
464 crFree( temp );
465
466 crHashIdPoolFreeBlock( h->idPool, key, 1 );
467#ifdef CHROMIUM_THREADSAFE
468 crUnlockMutex(&h->mutex);
469#endif
470}
471
472void crHashtableDeleteBlock( CRHashTable *h, unsigned long key, GLsizei range, CRHashtableCallback deleteFunc )
473{
474 /* XXX optimize someday */
475 GLuint i;
476 for (i = 0; i < (GLuint)range; i++) {
477 crHashtableDelete( h, key, deleteFunc );
478 }
479}
480
481void *crHashtableSearch( const CRHashTable *h, unsigned long key )
482{
483 unsigned int index = crHash( key );
484 CRHashNode *temp;
485#ifdef CHROMIUM_THREADSAFE
486 crLockMutex((CRmutex *)&h->mutex);
487#endif
488 for ( temp = h->buckets[index]; temp; temp = temp->next )
489 {
490 if ( temp->key == key )
491 break;
492 }
493#ifdef CHROMIUM_THREADSAFE
494 crUnlockMutex((CRmutex *)&h->mutex);
495#endif
496 if ( !temp )
497 {
498 return NULL;
499 }
500 return temp->data;
501}
502
503void crHashtableReplace( CRHashTable *h, unsigned long key, void *data,
504 CRHashtableCallback deleteFunc)
505{
506 unsigned int index = crHash( key );
507 CRHashNode *temp;
508#ifdef CHROMIUM_THREADSAFE
509 crLockMutex(&h->mutex);
510#endif
511 for ( temp = h->buckets[index]; temp; temp = temp->next )
512 {
513 if ( temp->key == key )
514 break;
515 }
516#ifdef CHROMIUM_THREADSAFE
517 crUnlockMutex(&h->mutex);
518#endif
519 if ( !temp )
520 {
521 crHashtableAdd( h, key, data );
522 return;
523 }
524#ifdef CHROMIUM_THREADSAFE
525 crLockMutex(&h->mutex);
526#endif
527 if ( temp->data && deleteFunc )
528 {
529 (*deleteFunc)( temp->data );
530 }
531 temp->data = data;
532#ifdef CHROMIUM_THREADSAFE
533 crUnlockMutex(&h->mutex);
534#endif
535}
536
537unsigned int crHashtableNumElements( const CRHashTable *h)
538{
539 if (h)
540 return h->num_elements;
541 else
542 return 0;
543}
544
545/*
546 * Determine if the given key is used. Return GL_TRUE if so.
547 */
548GLboolean crHashtableIsKeyUsed( const CRHashTable *h, GLuint id )
549{
550 return (GLboolean) !crHashIdPoolIsIdFree( h->idPool, id);
551}
552
553GLboolean crHashtableGetDataKey(CRHashTable *pHash, void *pData, unsigned long *pKey)
554{
555 int i;
556 CRHashNode *entry;
557 GLboolean rc = GL_FALSE;
558
559 if (!pHash)
560 return rc;
561
562#ifdef CHROMIUM_THREADSAFE
563 crLockMutex(&pHash->mutex);
564#endif
565 for (i = 0; i<CR_NUM_BUCKETS && !rc; i++)
566 {
567 entry = pHash->buckets[i];
568 while (entry)
569 {
570 if (entry->data == pData) {
571 if (pKey)
572 *pKey = entry->key;
573 rc = GL_TRUE;
574 break;
575 }
576 entry = entry->next;
577 }
578 }
579#ifdef CHROMIUM_THREADSAFE
580 crUnlockMutex(&pHash->mutex);
581#endif
582
583 return rc;
584}
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