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