@cryptotaxi247 / netdata / commits / 8fb66be12

libnetdata: make standalone-linkable (#22528)

* libnetdata: register thread-exit cleanups via callbacks Replace the five hard-coded daemon-side cleanup calls in threads.c (rrd_collector_finished, sender_thread_buffer_free, rrdset_thread_rda_free, query_target_free, service_exits) with a register-callback API. The daemon registers its cleanups in rrd_init; libnetdata walks the registered list at thread exit. After this, libnetdata.a no longer carries unresolved references to the five daemon functions. * libnetdata: own all netdata_configured_* globals Move the twelve netdata_configured_* globals (hostname, host_prefix, plus the ten config-path strings) from src/daemon/common.c into a new libnetdata module under src/libnetdata/runtime-paths/. libnetdata owns the storage; the daemon's config layer still writes the values through the extern declarations (now declared once, in libnetdata.h instead of split between libnetdata.h and daemon/common.h). required_dummies.h drops its fallback definitions for these symbols (and for the cleanup functions retired by the sibling commit). The header is kept as a no-op so the ~12 plugins that * libnetdata: remove required_dummies.h The header is no longer needed: libnetdata provides every symbol its consumers used to need local dummies for. Remove the file, the 22 #include lines in plugins / utilities / tests, the entry in CMakeLists.txt, and the stray include in tests/profile/test-eval.c. * libnetdata: move netdata.conf path/hostname loaders into runtime-paths The daemon's two inicfg_get-driven loaders (paths in netdata-conf-directories.c, hostname/host_prefix in netdata-conf-global.c) consisted almost entirely of libnetdata calls operating on libnetdata-owned state. Move them into runtime-paths.c alongside the storage definitions; the daemon wrappers shrink to the orchestration that still needs daemon-specific state (plugin discovery, the FUNCTION_RUN_ONCE guard at each existing entry point). New libnetdata API: void nd_runtime_paths_load_directories_from_inicfg(void); void nd_runtime_paths_load_hostname_from_inicfg(void); Both are idempotent and safe to call multiple times. The daemon's public function names (netdata_conf_section_directories, netdata_conf_section_global_hostname) are unchanged; the 11 existing callers of the former and the 1 caller of the latter need no changes. * libnetdata: initialize cleanup-registry spinlock with SPINLOCK_INITIALIZER Using `{ 0 }` happens to work for the bool-backed spinlock but bypasses the contract on SPINLOCK_IMPL_WITH_MUTEX builds, where the macro expands to `{ .inner = PTHREAD_MUTEX_INITIALIZER }`. * Properly initialize buf. Initialize buf before os_hostname() so the fallback passed to inicfg_get() is always a valid string when hostname lookup fails. Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

vkalintiris committed May 25, 2026 at 11:42 UTC 8fb66be12c3cdc68ee954152c6af6197c01f3f48
36 files changed +182 -103
CMakeLists.txt
+2 -1
@@ -1012,7 +1012,6 @@ set(LIBNETDATA_FILES
1012 src/libnetdata/procfile/procfile.h
1013 src/libnetdata/query_progress/progress.c
1014 src/libnetdata/query_progress/progress.h
1015 - src/libnetdata/required_dummies.h
1015 src/libnetdata/socket/security.c
1016 src/libnetdata/socket/security.h
1017 src/libnetdata/simple_hashtable/simple_hashtable.h
@@ -1232,6 +1231,8 @@ set(LIBNETDATA_FILES
1231 src/libnetdata/os/mmap_limit.h
1232 src/libnetdata/signals/signals.c
1233 src/libnetdata/signals/signals.h
1234 + src/libnetdata/runtime-paths/runtime-paths.c
1235 + src/libnetdata/runtime-paths/runtime-paths.h
1236 src/libnetdata/os/machine_id.c
1237 src/libnetdata/os/machine_id.h
1238 src/libnetdata/os/process_memory.c
src/cli/cli.c
-1
@@ -2,7 +2,6 @@
2
3 #include "daemon/pipename.h"
4 #include "daemon/common.h"
5 -#include "libnetdata/required_dummies.h"
5
6 static uv_pipe_t client_pipe;
7 static uv_write_t write_req;
src/collectors/apps.plugin/apps_plugin.c
-1
@@ -1,7 +1,6 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "apps_plugin.h"
4 -#include "libnetdata/required_dummies.h"
4 #include "libnetdata/parsers/duration.h"
5
6 #define APPS_PLUGIN_FUNCTIONS() do { \
src/collectors/cgroups.plugin/cgroup-network.c
-1
@@ -1,7 +1,6 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "libnetdata/libnetdata.h"
4 -#include "libnetdata/required_dummies.h"
4
5 SPAWN_SERVER *spawn_server = NULL;
6
src/collectors/cgroups.plugin/tests/test_cgroups_plugin.c
-2
@@ -1,11 +1,9 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "test_cgroups_plugin.h"
4 -#include "libnetdata/required_dummies.h"
4
5 RRDHOST *localhost;
6 struct config netdata_config;
8 -char *netdata_configured_primary_plugins_dir = NULL;
7
8 struct k8s_test_data {
9 char *data;
src/collectors/cups.plugin/cups_plugin.c
-1
@@ -1,7 +1,6 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "libnetdata/libnetdata.h"
4 -#include "libnetdata/required_dummies.h"
4
5 #include <cups/cups.h>
6 #include <limits.h>
src/collectors/debugfs.plugin/debugfs_plugin.c
-1
@@ -1,7 +1,6 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "debugfs_plugin.h"
4 -#include "libnetdata/required_dummies.h"
4
5 static char *user_config_dir = CONFIG_DIR;
6 static char *stock_config_dir = LIBCONFIG_DIR;
src/collectors/ebpf.plugin/ebpf.c
-1
@@ -10,7 +10,6 @@
10 #include "ebpf_socket.h"
11 #include "ebpf_unittest.h"
12 #include "libbpf_api/ebpf_library.h"
13 -#include "libnetdata/required_dummies.h"
13 #include "libnetdata/libjudy/judy-malloc.h"
14
15 /*****************************************************************
src/collectors/freeipmi.plugin/freeipmi_plugin.c
-1
@@ -16,7 +16,6 @@
16
17 // #define NETDATA_TIMING_REPORT 1
18 #include "libnetdata/libnetdata.h"
19 -#include "libnetdata/required_dummies.h"
19
20 #define FREEIPMI_GLOBAL_FUNCTION_SENSORS() do { \
21 fprintf(stdout, PLUGINSD_KEYWORD_FUNCTION " GLOBAL \"ipmi-sensors\" %d \"%s\" \"top\" "HTTP_ACCESS_FORMAT" %d\n", \
src/collectors/log2journal/log2journal.c
-1
@@ -1,7 +1,6 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "log2journal.h"
4 -#include "libnetdata/required_dummies.h"
4
5 // ----------------------------------------------------------------------------
6
src/collectors/network-viewer.plugin/network-viewer.c
-1
@@ -3,7 +3,6 @@
3 #include "collectors/all.h"
4 #include "libnetdata/libnetdata.h"
5
6 -#include "libnetdata/required_dummies.h"
6
7 static SPAWN_SERVER *spawn_srv = NULL;
8
src/collectors/nfacct.plugin/plugin_nfacct.c
-1
@@ -1,7 +1,6 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "libnetdata/libnetdata.h"
4 -#include "libnetdata/required_dummies.h"
4
5 #include <linux/netfilter/nfnetlink_conntrack.h>
6 #include <libmnl/libmnl.h>
src/collectors/perf.plugin/perf_plugin.c
-1
@@ -1,7 +1,6 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "libnetdata/libnetdata.h"
4 -#include "libnetdata/required_dummies.h"
4
5 #include <linux/perf_event.h>
6
src/collectors/slabinfo.plugin/slabinfo.c
-1
@@ -1,7 +1,6 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "database/rrd.h"
4 -#include "libnetdata/required_dummies.h"
4
5 #define PLUGIN_SLABINFO_NAME "slabinfo.plugin"
6 #define PLUGIN_SLABINFO_PROCFILE "/proc/slabinfo"
src/collectors/systemd-journal.plugin/systemd-main.c
-1
@@ -1,7 +1,6 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "systemd-internals.h"
4 -#include "libnetdata/required_dummies.h"
4
5 #define ND_SD_JOURNAL_WORKER_THREADS 5
6
src/collectors/systemd-units.plugin/plugin_systemd_units.c
-1
@@ -2,7 +2,6 @@
2
3 #include "collectors/all.h"
4 #include "libnetdata/libnetdata.h"
5 -#include "libnetdata/required_dummies.h"
5
6 #include <linux/capability.h>
7 #include <syslog.h>
src/collectors/utils/local_listeners.c
-1
@@ -2,7 +2,6 @@
2
3 #include "libnetdata/libnetdata.h"
4 #include "libnetdata/local-sockets/local-sockets.h"
5 -#include "libnetdata/required_dummies.h"
5
6 // --------------------------------------------------------------------------------------------------------------------
7
src/collectors/windows-events.plugin/windows-events.c
-1
@@ -1,7 +1,6 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "libnetdata/libnetdata.h"
4 -#include "libnetdata/required_dummies.h"
4
5 #include "windows-events.h"
6
src/collectors/xenstat.plugin/xenstat_plugin.c
-1
@@ -1,7 +1,6 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "libnetdata/libnetdata.h"
4 -#include "libnetdata/required_dummies.h"
4
5 #include <xenstat.h>
6 #include <libxl.h>
src/daemon/common.c
-13
@@ -2,19 +2,6 @@
2
3 #include "common.h"
4
5 -const char *netdata_configured_hostname = NULL;
6 -const char *netdata_configured_user_config_dir = CONFIG_DIR;
7 -const char *netdata_configured_stock_config_dir = LIBCONFIG_DIR;
8 -const char *netdata_configured_stock_data_dir = STOCK_DATA_DIR;
9 -const char *netdata_configured_log_dir = LOG_DIR;
10 -const char *netdata_configured_primary_plugins_dir = PLUGINS_DIR;
11 -const char *netdata_configured_web_dir = WEB_DIR;
12 -const char *netdata_configured_cache_dir = CACHE_DIR;
13 -const char *netdata_configured_varlib_dir = VARLIB_DIR;
14 -const char *netdata_configured_cloud_dir = VARLIB_DIR "/cloud.d";
15 -const char *netdata_configured_home_dir = VARLIB_DIR;
16 -const char *netdata_configured_host_prefix = NULL;
17 -
5 bool netdata_ready = false;
6
7 // ============================================================================
src/daemon/common.h
-12
@@ -71,18 +71,6 @@ extern "C" {
71 #include "analytics.h"
72
73 // global netdata daemon variables
74 -extern const char *netdata_configured_hostname;
75 -extern const char *netdata_configured_user_config_dir;
76 -extern const char *netdata_configured_stock_config_dir;
77 -extern const char *netdata_configured_stock_data_dir;
78 -extern const char *netdata_configured_log_dir;
79 -extern const char *netdata_configured_primary_plugins_dir;
80 -extern const char *netdata_configured_web_dir;
81 -extern const char *netdata_configured_cache_dir;
82 -extern const char *netdata_configured_varlib_dir;
83 -extern const char *netdata_configured_cloud_dir;
84 -extern const char *netdata_configured_home_dir;
85 -extern const char *netdata_configured_host_prefix;
74 extern bool netdata_anonymous_statistics_enabled;
75
76 // Thread-safe system timezone access.
src/daemon/config/netdata-conf-directories.c
+1 -18
@@ -3,27 +3,10 @@
3 #include "netdata-conf-directories.h"
4 #include "daemon/common.h"
5
6 -static const char *get_varlib_subdir_from_config(const char *prefix, const char *dir) {
7 - char filename[FILENAME_MAX + 1];
8 - snprintfz(filename, FILENAME_MAX, "%s/%s", prefix, dir);
9 - return inicfg_get_path(&netdata_config, CONFIG_SECTION_DIRECTORIES, dir, filename);
10 -}
11 -
6 void netdata_conf_section_directories(void) {
7 FUNCTION_RUN_ONCE();
8
15 - // ------------------------------------------------------------------------
16 - // get system paths
17 -
18 - netdata_configured_user_config_dir = inicfg_get_path(&netdata_config, CONFIG_SECTION_DIRECTORIES, "config", netdata_configured_user_config_dir);
19 - netdata_configured_stock_config_dir = inicfg_get_path(&netdata_config, CONFIG_SECTION_DIRECTORIES, "stock config", netdata_configured_stock_config_dir);
20 - netdata_configured_stock_data_dir = inicfg_get_path(&netdata_config, CONFIG_SECTION_DIRECTORIES, "stock data", netdata_configured_stock_data_dir);
21 - netdata_configured_log_dir = inicfg_get_path(&netdata_config, CONFIG_SECTION_DIRECTORIES, "log", netdata_configured_log_dir);
22 - netdata_configured_web_dir = inicfg_get_path(&netdata_config, CONFIG_SECTION_DIRECTORIES, "web", netdata_configured_web_dir);
23 - netdata_configured_cache_dir = inicfg_get_path(&netdata_config, CONFIG_SECTION_DIRECTORIES, "cache", netdata_configured_cache_dir);
24 - netdata_configured_varlib_dir = inicfg_get_path(&netdata_config, CONFIG_SECTION_DIRECTORIES, "lib", netdata_configured_varlib_dir);
25 -
26 - netdata_configured_cloud_dir = get_varlib_subdir_from_config(netdata_configured_varlib_dir, "cloud.d");
9 + nd_runtime_paths_load_directories_from_inicfg();
10
11 pluginsd_initialize_plugin_directories();
12 netdata_configured_primary_plugins_dir = plugin_directories[PLUGINSD_STOCK_PLUGINS_DIRECTORY_PATH];
src/daemon/config/netdata-conf-global.c
+1 -9
@@ -136,15 +136,7 @@ void libuv_initialize(void) {
136 void netdata_conf_section_global_hostname(void) {
137 FUNCTION_RUN_ONCE();
138
139 - netdata_configured_host_prefix = inicfg_get(&netdata_config, CONFIG_SECTION_GLOBAL, "host access prefix", "");
140 - (void) verify_netdata_host_prefix(true);
141 -
142 - char buf[HOST_NAME_MAX * 4 + 1];
143 - if (!os_hostname(buf, sizeof(buf), netdata_configured_host_prefix))
144 - netdata_log_error("Cannot get machine hostname.");
145 -
146 - netdata_configured_hostname = inicfg_get(&netdata_config, CONFIG_SECTION_GLOBAL, "hostname", buf);
147 - netdata_log_debug(D_OPTIONS, "hostname set to '%s'", netdata_configured_hostname);
139 + nd_runtime_paths_load_hostname_from_inicfg();
140 }
141
142 void netdata_conf_section_global(void) {
src/daemon/main.c
+7
@@ -264,6 +264,13 @@ int netdata_main(int argc, char **argv) {
264 analytics_init();
265 nd_log_initialize_mutexes();
266
267 + // Register the daemon's per-thread cleanup callback. Each subsystem
268 + // should own the registration of its own cleanups; this one lives in
269 + // the daemon because service_exits is a daemon-layer concern. The
270 + // rest are currently registered together in rrd_init() and should be
271 + // moved to their respective subsystems in a follow-up.
272 + nd_thread_register_cleanup(service_exits);
273 +
274 netdata_start_time = now_realtime_sec();
275 usec_t started_ut = now_monotonic_usec();
276 usec_t last_ut = started_ut;
src/database/rrd.c
+12
@@ -70,7 +70,19 @@ inline long align_entries_to_pagesize(RRD_DB_MODE mode, long entries) {
70
71 void api_v1_management_init(void);
72
73 +// Thread-exit cleanup callbacks. Registered with libnetdata below;
74 +// called once per thread at exit time, in registration order. All
75 +// callbacks except rrdset_thread_rda_free are declared in their
76 +// owning headers (included via rrd.h); rrdset_thread_rda_free has no
77 +// public header so it is declared locally here.
78 +void rrdset_thread_rda_free(void);
79 +
80 int rrd_init(const char *hostname, struct rrdhost_system_info *system_info, bool unittest) {
81 + nd_thread_register_cleanup(rrd_collector_finished);
82 + nd_thread_register_cleanup(sender_thread_buffer_free);
83 + nd_thread_register_cleanup(rrdset_thread_rda_free);
84 + nd_thread_register_cleanup(query_target_free);
85 +
86 rrdhost_init();
87
88 if (unlikely(sql_init_meta_database(DB_CHECK_NONE, system_info ? 0 : 1))) {
src/libnetdata/libnetdata.h
+1 -1
@@ -55,7 +55,7 @@ char *find_and_replace(const char *src, const char *find, const char *replace, c
55 bool run_command_and_copy_output_to_stdout(const char *command, int max_line_length);
56 struct web_buffer *run_command_and_get_output_to_buffer(const char *command, int max_line_length);
57
58 -extern const char *netdata_configured_host_prefix;
58 +#include "runtime-paths/runtime-paths.h"
59
60 // safe includes before O/S specific functions
61 #include "template-enum.h"
src/libnetdata/log/systemd-cat-native.c
-1
@@ -1,7 +1,6 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "systemd-cat-native.h"
4 -#include "../required_dummies.h"
4
5 #ifdef __FreeBSD__
6 #include <sys/endian.h>
src/libnetdata/required_dummies.h deleted
-15
@@ -1,15 +0,0 @@
1 -// SPDX-License-Identifier: GPL-3.0-or-later
2 -
3 -#ifndef NETDATA_LIB_DUMMIES_H
4 -#define NETDATA_LIB_DUMMIES_H 1
5 -
6 -void rrdset_thread_rda_free(void){}
7 -void sender_thread_buffer_free(void){}
8 -void query_target_free(void){}
9 -void service_exits(void){}
10 -void rrd_collector_finished(void){}
11 -
12 -// required by get_system_cpus()
13 -const char *netdata_configured_host_prefix = "";
14 -
15 -#endif // NETDATA_LIB_DUMMIES_H
src/libnetdata/runtime-paths/runtime-paths.c new
+56
@@ -0,0 +1,56 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +//
3 +// Storage and netdata.conf loaders for the netdata_configured_*
4 +// globals. Compile-time defaults come from build/config.h via the
5 +// libnetdata.h chain.
6 +
7 +#include "../libnetdata.h"
8 +
9 +const char *netdata_configured_hostname = NULL;
10 +const char *netdata_configured_user_config_dir = CONFIG_DIR;
11 +const char *netdata_configured_stock_config_dir = LIBCONFIG_DIR;
12 +const char *netdata_configured_stock_data_dir = STOCK_DATA_DIR;
13 +const char *netdata_configured_log_dir = LOG_DIR;
14 +const char *netdata_configured_primary_plugins_dir = PLUGINS_DIR;
15 +const char *netdata_configured_web_dir = WEB_DIR;
16 +const char *netdata_configured_cache_dir = CACHE_DIR;
17 +const char *netdata_configured_varlib_dir = VARLIB_DIR;
18 +const char *netdata_configured_cloud_dir = VARLIB_DIR "/cloud.d";
19 +const char *netdata_configured_home_dir = VARLIB_DIR;
20 +const char *netdata_configured_host_prefix = NULL;
21 +
22 +// ----------------------------------------------------------------------------
23 +// netdata.conf loaders
24 +
25 +static const char *get_varlib_subdir_from_config(const char *prefix, const char *dir) {
26 + char filename[FILENAME_MAX + 1];
27 + snprintfz(filename, FILENAME_MAX, "%s/%s", prefix, dir);
28 + return inicfg_get_path(&netdata_config, CONFIG_SECTION_DIRECTORIES, dir, filename);
29 +}
30 +
31 +void nd_runtime_paths_load_directories_from_inicfg(void) {
32 + FUNCTION_RUN_ONCE();
33 +
34 + netdata_configured_user_config_dir = inicfg_get_path(&netdata_config, CONFIG_SECTION_DIRECTORIES, "config", netdata_configured_user_config_dir);
35 + netdata_configured_stock_config_dir = inicfg_get_path(&netdata_config, CONFIG_SECTION_DIRECTORIES, "stock config", netdata_configured_stock_config_dir);
36 + netdata_configured_stock_data_dir = inicfg_get_path(&netdata_config, CONFIG_SECTION_DIRECTORIES, "stock data", netdata_configured_stock_data_dir);
37 + netdata_configured_log_dir = inicfg_get_path(&netdata_config, CONFIG_SECTION_DIRECTORIES, "log", netdata_configured_log_dir);
38 + netdata_configured_web_dir = inicfg_get_path(&netdata_config, CONFIG_SECTION_DIRECTORIES, "web", netdata_configured_web_dir);
39 + netdata_configured_cache_dir = inicfg_get_path(&netdata_config, CONFIG_SECTION_DIRECTORIES, "cache", netdata_configured_cache_dir);
40 + netdata_configured_varlib_dir = inicfg_get_path(&netdata_config, CONFIG_SECTION_DIRECTORIES, "lib", netdata_configured_varlib_dir);
41 + netdata_configured_cloud_dir = get_varlib_subdir_from_config(netdata_configured_varlib_dir, "cloud.d");
42 +}
43 +
44 +void nd_runtime_paths_load_hostname_from_inicfg(void) {
45 + FUNCTION_RUN_ONCE();
46 +
47 + netdata_configured_host_prefix = inicfg_get(&netdata_config, CONFIG_SECTION_GLOBAL, "host access prefix", "");
48 + (void) verify_netdata_host_prefix(true);
49 +
50 + char buf[HOST_NAME_MAX * 4 + 1] = "";
51 + if (!os_hostname(buf, sizeof(buf), netdata_configured_host_prefix))
52 + netdata_log_error("Cannot get machine hostname.");
53 +
54 + netdata_configured_hostname = inicfg_get(&netdata_config, CONFIG_SECTION_GLOBAL, "hostname", buf);
55 + netdata_log_debug(D_OPTIONS, "hostname set to '%s'", netdata_configured_hostname);
56 +}
src/libnetdata/runtime-paths/runtime-paths.h new
+39
@@ -0,0 +1,39 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +//
3 +// Process-wide configuration values resolved at netdata startup.
4 +//
5 +// libnetdata owns these globals. They start at compile-time defaults
6 +// (from build/config.h) and are re-resolved against netdata_config by
7 +// nd_runtime_paths_load_directories_from_inicfg() and
8 +// nd_runtime_paths_load_hostname_from_inicfg(), which the daemon
9 +// startup path invokes once after the config is loaded. Callers must
10 +// not assign to these variables directly; use the loaders declared
11 +// below.
12 +
13 +#ifndef NETDATA_RUNTIME_PATHS_H
14 +#define NETDATA_RUNTIME_PATHS_H
15 +
16 +extern const char *netdata_configured_hostname;
17 +extern const char *netdata_configured_user_config_dir;
18 +extern const char *netdata_configured_stock_config_dir;
19 +extern const char *netdata_configured_stock_data_dir;
20 +extern const char *netdata_configured_log_dir;
21 +extern const char *netdata_configured_primary_plugins_dir;
22 +extern const char *netdata_configured_web_dir;
23 +extern const char *netdata_configured_cache_dir;
24 +extern const char *netdata_configured_varlib_dir;
25 +extern const char *netdata_configured_cloud_dir;
26 +extern const char *netdata_configured_home_dir;
27 +extern const char *netdata_configured_host_prefix;
28 +
29 +// Re-resolve the directory globals from the loaded netdata_config.
30 +// Values absent from the config keep their compile-time defaults.
31 +// Idempotent.
32 +void nd_runtime_paths_load_directories_from_inicfg(void);
33 +
34 +// Re-resolve host_prefix and hostname from netdata_config.
35 +// host_prefix is loaded first because os_hostname uses it.
36 +// Idempotent.
37 +void nd_runtime_paths_load_hostname_from_inicfg(void);
38 +
39 +#endif // NETDATA_RUNTIME_PATHS_H
src/libnetdata/spawn_server/spawn-tester.c
-1
@@ -1,5 +1,4 @@
1 #include "libnetdata/libnetdata.h"
2 -#include "libnetdata/required_dummies.h"
2
3 #define ENV_VAR_KEY "SPAWN_TESTER"
4 #define ENV_VAR_VALUE "1234567890"
src/libnetdata/storage_number/tests/test_storage_number.c
-1
@@ -1,7 +1,6 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "../../libnetdata.h"
4 -#include "../../required_dummies.h"
4 #include <setjmp.h>
5 #include <cmocka.h>
6
src/libnetdata/tests/test_str2ld.c
-1
@@ -1,7 +1,6 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "../libnetdata.h"
4 -#include "../required_dummies.h"
4 #include <setjmp.h>
5 #include <cmocka.h>
6
src/libnetdata/threads/threads.c
+54 -10
@@ -254,12 +254,60 @@ void netdata_threads_init_for_external_plugins(size_t stacksize) {
254 }
255
256 // ----------------------------------------------------------------------------
257 +// Thread-cleanup callback registry.
258 +//
259 +// Registration is startup-only — callers register before any daemon
260 +// thread is created. libnetdata calls every registered callback at
261 +// thread-exit time, in registration order. The startup-only invariant
262 +// lets nd_thread_run_cleanup_callbacks read the count without holding
263 +// the spinlock; the __ATOMIC_RELEASE/_ACQUIRE pair handles any late
264 +// edge.
265 +//
266 +// Ordering: all registered callbacks run before thread_cache_destroy
267 +// and worker_unregister (called below). A callback that needs to
268 +// observe thread_cache state must do so before that destroy.
269 +
270 +#define ND_THREAD_CLEANUP_MAX 16
271 +static struct {
272 + SPINLOCK spinlock;
273 + size_t count;
274 + nd_thread_cleanup_fn fns[ND_THREAD_CLEANUP_MAX];
275 +} nd_thread_cleanup_registry = { .spinlock = SPINLOCK_INITIALIZER };
276 +
277 +void nd_thread_register_cleanup(nd_thread_cleanup_fn fn) {
278 + if(!fn) return;
279 +
280 + spinlock_lock(&nd_thread_cleanup_registry.spinlock);
281 +
282 + // Idempotent: skip if this fn is already registered. Keeps the
283 + // registry small under repeated rrd_init / unittest re-entry.
284 + for(size_t i = 0; i < nd_thread_cleanup_registry.count; i++) {
285 + if(nd_thread_cleanup_registry.fns[i] == fn) {
286 + spinlock_unlock(&nd_thread_cleanup_registry.spinlock);
287 + return;
288 + }
289 + }
290 +
291 + if(nd_thread_cleanup_registry.count >= ND_THREAD_CLEANUP_MAX) {
292 + spinlock_unlock(&nd_thread_cleanup_registry.spinlock);
293 + fatal("nd_thread_register_cleanup: registry full (max %d)", ND_THREAD_CLEANUP_MAX);
294 + }
295 + nd_thread_cleanup_registry.fns[nd_thread_cleanup_registry.count] = fn;
296 + __atomic_store_n(&nd_thread_cleanup_registry.count,
297 + nd_thread_cleanup_registry.count + 1,
298 + __ATOMIC_RELEASE);
299 + spinlock_unlock(&nd_thread_cleanup_registry.spinlock);
300 +}
301
258 -void rrdset_thread_rda_free(void);
259 -void sender_thread_buffer_free(void);
260 -void query_target_free(void);
261 -void service_exits(void);
262 -void rrd_collector_finished(void);
302 +static void nd_thread_run_cleanup_callbacks(void) {
303 + size_t count = __atomic_load_n(&nd_thread_cleanup_registry.count, __ATOMIC_ACQUIRE);
304 + for(size_t i = 0; i < count; i++) {
305 + nd_thread_cleanup_fn fn = nd_thread_cleanup_registry.fns[i];
306 + if(fn) fn();
307 + }
308 +}
309 +
310 +// ----------------------------------------------------------------------------
311
312 void nd_thread_join_threads()
313 {
@@ -323,12 +371,8 @@ static void nd_thread_exit(ND_THREAD *nti) {
371 if(nd_thread_status_check(nti, NETDATA_THREAD_OPTION_DONT_LOG_CLEANUP) != NETDATA_THREAD_OPTION_DONT_LOG_CLEANUP)
372 nd_log(NDLS_DAEMON, NDLP_DEBUG, "thread with task id %d finished", nti->tid);
373
326 - rrd_collector_finished();
327 - sender_thread_buffer_free();
328 - rrdset_thread_rda_free();
329 - query_target_free();
374 + nd_thread_run_cleanup_callbacks();
375 thread_cache_destroy();
331 - service_exits();
376 worker_unregister();
377
378 nd_thread_status_set(nti, NETDATA_THREAD_STATUS_FINISHED);
src/libnetdata/threads/threads.h
+9
@@ -82,6 +82,15 @@ void nd_thread_register_canceller(nd_thread_canceller cb, void *data);
82 void nd_thread_signal_cancel(ND_THREAD *nti);
83 bool nd_thread_signaled_to_cancel(void);
84
85 +// Register a process-wide cleanup callback that runs once per thread
86 +// at thread-exit time. Callbacks run in registration order, after the
87 +// libnetdata-internal lock-leak assertions and before
88 +// thread_cache_destroy / worker_unregister. Registration is intended
89 +// to be done once at process startup; the registry has a small fixed
90 +// capacity.
91 +typedef void (*nd_thread_cleanup_fn)(void);
92 +void nd_thread_register_cleanup(nd_thread_cleanup_fn fn);
93 +
94 #define ND_THREAD_TAG_MAX 15
95 void uv_thread_set_name_np(const char* name);
96 void webrtc_set_thread_name(void);
tests/profile/test-eval.c
-1
@@ -9,7 +9,6 @@
9
10 #include "config.h"
11 #include "libnetdata/libnetdata.h"
12 -#include "libnetdata/required_dummies.h"
12 #include "health/rrdcalc.h"
13
14 /*