@cryptotaxi247 / netdata-1 / commits / 0194a2a26

fix cleanup and exit and memory leaks (#20120)

Costa Tsaousis committed Apr 14, 2025 at 23:22 UTC 0194a2a2659cfcc78bb620128ade65501c2e87a7
18 files changed +154 -88
src/collectors/diskspace.plugin/plugin_diskspace.c
+22 -15
@@ -95,6 +95,10 @@ void mountpoint_delete_cb(const DICTIONARY_ITEM *item __maybe_unused, void *entr
95 string_freez(mp->mountroot);
96 mp->mountroot = NULL;
97
98 + // Free the labels if they exist
99 + rrdlabels_destroy(mp->chart_labels);
100 + mp->chart_labels = NULL;
101 +
102 rrdset_obsolete_and_pointer_null(mp->st_space);
103 rrdset_obsolete_and_pointer_null(mp->st_inodes);
104
@@ -512,13 +516,6 @@ cleanup:
516 dictionary_acquired_item_release(dict_mountpoints, item);
517 }
518
515 -static void diskspace_slow_worker_cleanup(void *pptr) {
516 - struct slow_worker_data *data = CLEANUP_FUNCTION_GET_PTR(pptr);
517 - if(data) return;
518 -
519 - worker_unregister();
520 -}
521 -
519 #define WORKER_JOB_SLOW_MOUNTPOINT 0
520 #define WORKER_JOB_SLOW_CLEANUP 1
521
@@ -529,7 +526,6 @@ struct slow_worker_data {
526 void *diskspace_slow_worker(void *ptr)
527 {
528 struct slow_worker_data *data = (struct slow_worker_data *)ptr;
532 - CLEANUP_FUNCTION_REGISTER(diskspace_slow_worker_cleanup) cleanup_ptr = data;
529
530 worker_register("DISKSPACE_SLOW");
531 worker_register_job_name(WORKER_JOB_SLOW_MOUNTPOINT, "mountpoint");
@@ -595,20 +591,22 @@ void *diskspace_slow_worker(void *ptr)
591 }
592 }
593
594 + // cleanup
595 + netdata_mutex_lock(&slow_mountinfo_mutex);
596 free_basic_mountinfo_list(slow_mountinfo_root);
597 + netdata_mutex_unlock(&slow_mountinfo_mutex);
598 +
599 + worker_unregister();
600
601 return NULL;
602 }
603
603 -static void diskspace_main_cleanup(void *pptr) {
604 - struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
604 +static void diskspace_main_cleanup(void *ptr) {
605 + struct netdata_static_thread *static_thread = ptr;
606 if(!static_thread) return;
607
608 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
609
609 - rrd_collector_finished();
610 - worker_unregister();
611 -
610 if (diskspace_slow_thread)
611 nd_thread_join(diskspace_slow_thread);
612
@@ -616,6 +614,13 @@ static void diskspace_main_cleanup(void *pptr) {
614 free_basic_mountinfo_list(slow_mountinfo_tmp_root);
615 netdata_mutex_unlock(&slow_mountinfo_mutex);
616
617 + // Free the mountpoints dictionary
618 + dictionary_destroy(dict_mountpoints);
619 + dict_mountpoints = NULL;
620 +
621 + rrd_collector_finished();
622 + worker_unregister();
623 +
624 static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
625 }
626
@@ -839,8 +844,6 @@ static int diskspace_function_mount_points(BUFFER *wb, const char *function __ma
844 }
845
846 void *diskspace_main(void *ptr) {
842 - CLEANUP_FUNCTION_REGISTER(diskspace_main_cleanup) cleanup_ptr = ptr;
843 -
847 worker_register("DISKSPACE");
848 worker_register_job_name(WORKER_JOB_MOUNTINFO, "mountinfo");
849 worker_register_job_name(WORKER_JOB_MOUNTPOINT, "mountpoint");
@@ -918,5 +921,9 @@ void *diskspace_main(void *ptr) {
921 mount_points_cleanup(false);
922 }
923 }
924 +
925 + // cleanup
926 + diskspace_main_cleanup(ptr);
927 +
928 return NULL;
929 }
src/collectors/proc.plugin/plugin_proc.c
+1 -1
@@ -37,7 +37,7 @@ static struct proc_module {
37 {.name = "/sys/kernel/mm/ksm", .dim = "ksm", .func = do_sys_kernel_mm_ksm},
38 {.name = "/sys/block/zram", .dim = "zram", .func = do_sys_block_zram},
39 {.name = "/sys/devices/system/edac/mc", .dim = "edac", .func = do_proc_sys_devices_system_edac_mc},
40 - {.name = "/sys/devices/pci/aer", .dim = "pci_aer", .func = do_proc_sys_devices_pci_aer},
40 + {.name = "/sys/devices/pci/aer", .dim = "pci_aer", .func = do_proc_sys_devices_pci_aer, .cleanup = pci_aer_plugin_cleanup},
41 {.name = "/sys/devices/system/node", .dim = "numa", .func = do_proc_sys_devices_system_node},
42 {.name = "/proc/pagetypeinfo", .dim = "pagetypeinfo", .func = do_proc_pagetypeinfo},
43
src/collectors/proc.plugin/plugin_proc.h
+1
@@ -57,6 +57,7 @@ void proc_stat_plugin_cleanup(void);
57 void proc_net_sockstat_plugin_cleanup(void);
58 void proc_loadavg_plugin_cleanup(void);
59 void sys_class_infiniband_plugin_cleanup(void);
60 +void pci_aer_plugin_cleanup(void);
61
62 // metrics that need to be shared among data collectors
63 extern unsigned long long zfs_arcstats_shrinkable_cache_size_bytes;
src/collectors/proc.plugin/sys_devices_pci_aer.c
+16
@@ -40,6 +40,13 @@ static bool aer_value_conflict_callback(const DICTIONARY_ITEM *item __maybe_unus
40 return false;
41 }
42
43 +static void aer_entry_free_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
44 + struct aer_entry *a = value;
45 + dictionary_destroy(a->values);
46 + string_freez(a->name);
47 + procfile_close(a->ff);
48 +}
49 +
50 static void aer_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
51 struct aer_entry *a = value;
52 a->values = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE|DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(struct aer_value));
@@ -190,6 +197,14 @@ static void add_label_from_link(struct aer_entry *a, const char *path, const cha
197 }
198 }
199
200 +// Cleanup function for the PCI AER module
201 +void pci_aer_plugin_cleanup(void) {
202 + if(aer_root) {
203 + dictionary_destroy(aer_root);
204 + aer_root = NULL;
205 + }
206 +}
207 +
208 int do_proc_sys_devices_pci_aer(int update_every, usec_t dt __maybe_unused) {
209 if(unlikely(!aer_root)) {
210 int do_root_ports = CONFIG_BOOLEAN_AUTO;
@@ -211,6 +226,7 @@ int do_proc_sys_devices_pci_aer(int update_every, usec_t dt __maybe_unused) {
226
227 aer_root = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(struct aer_entry));
228 dictionary_register_insert_callback(aer_root, aer_insert_callback, NULL);
229 + dictionary_register_delete_callback(aer_root, aer_entry_free_callback, NULL);
230
231 AER_TYPE types = ((do_root_ports) ? (AER_ROOTPORT_TOTAL_ERR_COR|AER_ROOTPORT_TOTAL_ERR_FATAL) : 0) |
232 ((do_pci_slots) ? (AER_DEV_FATAL|AER_DEV_NONFATAL|AER_DEV_CORRECTABLE) : 0);
src/collectors/statsd.plugin/statsd.c
+10
@@ -2425,6 +2425,16 @@ static void statsd_main_cleanup(void *pptr) {
2425 dictionary_destroy(statsd.sets.dict);
2426 dictionary_destroy(statsd.timers.dict);
2427
2428 + // Clean up app dictionaries
2429 + STATSD_APP *app = statsd.apps;
2430 + while(app) {
2431 + if(app->dict) {
2432 + dictionary_destroy(app->dict);
2433 + app->dict = NULL;
2434 + }
2435 + app = app->next;
2436 + }
2437 +
2438 collector_info("STATSD: cleanup completed.");
2439 static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
2440
src/daemon/daemon-shutdown.c
+8 -4
@@ -21,6 +21,7 @@ extern void inicfg_free(struct config *root);
21 extern void claim_config_free(void);
22 extern void stream_config_free(void);
23 extern void exporting_config_free(void);
24 +extern void rrd_functions_inflight_destroy(void);
25
26 static bool abort_on_fatal = true;
27
@@ -219,7 +220,7 @@ static void netdata_cleanup_and_exit(EXIT_REASON reason, bool abnormal, bool exi
220 ABILITY_STREAMING_CONNECTIONS | SERVICE_SYSTEMD);
221 watcher_step_complete(WATCHER_STEP_ID_DISABLE_MAINTENANCE_NEW_QUERIES_NEW_WEB_REQUESTS_NEW_STREAMING_CONNECTIONS);
222
222 - service_wait_exit(SERVICE_MAINTENANCE | SERVICE_SYSTEMD, 3 * USEC_PER_SEC);
223 + service_wait_exit(SERVICE_MAINTENANCE | SERVICE_SYSTEMD, 5 * USEC_PER_SEC);
224 watcher_step_complete(WATCHER_STEP_ID_STOP_MAINTENANCE_THREAD);
225
226 service_wait_exit(SERVICE_EXPORTERS | SERVICE_HEALTH | SERVICE_WEB_SERVER | SERVICE_HTTPD, 3 * USEC_PER_SEC);
@@ -236,14 +237,14 @@ static void netdata_cleanup_and_exit(EXIT_REASON reason, bool abnormal, bool exi
237 rrdeng_flush_everything_and_wait(false, false, true);
238 #endif
239
239 - service_wait_exit(SERVICE_REPLICATION, 3 * USEC_PER_SEC);
240 + service_wait_exit(SERVICE_REPLICATION, 5 * USEC_PER_SEC);
241 watcher_step_complete(WATCHER_STEP_ID_STOP_REPLICATION_THREADS);
242
243 ml_stop_threads();
244 ml_fini();
245 watcher_step_complete(WATCHER_STEP_ID_DISABLE_ML_DETEC_AND_TRAIN_THREADS);
246
246 - service_wait_exit(SERVICE_CONTEXT, 3 * USEC_PER_SEC);
247 + service_wait_exit(SERVICE_CONTEXT, 5 * USEC_PER_SEC);
248 watcher_step_complete(WATCHER_STEP_ID_STOP_CONTEXT_THREAD);
249
250 web_client_cache_destroy();
@@ -257,7 +258,7 @@ static void netdata_cleanup_and_exit(EXIT_REASON reason, bool abnormal, bool exi
258 service_wait_exit(SERVICE_ACLK, 3 * USEC_PER_SEC);
259 watcher_step_complete(WATCHER_STEP_ID_STOP_ACLK_MQTT_THREAD);
260
260 - service_wait_exit(~0, 10 * USEC_PER_SEC);
261 + service_wait_exit(~0, 20 * USEC_PER_SEC);
262 watcher_step_complete(WATCHER_STEP_ID_STOP_ALL_REMAINING_WORKER_THREADS);
263
264 cancel_main_threads();
@@ -345,6 +346,9 @@ static void netdata_cleanup_and_exit(EXIT_REASON reason, bool abnormal, bool exi
346
347 fprintf(stderr, "Freeing all RRDHOSTs...\n");
348 rrdhost_free_all();
349 + dyncfg_shutdown();
350 + rrd_functions_inflight_destroy();
351 + health_plugin_destroy();
352
353 fprintf(stderr, "Cleaning up destroyed dictionaries...\n");
354 size_t dictionaries_referenced = cleanup_destroyed_dictionaries();
src/daemon/dyncfg/dyncfg-inline.c
+8
@@ -64,3 +64,11 @@ void dyncfg_init(bool load_saved) {
64 dyncfg_nodes = dyncfg_nodes_dictionary_create();
65 dyncfg_init_low_level(load_saved);
66 }
67 +
68 +void dyncfg_shutdown(void) {
69 + if(dyncfg_nodes) {
70 + dictionary_destroy(dyncfg_nodes);
71 + dyncfg_nodes = NULL;
72 + }
73 + dyncfg_shutdown_low_level();
74 +}
src/daemon/dyncfg/dyncfg.c
+10
@@ -182,6 +182,16 @@ void dyncfg_init_low_level(bool load_saved) {
182 }
183 }
184
185 +void dyncfg_shutdown_low_level(void) {
186 + if(dyncfg_globals.nodes) {
187 + dictionary_destroy(dyncfg_globals.nodes);
188 + dyncfg_globals.nodes = NULL;
189 + }
190 +
191 + freez((void *)dyncfg_globals.dir);
192 + dyncfg_globals.dir = NULL;
193 +}
194 +
195 // ----------------------------------------------------------------------------
196
197 const DICTIONARY_ITEM *dyncfg_add_internal(RRDHOST *host, const char *id, const char *path,
src/daemon/dyncfg/dyncfg.h
+2
@@ -22,6 +22,7 @@ bool dyncfg_add_low_level(RRDHOST *host, const char *id, const char *path, DYNCF
22 void dyncfg_del_low_level(RRDHOST *host, const char *id);
23 void dyncfg_status_low_level(RRDHOST *host, const char *id, DYNCFG_STATUS status);
24 void dyncfg_init_low_level(bool load_saved);
25 +void dyncfg_shutdown_low_level(void);
26
27 // high-level API for internal modules
28 bool dyncfg_add(RRDHOST *host, const char *id, const char *path, DYNCFG_STATUS status, DYNCFG_TYPE type,
@@ -32,5 +33,6 @@ void dyncfg_del(RRDHOST *host, const char *id);
33 void dyncfg_status(RRDHOST *host, const char *id, DYNCFG_STATUS status);
34
35 void dyncfg_init(bool load_saved);
36 +void dyncfg_shutdown(void);
37
38 #endif //NETDATA_DYNCFG_H
src/database/pattern-array.c
+26 -27
@@ -8,35 +8,35 @@ struct pattern_array *pattern_array_allocate()
8 return pa;
9 }
10
11 -void pattern_array_add_lblkey_with_sp(struct pattern_array *pa, const char *key, SIMPLE_PATTERN *sp)
12 -{
13 - if (!pa || !key || !sp)
11 +void pattern_array_add_lblkey_with_sp(struct pattern_array *pa, const char *key, SIMPLE_PATTERN *sp) {
12 + if (!pa || !key) {
13 + simple_pattern_free(sp);
14 + return;
15 + }
16 +
17 + if(!sp)
18 return;
19
20 STRING *string_key = string_strdupz(key);
21 Pvoid_t *Pvalue = JudyLIns(&pa->JudyL, (Word_t) string_key, PJE0);
18 - if (!Pvalue) {
22 + if (!Pvalue || Pvalue == PJERR) {
23 string_freez(string_key);
24 simple_pattern_free(sp);
25 return;
26 }
27
24 - struct pattern_array_item *pai;
25 - if (*Pvalue) {
26 - pai = *Pvalue;
27 - } else {
28 - *Pvalue = pai = callocz(1, sizeof(*pai));
29 - pa->key_count++;
28 + if(*Pvalue) {
29 + // the string was already there
30 + string_freez(string_key);
31 }
32
32 - pai->size++;
33 - Pvalue = JudyLIns(&pai->JudyL, (Word_t) pai->size, PJE0);
34 - if (!Pvalue) {
33 + Pvoid_t *Pvalue2 = JudyLIns(Pvalue, (Word_t)sp, PJE0);
34 + if (!Pvalue2 || Pvalue2 == PJERR || *Pvalue2 == sp) {
35 simple_pattern_free(sp);
36 return;
37 }
38
39 - *Pvalue = sp;
39 + *Pvalue2 = sp;
40 }
41
42 bool pattern_array_label_match(
@@ -52,17 +52,17 @@ bool pattern_array_label_match(
52 Word_t Index = 0;
53 bool first_then_next = true;
54 while ((Pvalue = JudyLFirstThenNext(pa->JudyL, &Index, &first_then_next))) {
55 - // for each label key in the patterns array
55 + // for each label key in the pattern array
56
57 - struct pattern_array_item *pai = *Pvalue;
58 - SIMPLE_PATTERN_RESULT match = SP_NOT_MATCHED ;
59 - for (Word_t i = 1; i <= pai->size; i++) {
57 + SIMPLE_PATTERN_RESULT match = SP_NOT_MATCHED;
58 + Pvoid_t *Pvalue2;
59 + Word_t Index2 = 0;
60 + bool first_then_next2 = true;
61 + while((Pvalue2 = JudyLFirstThenNext(*Pvalue, &Index2, &first_then_next2))) {
62 // for each pattern in the label key pattern list
63
62 - if (!(Pvalue = JudyLGet(pai->JudyL, i, PJE0)) || !*Pvalue)
63 - continue;
64 -
65 - match = rrdlabels_match_simple_pattern_parsed(labels, (SIMPLE_PATTERN *)(*Pvalue), eq, searches);
64 + SIMPLE_PATTERN *sp = *Pvalue2;
65 + match = rrdlabels_match_simple_pattern_parsed(labels, sp, eq, searches);
66
67 if(match != SP_NOT_MATCHED)
68 break;
@@ -134,18 +134,17 @@ void pattern_array_free(struct pattern_array *pa)
134 Word_t Index = 0;
135 bool first = true;
136 while ((Pvalue = JudyLFirstThenNext(pa->JudyL, &Index, &first))) {
137 - struct pattern_array_item *pai = *Pvalue;
137
138 Word_t Index2 = 0;
139 + Pvoid_t *Pvalue2;
140 bool first2 = true;
141 - while ((Pvalue = JudyLFirstThenNext(pai->JudyL, &Index2, &first2))) {
142 - SIMPLE_PATTERN *sp = (SIMPLE_PATTERN *)*Pvalue;
141 + while ((Pvalue2 = JudyLFirstThenNext(*Pvalue, &Index2, &first2))) {
142 + SIMPLE_PATTERN *sp = (SIMPLE_PATTERN *)*Pvalue2;
143 simple_pattern_free(sp);
144 }
145
146 - JudyLFreeArray(&(pai->JudyL), PJE0);
146 + JudyLFreeArray(Pvalue, PJE0);
147 string_freez((STRING *)Index);
148 - freez(pai);
148 }
149
150 JudyLFreeArray(&(pa->JudyL), PJE0);
src/database/pattern-array.h
-6
@@ -6,13 +6,7 @@
6 #include "libnetdata/libnetdata.h"
7 #include "rrdlabels.h"
8
9 -struct pattern_array_item {
10 - Word_t size;
11 - Pvoid_t JudyL;
12 -};
13 -
9 struct pattern_array {
15 - Word_t key_count;
10 Pvoid_t JudyL;
11 };
12
src/database/rrdhost.c
-3
@@ -781,9 +781,6 @@ void rrdhost_free___while_having_rrd_wrlock(RRDHOST *host) {
781 pulse_host_status(host, PULSE_HOST_STATUS_DELETED, 0);
782 __atomic_sub_fetch(&netdata_buffers_statistics.rrdhost_allocations_size, sizeof(RRDHOST), __ATOMIC_RELAXED);
783
784 - if (host == localhost)
785 - health_plugin_destroy();
786 -
784 freez(host->cache_dir);
785 rrdhost_stream_parents_free(host, false);
786 simple_pattern_free(host->stream.snd.charts_matching);
src/health/health_prototypes.c
+7 -11
@@ -244,20 +244,16 @@ bool health_prototype_conflict_cb(const DICTIONARY_ITEM *item __maybe_unused, vo
244 ap->_internal.is_on_disk = nap->_internal.is_on_disk = true;
245
246 if(!replace) {
247 - if(ap->config.source_type == DYNCFG_SOURCE_TYPE_DYNCFG) {
248 - // the existing is a dyncfg and the new one is read from the config
249 - health_prototype_cleanup(nap);
250 - }
251 - else {
247 + if(ap->config.source_type != DYNCFG_SOURCE_TYPE_DYNCFG) {
248 // alerts with the same name are appended to the existing one
253 - nap = callocz(1, sizeof(*nap));
254 - memcpy(nap, new_value, sizeof(*nap));
249 + RRD_ALERT_PROTOTYPE *alloced = callocz(1, sizeof(*alloced));
250 + SWAP(*alloced, *nap);
251
252 rw_spinlock_write_lock(&ap->_internal.rw_spinlock);
257 - DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(ap->_internal.next, nap, _internal.prev, _internal.next);
253 + DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(ap->_internal.next, alloced, _internal.prev, _internal.next);
254 rw_spinlock_write_unlock(&ap->_internal.rw_spinlock);
255
260 - if(nap->_internal.enabled)
256 + if(alloced->_internal.enabled)
257 ap->_internal.enabled = true;
258 }
259 }
@@ -270,10 +266,10 @@ bool health_prototype_conflict_cb(const DICTIONARY_ITEM *item __maybe_unused, vo
266 SWAP(*ap, *nap);
267 rw_spinlock_write_unlock(&ap->_internal.rw_spinlock);
268 rw_spinlock_write_unlock(&nap->_internal.rw_spinlock);
273 -
274 - health_prototype_cleanup(nap);
269 }
270
271 + health_prototype_cleanup(nap);
272 +
273 return true;
274 }
275
src/health/rrdcalc.c
-2
@@ -310,7 +310,6 @@ static void rrdcalc_rrdhost_insert_callback(const DICTIONARY_ITEM *item __maybe_
310 rc->chart = string_dup(st->id);
311
312 health_prototype_copy_config(&rc->config, &ap->config);
313 - health_prototype_copy_match_without_patterns(&rc->match, &ap->match);
313
314 rc->next_event_id = 1;
315 rc->value = NAN;
@@ -375,7 +374,6 @@ static void rrdcalc_rrdhost_delete_callback(const DICTIONARY_ITEM *item __maybe_
374 // any destruction actions that require other locks
375 // have to be placed in rrdcalc_del(), because the object is actually locked for deletion
376
378 - rrd_alert_match_cleanup(&rc->match);
377 rrd_alert_config_cleanup(&rc->config);
378
379 string_freez(rc->key);
src/health/rrdcalc.h
-1
@@ -49,7 +49,6 @@ struct rrdcalc {
49 STRING *key; // the unique key in the host's rrdcalc_root_index
50 STRING *chart; // the chart id this should be linked to
51
52 - struct rrd_alert_match match;
52 struct rrd_alert_config config;
53
54 // ------------------------------------------------------------------------
src/plugins.d/plugins_d.c
+37 -10
@@ -85,7 +85,7 @@ static void pluginsd_worker_thread_handle_success(struct plugind *cd) {
85
86 static void pluginsd_worker_thread_handle_error(struct plugind *cd, int worker_ret_code) {
87 if (worker_ret_code == -1) {
88 - netdata_log_info("PLUGINSD: 'host:%s', '%s' (pid %d) was killed with SIGTERM. Disabling it.",
88 + netdata_log_info("PLUGINSD: 'host:%s', '%s' (pid %d) exited abnormally. Disabling it.",
89 rrdhost_hostname(cd->host), string2str(cd->fullfilename), cd->unsafe.pid);
90 plugin_set_disabled(cd);
91 return;
@@ -184,7 +184,6 @@ static void *pluginsd_worker_thread(void *arg) {
184 spinlock_lock(&cd->unsafe.spinlock);
185
186 cd->unsafe.running = false;
187 - cd->unsafe.thread = 0;
187 cd->unsafe.pid = 0;
188
189 POPEN_INSTANCE *pi = cd->unsafe.pi;
@@ -206,8 +205,10 @@ static void pluginsd_main_cleanup(void *pptr) {
205 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
206 netdata_log_info("PLUGINSD: cleaning up...");
207
209 - struct plugind *cd;
210 - for (cd = pluginsd_root; cd; cd = cd->next) {
208 + struct plugind *cd = pluginsd_root;
209 + while(cd) {
210 + struct plugind *next = cd->next;
211 +
212 spinlock_lock(&cd->unsafe.spinlock);
213 if (cd->unsafe.enabled && cd->unsafe.running && cd->unsafe.thread != 0) {
214 netdata_log_info("PLUGINSD: 'host:%s', stopping plugin thread: %s",
@@ -215,7 +216,23 @@ static void pluginsd_main_cleanup(void *pptr) {
216
217 nd_thread_signal_cancel(cd->unsafe.thread);
218 }
219 +
220 + DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(pluginsd_root, cd, prev, next);
221 spinlock_unlock(&cd->unsafe.spinlock);
222 +
223 + if(cd->unsafe.thread) {
224 + nd_thread_signal_cancel(cd->unsafe.thread);
225 + nd_thread_join(cd->unsafe.thread);
226 + cd->unsafe.thread = NULL;
227 + }
228 +
229 + string_freez(cd->fullfilename);
230 + string_freez(cd->filename);
231 + string_freez(cd->id);
232 + string_freez(cd->cmd);
233 + freez(cd);
234 +
235 + cd = next;
236 }
237
238 netdata_log_info("PLUGINSD: cleanup completed.");
@@ -313,13 +330,23 @@ void *pluginsd_main(void *ptr) {
330
331 // check if it runs already
332 struct plugind *cd;
316 - for (cd = pluginsd_root; cd; cd = cd->next)
317 - if (unlikely(strcmp(string2str(cd->filename), file->d_name) == 0))
333 + for (cd = pluginsd_root; cd; cd = cd->next) {
334 + if (unlikely(strcmp(string2str(cd->filename), file->d_name) == 0)) {
335 break;
336 + }
337 + }
338
320 - if (likely(cd && plugin_is_running(cd))) {
321 - netdata_log_debug(D_PLUGINSD, "plugin '%s' is already running", string2str(cd->filename));
322 - continue;
339 + if(cd) {
340 + if (likely(plugin_is_running(cd))) {
341 + netdata_log_debug(D_PLUGINSD, "plugin '%s' is already running", string2str(cd->filename));
342 + continue;
343 + }
344 + else if(cd->unsafe.thread) {
345 + netdata_log_debug(D_PLUGINSD, "plugin '%s' gave up", string2str(cd->filename));
346 + nd_thread_signal_cancel(cd->unsafe.thread);
347 + nd_thread_join(cd->unsafe.thread);
348 + cd->unsafe.thread = NULL;
349 + }
350 }
351
352 // it is not running
@@ -372,7 +399,7 @@ void *pluginsd_main(void *ptr) {
399 snprintfz(tag, NETDATA_THREAD_TAG_MAX, "PD[%s]", pluginname);
400
401 // spawn a new thread for it
375 - cd->unsafe.thread = nd_thread_create(tag, NETDATA_THREAD_OPTION_DEFAULT,
402 + cd->unsafe.thread = nd_thread_create(tag, NETDATA_THREAD_OPTION_DEFAULT | NETDATA_THREAD_OPTION_JOINABLE,
403 pluginsd_worker_thread, cd);
404 }
405 }
src/plugins.d/plugins_d.h
-1
@@ -49,7 +49,6 @@ size_t pluginsd_process(struct rrdhost *host, struct plugind *cd, int fd_input,
49
50 struct parser;
51 void pluginsd_process_cleanup(struct parser *parser);
52 -void pluginsd_process_thread_cleanup(void *pptr);
52
53 size_t pluginsd_initialize_plugin_directories();
54
src/plugins.d/pluginsd_parser.c
+6 -7
@@ -1116,13 +1116,10 @@ void pluginsd_process_cleanup(PARSER *parser) {
1116 pluginsd_cleanup_v2(parser);
1117 pluginsd_host_define_cleanup(parser);
1118
1119 - parser_destroy(parser);
1120 -}
1119 + rrdlabels_destroy(parser->user.new_host_labels);
1120 + rrdlabels_destroy(parser->user.chart_rrdlabels_linked_temporarily);
1121
1122 -void pluginsd_process_thread_cleanup(void *pptr) {
1123 - PARSER *parser = CLEANUP_FUNCTION_GET_PTR(pptr);
1124 - pluginsd_process_cleanup(parser);
1125 - rrd_collector_finished();
1122 + parser_destroy(parser);
1123 }
1124
1125 bool parser_reconstruct_node(BUFFER *wb, void *ptr) {
@@ -1188,7 +1185,6 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, int fd_input,
1185 };
1186 ND_LOG_STACK_PUSH(lgs);
1187
1191 - CLEANUP_FUNCTION_REGISTER(pluginsd_process_thread_cleanup) cleanup_parser = parser;
1188 buffered_reader_init(&parser->reader);
1189 CLEAN_BUFFER *buffer = buffer_create(sizeof(parser->reader.read_buffer) + 2, NULL);
1190 bool send_quit = true;
@@ -1234,6 +1230,9 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, int fd_input,
1230 else
1231 cd->serial_failures++;
1232
1233 + pluginsd_process_cleanup(parser);
1234 + rrd_collector_finished();
1235 +
1236 return count;
1237 }
1238