summaryrefslogtreecommitdiff
path: root/deps/sysobj_early/src/auto_free.c
diff options
context:
space:
mode:
authorLucas de Castro Borges <lucas@gnuabordo.com.br>2024-04-22 00:35:53 -0300
committerLucas de Castro Borges <lucas@gnuabordo.com.br>2024-04-22 00:35:53 -0300
commit5f01c706267c595de92406a32e7f31ef5056c2d0 (patch)
treed1e74ef54efc41ada622900fe3e2a50dee44a237 /deps/sysobj_early/src/auto_free.c
parent09fcc751ef158898c315ebc9299a0fa3a722d914 (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.c219
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);
+}