diff options
author | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2024-04-22 00:35:53 -0300 |
---|---|---|
committer | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2024-04-22 00:35:53 -0300 |
commit | 5f01c706267c595de92406a32e7f31ef5056c2d0 (patch) | |
tree | d1e74ef54efc41ada622900fe3e2a50dee44a237 /deps/sysobj_early/src/auto_free.c | |
parent | 09fcc751ef158898c315ebc9299a0fa3a722d914 (diff) |
New upstream version 2.0.3preupstream/2.0.3pre
Diffstat (limited to 'deps/sysobj_early/src/auto_free.c')
-rw-r--r-- | deps/sysobj_early/src/auto_free.c | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/deps/sysobj_early/src/auto_free.c b/deps/sysobj_early/src/auto_free.c new file mode 100644 index 00000000..9a10e27a --- /dev/null +++ b/deps/sysobj_early/src/auto_free.c @@ -0,0 +1,219 @@ +/* + * sysobj - https://github.com/bp0/verbose-spork + * Copyright (C) 2018 Burt P. <pburt0@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "auto_free.h" +#if (AF_USE_SYSOBJ) +#include "sysobj.h" +#else +#include <stdio.h> +#define sysobj_elapsed() af_elapsed() +#define sysobj_stats af_stats +static struct { + double auto_free_next; + unsigned long long + auto_freed, + auto_free_len; +} af_stats; +#endif + +//Compatibility +#ifndef G_SOURCE_REMOVE + #define G_SOURCE_REMOVE FALSE +#endif + +#ifndef G_SOURCE_CONTINUE + #define G_SOURCE_CONTINUE TRUE +#endif + + +static GMutex *free_lock = NULL; +static GSList *free_list = NULL; +static gboolean free_final = FALSE; +static GTimer *auto_free_timer = NULL; +static guint free_event_source = 0; +#define af_elapsed() (auto_free_timer ? g_timer_elapsed(auto_free_timer, NULL) : 0) + +#define auto_free_msg(msg, ...) fprintf (stderr, "[%s] " msg "\n", __FUNCTION__, ##__VA_ARGS__) /**/ + +typedef struct { + gpointer ptr; + GThread *thread; + GDestroyNotify f_free; + double stamp; + + const char *file; + int line; + const char *func; +} auto_free_item; + +gboolean free_auto_free_sf(gpointer trash) { + (void)trash; + if (free_final) { + free_event_source = 0; + return G_SOURCE_REMOVE; + } + free_auto_free(); + sysobj_stats.auto_free_next = sysobj_elapsed() + AF_SECONDS; + return G_SOURCE_CONTINUE; +} + +gpointer auto_free_ex_(gpointer p, GDestroyNotify f, const char *file, int line, const char *func) { + if (!p) return p; + + /* an auto_free() after free_auto_free_final()? + * Changed mind, I guess, just go with it. */ + if (free_final) + free_final = FALSE; + + if (!auto_free_timer) { + auto_free_timer = g_timer_new(); + g_timer_start(auto_free_timer); + } + + if (!free_event_source) { + /* if there is a main loop, then this will call + * free_auto_free() in idle time every AF_SECONDS seconds. + * If there is no main loop, then free_auto_free() + * will be called at sysobj_cleanup() and when exiting + * threads, as in sysobj_foreach(). */ + free_event_source = g_timeout_add_seconds(AF_SECONDS, (GSourceFunc)free_auto_free_sf, NULL); + sysobj_stats.auto_free_next = sysobj_elapsed() + AF_SECONDS; + } + + auto_free_item *z = g_new0(auto_free_item, 1); + z->ptr = p; + z->f_free = f; + z->thread = g_thread_self(); + z->file = file; + z->line = line; + z->func = func; + z->stamp = af_elapsed(); +#if GLIB_CHECK_VERSION(2,32,0) + if(free_lock==NULL) {free_lock=g_new(GMutex,1);g_mutex_init(free_lock);} +#else + if(free_lock==NULL) free_lock=g_mutex_new(); +#endif + g_mutex_lock(free_lock); + free_list = g_slist_prepend(free_list, z); + sysobj_stats.auto_free_len++; + g_mutex_unlock(free_lock); + return p; +} + +gpointer auto_free_on_exit_ex_(gpointer p, GDestroyNotify f, const char *file, int line, const char *func) { + if (!p) return p; + + auto_free_item *z = g_new0(auto_free_item, 1); + z->ptr = p; + z->f_free = f; + z->thread = g_thread_self(); + z->file = file; + z->line = line; + z->func = func; + z->stamp = -1.0; +#if GLIB_CHECK_VERSION(2,32,0) + if(free_lock==NULL) g_mutex_init(free_lock); +#else + if(free_lock==NULL) free_lock=g_mutex_new(); +#endif + g_mutex_lock(free_lock); + free_list = g_slist_prepend(free_list, z); + sysobj_stats.auto_free_len++; + g_mutex_unlock(free_lock); + return p; +} + +static struct { GDestroyNotify fptr; char *name; } + free_function_tab[] = { + { (GDestroyNotify) g_free, "g_free" }, +#if (AF_USE_SYSOBJ) + { (GDestroyNotify) sysobj_free, "sysobj_free" }, + { (GDestroyNotify) class_free, "class_free" }, + { (GDestroyNotify) sysobj_filter_free, "sysobj_filter_free" }, + { (GDestroyNotify) sysobj_virt_free, "sysobj_virt_free" }, +#endif + { NULL, "(null)" }, +}; + +static void free_auto_free_ex(gboolean thread_final) { + GThread *this_thread = g_thread_self(); + GSList *l = NULL, *n = NULL; + long long unsigned fc = 0; + double now = af_elapsed(); + + if (!free_list) return; + +#if GLIB_CHECK_VERSION(2,32,0) + if(free_lock==NULL) {free_lock=g_new(GMutex,1);g_mutex_init(free_lock);} +#else + if(free_lock==NULL) free_lock=g_mutex_new(); +#endif + g_mutex_lock(free_lock); + if (DEBUG_AUTO_FREE) + auto_free_msg("%llu total items in queue, but will free from thread %p only... ", sysobj_stats.auto_free_len, this_thread); + for(l = free_list; l; l = n) { + auto_free_item *z = (auto_free_item*)l->data; + n = l->next; + if (!free_final && z->stamp < 0) continue; + double age = now - z->stamp; + if (free_final || (z->thread == this_thread && (thread_final || age > AF_DELAY_SECONDS) ) ) { + if (DEBUG_AUTO_FREE == 2) { + char fptr[128] = "", *fname; + for(int i = 0; i < (int)G_N_ELEMENTS(free_function_tab); i++) + if (z->f_free == free_function_tab[i].fptr) + fname = free_function_tab[i].name; + if (!fname) { + snprintf(fname, 127, "%p", z->f_free); + fname = fptr; + } + if (z->file || z->func) + auto_free_msg("free: %s(%p) age:%lfs from %s:%d %s()", fname, z->ptr, age, z->file, z->line, z->func); + else + auto_free_msg("free: %s(%p) age:%lfs", fname, z->ptr, age); + } + + z->f_free(z->ptr); + g_free(z); + free_list = g_slist_delete_link(free_list, l); + fc++; + } + } + if (DEBUG_AUTO_FREE) + auto_free_msg("... freed %llu (from thread %p)", fc, this_thread); + sysobj_stats.auto_freed += fc; + sysobj_stats.auto_free_len -= fc; + g_mutex_unlock(free_lock); +} + +void free_auto_free_thread_final() { + free_auto_free_ex(TRUE); +} + +void free_auto_free_final() { + free_final = TRUE; + free_auto_free_ex(TRUE); + if (auto_free_timer) + g_timer_destroy(auto_free_timer); + auto_free_timer = NULL; +} + +void free_auto_free() { + free_auto_free_ex(FALSE); +} |