From be9e6893e5063e803a0cfa7da44f902c7f0ba708 Mon Sep 17 00:00:00 2001 From: Bill Currie <bill@taniwha.org> Date: Sat, 4 Mar 2023 02:07:31 +0900 Subject: [PATCH] [util] Free up hash links Finally, hash links can be freed when the hash context is no longer relevant. The context is created automatically when needed, and the owner can delete the context when its done with the relevant hash tables. --- include/QF/hash.h | 2 + libs/util/hash.c | 71 +++++++++++++++++++++++++++--------- ruamoko/qwaq/builtins/main.c | 3 ++ 3 files changed, 58 insertions(+), 18 deletions(-) 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; }