fixed incomplete code in avl.c; added comments about the status of appconfig.c
Costa Tsaousis committed
May 12, 2016 at 22:20 UTC
35f61482be4bced0db62e16dc2afa38d8ee8a594
4 files changed
+208
-138
src/appconfig.c
+176
-127
@@ -1,3 +1,20 @@
1
+
2
+/*
3
+ * TODO
4
+ *
5
+ * 1. Re-write this using DICTIONARY
6
+ *
7
+ * FIXME
8
+ * The way it is now, concurrency locking is incomplete!
9
+ * It makes sure that only one writes to the structures
10
+ * but at the same time there may be unlimited readers.
11
+ * This can cause crashes.
12
+ *
13
+ * Of course, rewriting this to use DICTIONARY instead of
14
+ * directly accessing AVL structures, will solve the problem.
15
+ *
16
+ */
17
+
18
#ifdef HAVE_CONFIG_H
19
#include <config.h>
20
#endif
@@ -54,7 +71,35 @@ struct config {
71
72
73
// ----------------------------------------------------------------------------
57
-// config value
74
+// locking
75
+
76
+static inline void config_global_read_lock(void) {
77
+ pthread_rwlock_rdlock(&config_rwlock);
78
+}
79
+
80
+static inline void config_global_write_lock(void) {
81
+ pthread_rwlock_wrlock(&config_rwlock);
82
+}
83
+
84
+static inline void config_global_unlock(void) {
85
+ pthread_rwlock_unlock(&config_rwlock);
86
+}
87
+
88
+static inline void config_section_read_lock(struct config *co) {
89
+ pthread_rwlock_rdlock(&co->rwlock);
90
+}
91
+
92
+static inline void config_section_write_lock(struct config *co) {
93
+ pthread_rwlock_wrlock(&co->rwlock);
94
+}
95
+
96
+static inline void config_section_unlock(struct config *co) {
97
+ pthread_rwlock_unlock(&co->rwlock);
98
+}
99
+
100
+
101
+// ----------------------------------------------------------------------------
102
+// config name-value index
103
104
static int config_value_iterator(avl *a) { if(a) {}; return 0; }
105
@@ -76,8 +121,9 @@ static struct config_value *config_value_index_find(struct config *co, const cha
121
return result;
122
}
123
124
+
125
// ----------------------------------------------------------------------------
80
-// config
126
+// config sections index
127
128
static int config_iterator(avl *a) { if(a) {}; return 0; }
129
@@ -104,39 +150,15 @@ static struct config *config_index_find(const char *name, uint32_t hash) {
150
return result;
151
}
152
107
-struct config_value *config_value_create(struct config *co, const char *name, const char *value)
108
-{
109
- debug(D_CONFIG, "Creating config entry for name '%s', value '%s', in section '%s'.", name, value, co->name);
110
-
111
- struct config_value *cv = calloc(1, sizeof(struct config_value));
112
- if(!cv) fatal("Cannot allocate config_value");
153
114
- cv->name = strdup(name);
115
- if(!cv->name) fatal("Cannot allocate config.name");
116
- cv->hash = simple_hash(cv->name);
117
-
118
- cv->value = strdup(value);
119
- if(!cv->value) fatal("Cannot allocate config.value");
120
-
121
- config_value_index_add(co, cv);
122
-
123
- // no need for string termination, due to calloc()
124
-
125
- pthread_rwlock_wrlock(&co->rwlock);
126
-
127
- struct config_value *cv2 = co->values;
128
- if(cv2) {
129
- while (cv2->next) cv2 = cv2->next;
130
- cv2->next = cv;
131
- }
132
- else co->values = cv;
133
-
134
- pthread_rwlock_unlock(&co->rwlock);
154
+// ----------------------------------------------------------------------------
155
+// config section methods
156
136
- return cv;
157
+static inline struct config *config_section_find(const char *section) {
158
+ return config_index_find(section, 0);
159
}
160
139
-struct config *config_create(const char *section)
161
+static inline struct config *config_section_create(const char *section)
162
{
163
debug(D_CONFIG, "Creating section '%s'.", section);
164
@@ -147,14 +169,11 @@ struct config *config_create(const char *section)
169
if(!co->name) fatal("Cannot allocate config.name");
170
co->hash = simple_hash(co->name);
171
150
- pthread_rwlock_init(&co->rwlock, NULL);
172
avl_init_lock(&co->values_index, config_value_compare);
173
153
- config_index_add(co);
154
-
155
- // no need for string termination, due to calloc()
174
+ config_global_write_lock();
175
157
- pthread_rwlock_wrlock(&config_rwlock);
176
+ config_index_add(co);
177
178
struct config *co2 = config_root;
179
if(co2) {
@@ -163,98 +182,43 @@ struct config *config_create(const char *section)
182
}
183
else config_root = co;
184
166
- pthread_rwlock_unlock(&config_rwlock);
185
+ config_global_unlock();
186
187
return co;
188
}
189
171
-struct config *config_find_section(const char *section)
172
-{
173
- return config_index_find(section, 0);
174
-}
190
176
-int load_config(char *filename, int overwrite_used)
177
-{
178
- int line = 0;
179
- struct config *co = NULL;
180
-
181
- char buffer[CONFIG_FILE_LINE_MAX + 1], *s;
182
-
183
- if(!filename) filename = CONFIG_DIR "/" CONFIG_FILENAME;
184
- FILE *fp = fopen(filename, "r");
185
- if(!fp) {
186
- error("Cannot open file '%s'", filename);
187
- return 0;
188
- }
189
-
190
- while(fgets(buffer, CONFIG_FILE_LINE_MAX, fp) != NULL) {
191
- buffer[CONFIG_FILE_LINE_MAX] = '\0';
192
- line++;
193
-
194
- s = trim(buffer);
195
- if(!s) {
196
- debug(D_CONFIG, "Ignoring line %d, it is empty.", line);
197
- continue;
198
- }
199
-
200
- int len = (int) strlen(s);
201
- if(*s == '[' && s[len - 1] == ']') {
202
- // new section
203
- s[len - 1] = '\0';
204
- s++;
191
+// ----------------------------------------------------------------------------
192
+// config name-value methods
193
206
- co = config_find_section(s);
207
- if(!co) co = config_create(s);
194
+static inline struct config_value *config_value_create(struct config *co, const char *name, const char *value)
195
+{
196
+ debug(D_CONFIG, "Creating config entry for name '%s', value '%s', in section '%s'.", name, value, co->name);
197
209
- continue;
210
- }
198
+ struct config_value *cv = calloc(1, sizeof(struct config_value));
199
+ if(!cv) fatal("Cannot allocate config_value");
200
212
- if(!co) {
213
- // line outside a section
214
- error("Ignoring line %d ('%s'), it is outside all sections.", line, s);
215
- continue;
216
- }
201
+ cv->name = strdup(name);
202
+ if(!cv->name) fatal("Cannot allocate config.name");
203
+ cv->hash = simple_hash(cv->name);
204
218
- char *name = s;
219
- char *value = strchr(s, '=');
220
- if(!value) {
221
- error("Ignoring line %d ('%s'), there is no = in it.", line, s);
222
- continue;
223
- }
224
- *value = '\0';
225
- value++;
205
+ cv->value = strdup(value);
206
+ if(!cv->value) fatal("Cannot allocate config.value");
207
227
- name = trim(name);
228
- value = trim(value);
208
+ config_section_write_lock(co);
209
230
- if(!name) {
231
- error("Ignoring line %d, name is empty.", line);
232
- continue;
233
- }
234
- if(!value) {
235
- debug(D_CONFIG, "Ignoring line %d, value is empty.", line);
236
- continue;
237
- }
238
-
239
- struct config_value *cv = config_value_index_find(co, name, 0);
210
+ config_value_index_add(co, cv);
211
241
- if(!cv) cv = config_value_create(co, name, value);
242
- else {
243
- if(((cv->flags & CONFIG_VALUE_USED) && overwrite_used) || !(cv->flags & CONFIG_VALUE_USED)) {
244
- debug(D_CONFIG, "Overwriting '%s/%s'.", line, co->name, cv->name);
245
- free(cv->value);
246
- cv->value = strdup(value);
247
- if(!cv->value) fatal("Cannot allocate config.value");
248
- }
249
- else
250
- debug(D_CONFIG, "Ignoring line %d, '%s/%s' is already present and used.", line, co->name, cv->name);
251
- }
252
- cv->flags |= CONFIG_VALUE_LOADED;
212
+ struct config_value *cv2 = co->values;
213
+ if(cv2) {
214
+ while (cv2->next) cv2 = cv2->next;
215
+ cv2->next = cv;
216
}
217
+ else co->values = cv;
218
255
- fclose(fp);
219
+ config_section_unlock(co);
220
257
- return 1;
221
+ return cv;
222
}
223
224
char *config_get(const char *section, const char *name, const char *default_value)
@@ -263,8 +227,8 @@ char *config_get(const char *section, const char *name, const char *default_valu
227
228
debug(D_CONFIG, "request to get config in section '%s', name '%s', default_value '%s'", section, name, default_value);
229
266
- struct config *co = config_find_section(section);
267
- if(!co) co = config_create(section);
230
+ struct config *co = config_section_find(section);
231
+ if(!co) co = config_section_create(section);
232
233
cv = config_value_index_find(co, name, 0);
234
if(!cv) {
@@ -341,7 +305,7 @@ const char *config_set_default(const char *section, const char *name, const char
305
306
debug(D_CONFIG, "request to set config in section '%s', name '%s', value '%s'", section, name, value);
307
344
- struct config *co = config_find_section(section);
308
+ struct config *co = config_section_find(section);
309
if(!co) return config_set(section, name, value);
310
311
cv = config_value_index_find(co, name, 0);
@@ -369,8 +333,8 @@ const char *config_set(const char *section, const char *name, const char *value)
333
334
debug(D_CONFIG, "request to set config in section '%s', name '%s', value '%s'", section, name, value);
335
372
- struct config *co = config_find_section(section);
373
- if(!co) co = config_create(section);
336
+ struct config *co = config_section_find(section);
337
+ if(!co) co = config_section_create(section);
338
339
cv = config_value_index_find(co, name, 0);
340
if(!cv) cv = config_value_create(co, name, value);
@@ -408,6 +372,94 @@ int config_set_boolean(const char *section, const char *name, int value)
372
return value;
373
}
374
375
+
376
+// ----------------------------------------------------------------------------
377
+// config load/save
378
+
379
+int load_config(char *filename, int overwrite_used)
380
+{
381
+ int line = 0;
382
+ struct config *co = NULL;
383
+
384
+ char buffer[CONFIG_FILE_LINE_MAX + 1], *s;
385
+
386
+ if(!filename) filename = CONFIG_DIR "/" CONFIG_FILENAME;
387
+ FILE *fp = fopen(filename, "r");
388
+ if(!fp) {
389
+ error("Cannot open file '%s'", filename);
390
+ return 0;
391
+ }
392
+
393
+ while(fgets(buffer, CONFIG_FILE_LINE_MAX, fp) != NULL) {
394
+ buffer[CONFIG_FILE_LINE_MAX] = '\0';
395
+ line++;
396
+
397
+ s = trim(buffer);
398
+ if(!s) {
399
+ debug(D_CONFIG, "Ignoring line %d, it is empty.", line);
400
+ continue;
401
+ }
402
+
403
+ int len = (int) strlen(s);
404
+ if(*s == '[' && s[len - 1] == ']') {
405
+ // new section
406
+ s[len - 1] = '\0';
407
+ s++;
408
+
409
+ co = config_section_find(s);
410
+ if(!co) co = config_section_create(s);
411
+
412
+ continue;
413
+ }
414
+
415
+ if(!co) {
416
+ // line outside a section
417
+ error("Ignoring line %d ('%s'), it is outside all sections.", line, s);
418
+ continue;
419
+ }
420
+
421
+ char *name = s;
422
+ char *value = strchr(s, '=');
423
+ if(!value) {
424
+ error("Ignoring line %d ('%s'), there is no = in it.", line, s);
425
+ continue;
426
+ }
427
+ *value = '\0';
428
+ value++;
429
+
430
+ name = trim(name);
431
+ value = trim(value);
432
+
433
+ if(!name) {
434
+ error("Ignoring line %d, name is empty.", line);
435
+ continue;
436
+ }
437
+ if(!value) {
438
+ debug(D_CONFIG, "Ignoring line %d, value is empty.", line);
439
+ continue;
440
+ }
441
+
442
+ struct config_value *cv = config_value_index_find(co, name, 0);
443
+
444
+ if(!cv) cv = config_value_create(co, name, value);
445
+ else {
446
+ if(((cv->flags & CONFIG_VALUE_USED) && overwrite_used) || !(cv->flags & CONFIG_VALUE_USED)) {
447
+ debug(D_CONFIG, "Overwriting '%s/%s'.", line, co->name, cv->name);
448
+ free(cv->value);
449
+ cv->value = strdup(value);
450
+ if(!cv->value) fatal("Cannot allocate config.value");
451
+ }
452
+ else
453
+ debug(D_CONFIG, "Ignoring line %d, '%s/%s' is already present and used.", line, co->name, cv->name);
454
+ }
455
+ cv->flags |= CONFIG_VALUE_LOADED;
456
+ }
457
+
458
+ fclose(fp);
459
+
460
+ return 1;
461
+}
462
+
463
void generate_config(BUFFER *wb, int only_changed)
464
{
465
int i, pri;
@@ -433,7 +485,7 @@ void generate_config(BUFFER *wb, int only_changed)
485
break;
486
}
487
436
- pthread_rwlock_wrlock(&config_rwlock);
488
+ config_global_write_lock();
489
for(co = config_root; co ; co = co->next) {
490
if(strcmp(co->name, "global") == 0 || strcmp(co->name, "plugins") == 0 || strcmp(co->name, "registry") == 0) pri = 0;
491
else if(strncmp(co->name, "plugin:", 7) == 0) pri = 1;
@@ -444,15 +496,13 @@ void generate_config(BUFFER *wb, int only_changed)
496
int changed = 0;
497
int count = 0;
498
447
- pthread_rwlock_wrlock(&co->rwlock);
448
-
499
+ config_section_write_lock(co);
500
for(cv = co->values; cv ; cv = cv->next) {
501
used += (cv->flags & CONFIG_VALUE_USED)?1:0;
502
changed += (cv->flags & CONFIG_VALUE_CHANGED)?1:0;
503
count++;
504
}
454
-
455
- pthread_rwlock_unlock(&co->rwlock);
505
+ config_section_unlock(co);
506
507
if(!count) continue;
508
if(only_changed && !changed) continue;
@@ -463,7 +513,7 @@ void generate_config(BUFFER *wb, int only_changed)
513
514
buffer_sprintf(wb, "\n[%s]\n", co->name);
515
466
- pthread_rwlock_wrlock(&co->rwlock);
516
+ config_section_write_lock(co);
517
for(cv = co->values; cv ; cv = cv->next) {
518
519
if(used && !(cv->flags & CONFIG_VALUE_USED)) {
@@ -471,10 +521,9 @@ void generate_config(BUFFER *wb, int only_changed)
521
}
522
buffer_sprintf(wb, "\t%s%s = %s\n", ((!(cv->flags & CONFIG_VALUE_CHANGED)) && (cv->flags & CONFIG_VALUE_USED))?"# ":"", cv->name, cv->value);
523
}
474
- pthread_rwlock_unlock(&co->rwlock);
524
+ config_section_unlock(co);
525
}
526
}
477
- pthread_rwlock_unlock(&config_rwlock);
527
+ config_global_unlock();
528
}
529
}
480
-
src/apps_plugin.c
+13
@@ -39,6 +39,10 @@
39
#include "procfile.h"
40
#include "../config.h"
41
42
+#ifdef NETDATA_INTERNAL_CHECKS
43
+#include <sys/prctl.h>
44
+#endif
45
+
46
#define MAX_COMPARE_NAME 100
47
#define MAX_NAME 100
48
#define MAX_CMDLINE 1024
@@ -2408,6 +2412,15 @@ int main(int argc, char **argv)
2412
}
2413
else info("Found NETDATA_CONFIG_DIR='%s'", config_dir);
2414
2415
+#ifdef NETDATA_INTERNAL_CHECKS
2416
+ if(debug_flags != 0) {
2417
+ struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
2418
+ if(setrlimit(RLIMIT_CORE, &rl) != 0)
2419
+ info("Cannot request unlimited core dumps for debugging... Proceeding anyway...");
2420
+ prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
2421
+ }
2422
+#endif /* NETDATA_INTERNAL_CHECKS */
2423
+
2424
info("starting...");
2425
2426
procfile_adaptive_initial_allocation = 1;
src/avl.c
+16
-6
@@ -316,7 +316,17 @@ void avl_init(avl_tree *t, int (*compar)(void *a, void *b)) {
316
317
/* ------------------------------------------------------------------------- */
318
319
-void avl_lock(avl_tree_lock *t) {
319
+void avl_read_lock(avl_tree_lock *t) {
320
+#ifndef AVL_WITHOUT_PTHREADS
321
+#ifdef AVL_LOCK_WITH_MUTEX
322
+ pthread_mutex_lock(&t->mutex);
323
+#else
324
+ pthread_rwlock_rdlock(&t->rwlock);
325
+#endif
326
+#endif /* AVL_WITHOUT_PTHREADS */
327
+}
328
+
329
+void avl_write_lock(avl_tree_lock *t) {
330
#ifndef AVL_WITHOUT_PTHREADS
331
#ifdef AVL_LOCK_WITH_MUTEX
332
pthread_mutex_lock(&t->mutex);
@@ -357,29 +367,29 @@ void avl_init_lock(avl_tree_lock *t, int (*compar)(void *a, void *b)) {
367
}
368
369
int avl_range_lock(avl_tree_lock *t, avl *a, avl *b, int (*iter)(avl *), avl **ret) {
360
- avl_lock(t);
370
+ avl_read_lock(t);
371
int ret2 = avl_range(&t->avl_tree, a, b, iter, ret);
372
avl_unlock(t);
373
return ret2;
374
}
375
376
int avl_removeroot_lock(avl_tree_lock *t) {
367
- avl_lock(t);
377
+ avl_write_lock(t);
378
int ret = avl_removeroot(&t->avl_tree);
379
avl_unlock(t);
380
return ret;
381
}
382
383
int avl_remove_lock(avl_tree_lock *t, avl *a) {
374
- avl_lock(t);
384
+ avl_write_lock(t);
385
int ret = avl_remove(&t->avl_tree, a);
386
avl_unlock(t);
387
return ret;
388
}
389
390
int avl_insert_lock(avl_tree_lock *t, avl *a) {
381
- avl_lock(t);
391
+ avl_write_lock(t);
392
int ret = avl_insert(&t->avl_tree, a);
383
- avl_lock(t);
393
+ avl_unlock(t);
394
return ret;
395
}
src/main.c
+3
-5
@@ -496,18 +496,17 @@ int main(int argc, char **argv)
496
// never become a problem
497
if(nice(20) == -1) error("Cannot lower my CPU priority.");
498
499
- if(become_daemon(dont_fork, 0, user, input_log_file, output_log_file, error_log_file, access_log_file, &access_fd, &stdaccess) == -1) {
499
+ if(become_daemon(dont_fork, 0, user, input_log_file, output_log_file, error_log_file, access_log_file, &access_fd, &stdaccess) == -1)
500
fatal("Cannot demonize myself.");
501
- exit(1);
502
- }
501
502
+#ifdef NETDATA_INTERNAL_CHECKS
503
if(debug_flags != 0) {
504
struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
505
if(setrlimit(RLIMIT_CORE, &rl) != 0)
506
info("Cannot request unlimited core dumps for debugging... Proceeding anyway...");
508
-
507
prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
508
}
509
+#endif /* NETDATA_INTERNAL_CHECKS */
510
511
if(output_log_syslog || error_log_syslog || access_log_syslog)
512
openlog("netdata", LOG_PID, LOG_DAEMON);
@@ -515,7 +514,6 @@ int main(int argc, char **argv)
514
info("NetData started on pid %d", getpid());
515
516
518
-
517
// ------------------------------------------------------------------------
518
// get default pthread stack size
519