diff --git a/include/QF/hash.h b/include/QF/hash.h index 8faa44aa5..df9773042 100644 --- a/include/QF/hash.h +++ b/include/QF/hash.h @@ -93,6 +93,8 @@ void Hash_SetHashCompare (hashtab_t *tab, uintptr_t (*gh)(const void*,void*), */ void Hash_DelTable (hashtab_t *tab); +void Hash_DelContext (hashctx_t *hashctx); + /** clean out all the entries from a hash table, starting over again. \param tab the table to be cleared */ diff --git a/libs/util/hash.c b/libs/util/hash.c index 14f41623f..d88f71aec 100644 --- a/libs/util/hash.c +++ b/libs/util/hash.c @@ -51,6 +51,15 @@ typedef struct hashlink_s { void *data; } hashlink_t; +typedef struct hlinkset_s { + struct hlinkset_s *next; +} hlinkset_t; + +struct hashctx_s { + hlinkset_t *linksets; + hashlink_t *free_hashlinks; +}; + struct hashtab_s { size_t tab_size; unsigned int size_bits; @@ -60,38 +69,41 @@ struct hashtab_s { uintptr_t (*get_hash)(const void*,void*); const char *(*get_key)(const void*,void*); void (*free_ele)(void*,void*); - hashlink_t **hashlink_freelist; + hashctx_t *hashctx; hashlink_t *tab[1]; // variable size }; static hashlink_t * -new_hashlink (hashlink_t **free_hashlinks) +new_hashlink (hashctx_t *hctx) { hashlink_t *link; - if (!*free_hashlinks) { + if (!hctx->free_hashlinks) { int i; - if (!(*free_hashlinks = calloc (1024, sizeof (hashlink_t)))) - return 0; - for (i = 0, link = *free_hashlinks; i < 1023; i++, link++) + hlinkset_t *linkset = malloc (sizeof (hlinkset_t) + + 1024 * sizeof (hashlink_t)); + linkset->next = hctx->linksets; + hctx->linksets = linkset; + hctx->free_hashlinks = (hashlink_t *) &linkset[1]; + for (i = 0, link = hctx->free_hashlinks; i < 1023; i++, link++) link->next = link + 1; link->next = 0; } - link = *free_hashlinks; - *free_hashlinks = link->next; + link = hctx->free_hashlinks; + hctx->free_hashlinks = link->next; link->next = 0; return link; } static void -free_hashlink (hashlink_t *link, hashlink_t **free_hashlinks) +free_hashlink (hashlink_t *link, hashctx_t *hctx) { - link->next = *free_hashlinks; - *free_hashlinks = link; + link->next = hctx->free_hashlinks; + hctx->free_hashlinks = link; } -static hashlink_t *default_hashlink_freelist; +static hashctx_t *default_hashctx; VISIBLE uintptr_t Hash_String (const char *str) @@ -208,6 +220,23 @@ get_index (uintptr_t hash, size_t size, size_t bits) #endif } +static void +hash_shutdown (void *data) +{ + Hash_DelContext (default_hashctx); +} + +VISIBLE void +Hash_DelContext (hashctx_t *hashctx) +{ + while (hashctx->linksets) { + hlinkset_t *l = hashctx->linksets->next; + free (hashctx->linksets); + hashctx->linksets = l; + } + free (hashctx); +} + VISIBLE hashtab_t * Hash_NewTable (int tsize, const char *(*gk)(const void*,void*), void (*f)(void*,void*), void *ud, hashctx_t **hctx) @@ -220,9 +249,15 @@ Hash_NewTable (int tsize, const char *(*gk)(const void*,void*), tab->get_key = gk; tab->free_ele = f; if (!hctx) { - hctx = (hashctx_t **) &default_hashlink_freelist; + hctx = &default_hashctx; + if (!default_hashctx) { + Sys_RegisterShutdown (hash_shutdown, 0); + } } - tab->hashlink_freelist = (hashlink_t **) hctx; + if (!*hctx) { + *hctx = calloc (1, sizeof (hashctx_t)); + } + tab->hashctx = *hctx; while (tsize) { tab->size_bits++; @@ -259,7 +294,7 @@ Hash_FlushTable (hashtab_t *tab) hashlink_t *t = tab->tab[i]->next; void *data = tab->tab[i]->data; - free_hashlink (tab->tab[i], tab->hashlink_freelist); + free_hashlink (tab->tab[i], tab->hashctx); tab->tab[i] = t; if (tab->free_ele) tab->free_ele (data, tab->user_data); @@ -272,7 +307,7 @@ static int hash_add_element (hashtab_t *tab, uintptr_t h, void *ele) { size_t ind = get_index (h, tab->tab_size, tab->size_bits); - hashlink_t *lnk = new_hashlink (tab->hashlink_freelist); + hashlink_t *lnk = new_hashlink (tab->hashctx); if (!lnk) return -1; @@ -415,7 +450,7 @@ Hash_Del (hashtab_t *tab, const char *key) if (lnk->next) lnk->next->prev = lnk->prev; *lnk->prev = lnk->next; - free_hashlink (lnk, tab->hashlink_freelist); + free_hashlink (lnk, tab->hashctx); tab->num_ele--; return data; } @@ -438,7 +473,7 @@ Hash_DelElement (hashtab_t *tab, void *ele) if (lnk->next) lnk->next->prev = lnk->prev; *lnk->prev = lnk->next; - free_hashlink (lnk, tab->hashlink_freelist); + free_hashlink (lnk, tab->hashctx); tab->num_ele--; return data; } diff --git a/ruamoko/qwaq/builtins/main.c b/ruamoko/qwaq/builtins/main.c index 2a4a98b76..2533ab677 100644 --- a/ruamoko/qwaq/builtins/main.c +++ b/ruamoko/qwaq/builtins/main.c @@ -42,6 +42,7 @@ #include "QF/cmd.h" #include "QF/cvar.h" #include "QF/gib.h" +#include "QF/hash.h" #include "QF/idparse.h" #include "QF/keys.h" #include "QF/progs.h" @@ -320,6 +321,8 @@ run_progs (void *data) PR_Shutdown (thread->pr); free (thread->pr); thread->pr = 0; + Hash_DelContext (thread->hashctx); + thread->hashctx = 0; return thread; }