VirtualBox

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

Last change on this file since 30440 was 21668, checked in by vboxsync, 15 years ago

crOpenGL: fix memory leaks when terminating guest apps

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 12.7 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
355
356void crHashtableWalk( CRHashTable *hash, CRHashtableWalkCallback walkFunc , void *dataPtr2)
357{
358 int i;
359 CRHashNode *entry, *next;
360
361 if (!hash)
362 return;
363
364#ifdef CHROMIUM_THREADSAFE
365 crLockMutex(&hash->mutex);
366#endif
367 for (i = 0; i < CR_NUM_BUCKETS; i++)
368 {
369 entry = hash->buckets[i];
370 while (entry)
371 {
372 /* save next ptr here, in case walkFunc deletes this entry */
373 next = entry->next;
374 if (entry->data && walkFunc) {
375 (*walkFunc)( entry->key, entry->data, dataPtr2 );
376 }
377 entry = next;
378 }
379 }
380#ifdef CHROMIUM_THREADSAFE
381 crUnlockMutex(&hash->mutex);
382#endif
383}
384
385static unsigned int crHash( unsigned long key )
386{
387 return key % CR_NUM_BUCKETS;
388}
389
390void crHashtableAdd( CRHashTable *h, unsigned long key, void *data )
391{
392 CRHashNode *node = (CRHashNode *) crCalloc( sizeof( CRHashNode ) );
393#ifdef CHROMIUM_THREADSAFE
394 crLockMutex(&h->mutex);
395#endif
396 node->key = key;
397 node->data = data;
398 node->next = h->buckets[crHash( key )];
399 h->buckets[ crHash( key ) ] = node;
400 h->num_elements++;
401 crHashIdPoolAllocId (h->idPool, key);
402#ifdef CHROMIUM_THREADSAFE
403 crUnlockMutex(&h->mutex);
404#endif
405}
406
407GLuint crHashtableAllocKeys( CRHashTable *h, GLsizei range)
408{
409 GLuint res;
410 int i;
411
412#ifdef CHROMIUM_THREADSAFE
413 crLockMutex(&h->mutex);
414#endif
415 res = crHashIdPoolAllocBlock (h->idPool, range);
416#ifdef CHROMIUM_THREADSAFE
417 crUnlockMutex(&h->mutex);
418#endif
419 for ( i = 0; i < range; i++)
420 crHashtableAdd( h, i + res , NULL );
421 return res;
422}
423
424void crHashtableDelete( CRHashTable *h, unsigned long key, CRHashtableCallback deleteFunc )
425{
426 unsigned int index = crHash( key );
427 CRHashNode *temp, *beftemp = NULL;
428
429#ifdef CHROMIUM_THREADSAFE
430 crLockMutex(&h->mutex);
431#endif
432 for ( temp = h->buckets[index]; temp; temp = temp->next )
433 {
434 if ( temp->key == key )
435 break;
436 beftemp = temp;
437 }
438 if ( !temp ) {
439#ifdef CHROMIUM_THREADSAFE
440 crUnlockMutex(&h->mutex);
441#endif
442 return; /* not an error */
443 }
444 if ( beftemp )
445 beftemp->next = temp->next;
446 else
447 h->buckets[index] = temp->next;
448 h->num_elements--;
449 if (temp->data && deleteFunc) {
450 (*deleteFunc)( temp->data );
451 }
452
453 crFree( temp );
454
455 crHashIdPoolFreeBlock( h->idPool, key, 1 );
456#ifdef CHROMIUM_THREADSAFE
457 crUnlockMutex(&h->mutex);
458#endif
459}
460
461void crHashtableDeleteBlock( CRHashTable *h, unsigned long key, GLsizei range, CRHashtableCallback deleteFunc )
462{
463 /* XXX optimize someday */
464 GLuint i;
465 for (i = 0; i < (GLuint)range; i++) {
466 crHashtableDelete( h, key, deleteFunc );
467 }
468}
469
470void *crHashtableSearch( const CRHashTable *h, unsigned long key )
471{
472 unsigned int index = crHash( key );
473 CRHashNode *temp;
474#ifdef CHROMIUM_THREADSAFE
475 crLockMutex((CRmutex *)&h->mutex);
476#endif
477 for ( temp = h->buckets[index]; temp; temp = temp->next )
478 {
479 if ( temp->key == key )
480 break;
481 }
482#ifdef CHROMIUM_THREADSAFE
483 crUnlockMutex((CRmutex *)&h->mutex);
484#endif
485 if ( !temp )
486 {
487 return NULL;
488 }
489 return temp->data;
490}
491
492void crHashtableReplace( CRHashTable *h, unsigned long key, void *data,
493 CRHashtableCallback deleteFunc)
494{
495 unsigned int index = crHash( key );
496 CRHashNode *temp;
497#ifdef CHROMIUM_THREADSAFE
498 crLockMutex(&h->mutex);
499#endif
500 for ( temp = h->buckets[index]; temp; temp = temp->next )
501 {
502 if ( temp->key == key )
503 break;
504 }
505#ifdef CHROMIUM_THREADSAFE
506 crUnlockMutex(&h->mutex);
507#endif
508 if ( !temp )
509 {
510 crHashtableAdd( h, key, data );
511 return;
512 }
513#ifdef CHROMIUM_THREADSAFE
514 crLockMutex(&h->mutex);
515#endif
516 if ( temp->data && deleteFunc )
517 {
518 (*deleteFunc)( temp->data );
519 }
520 temp->data = data;
521#ifdef CHROMIUM_THREADSAFE
522 crUnlockMutex(&h->mutex);
523#endif
524}
525
526unsigned int crHashtableNumElements( const CRHashTable *h)
527{
528 if (h)
529 return h->num_elements;
530 else
531 return 0;
532}
533
534/*
535 * Determine if the given key is used. Return GL_TRUE if so.
536 */
537GLboolean crHashtableIsKeyUsed( const CRHashTable *h, GLuint id )
538{
539 return (GLboolean) !crHashIdPoolIsIdFree( h->idPool, id);
540}
541
542GLboolean crHashtableGetDataKey(CRHashTable *pHash, void *pData, unsigned long *pKey)
543{
544 int i;
545 CRHashNode *entry;
546 GLboolean rc = GL_FALSE;
547
548 if (!pHash)
549 return rc;
550
551#ifdef CHROMIUM_THREADSAFE
552 crLockMutex(&pHash->mutex);
553#endif
554 for (i = 0; i<CR_NUM_BUCKETS && !rc; i++)
555 {
556 entry = pHash->buckets[i];
557 while (entry)
558 {
559 if (entry->data == pData) {
560 if (pKey)
561 *pKey = entry->key;
562 rc = GL_TRUE;
563 break;
564 }
565 entry = entry->next;
566 }
567 }
568#ifdef CHROMIUM_THREADSAFE
569 crUnlockMutex(&pHash->mutex);
570#endif
571
572 return rc;
573}
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