will not load dimensions if they are too old; threads are now handled with an array; possible fix for the defunct issue
Costa Tsaousis (ktsaou) committed
Mar 12, 2015 at 23:34 UTC
a689b90076ffb089db188d0cd469e724e6909d24
1 file changed
+359
-245
netdata.c
+359
-245
@@ -37,6 +37,8 @@
37
#include <dirent.h>
38
#include <sys/mman.h>
39
40
+void process_childs(int wait);
41
+
42
// enabling this will detach the plugins from netdata
43
// each plugin will have its own process group
44
// #define DETACH_PLUGINS_FROM_NETDATA
@@ -884,22 +886,22 @@ const char *chart_type_name(int chart_type)
886
// ----------------------------------------------------------------------------
887
// algorithms types
888
887
-#define RRD_DIMENSION_ABSOLUTE_NAME "absolute"
888
-#define RRD_DIMENSION_INCREMENTAL_NAME "incremental"
889
-#define RRD_DIMENSION_PCENT_OVER_DIFF_TOTAL_NAME "percentage-of-incremental-row"
890
-#define RRD_DIMENSION_PCENT_OVER_ROW_TOTAL_NAME "percentage-of-absolute-row"
889
+#define RRD_DIMENSION_ABSOLUTE_NAME "absolute"
890
+#define RRD_DIMENSION_INCREMENTAL_NAME "incremental"
891
+#define RRD_DIMENSION_PCENT_OVER_DIFF_TOTAL_NAME "percentage-of-incremental-row"
892
+#define RRD_DIMENSION_PCENT_OVER_ROW_TOTAL_NAME "percentage-of-absolute-row"
893
892
-#define RRD_DIMENSION_ABSOLUTE 0
893
-#define RRD_DIMENSION_INCREMENTAL 1
894
+#define RRD_DIMENSION_ABSOLUTE 0
895
+#define RRD_DIMENSION_INCREMENTAL 1
896
#define RRD_DIMENSION_PCENT_OVER_DIFF_TOTAL 2
895
-#define RRD_DIMENSION_PCENT_OVER_ROW_TOTAL 3
897
+#define RRD_DIMENSION_PCENT_OVER_ROW_TOTAL 3
898
899
int algorithm_id(const char *name)
900
{
899
- if(strcmp(name, RRD_DIMENSION_ABSOLUTE_NAME) == 0) return RRD_DIMENSION_ABSOLUTE;
900
- if(strcmp(name, RRD_DIMENSION_INCREMENTAL_NAME) == 0) return RRD_DIMENSION_INCREMENTAL;
901
- if(strcmp(name, RRD_DIMENSION_PCENT_OVER_ROW_TOTAL_NAME) == 0) return RRD_DIMENSION_PCENT_OVER_ROW_TOTAL;
902
- if(strcmp(name, RRD_DIMENSION_PCENT_OVER_DIFF_TOTAL_NAME) == 0) return RRD_DIMENSION_PCENT_OVER_DIFF_TOTAL;
901
+ if(strcmp(name, RRD_DIMENSION_ABSOLUTE_NAME) == 0) return RRD_DIMENSION_ABSOLUTE;
902
+ if(strcmp(name, RRD_DIMENSION_INCREMENTAL_NAME) == 0) return RRD_DIMENSION_INCREMENTAL;
903
+ if(strcmp(name, RRD_DIMENSION_PCENT_OVER_ROW_TOTAL_NAME) == 0) return RRD_DIMENSION_PCENT_OVER_ROW_TOTAL;
904
+ if(strcmp(name, RRD_DIMENSION_PCENT_OVER_DIFF_TOTAL_NAME) == 0) return RRD_DIMENSION_PCENT_OVER_DIFF_TOTAL;
905
return RRD_DIMENSION_ABSOLUTE;
906
}
907
@@ -1153,80 +1155,82 @@ calculated_number unpack_storage_number(storage_number value)
1155
}
1156
1157
1156
-#define RRD_STATS_MAGIC "NETDATA CACHE STATS FILE V008"
1157
-#define RRD_DIMENSION_MAGIC "NETDATA CACHE DIMENSION FILE V008"
1158
+#define RRD_STATS_MAGIC "NETDATA CACHE STATS FILE V009"
1159
+#define RRD_DIMENSION_MAGIC "NETDATA CACHE DIMENSION FILE V009"
1160
1161
struct rrd_dimension {
1160
- char magic[sizeof(RRD_DIMENSION_MAGIC) + 1];// our magic
1161
- char id[RRD_STATS_NAME_MAX + 1]; // the id of this dimension (for internal identification)
1162
- char *name; // the name of this dimension (as presented to user)
1162
+ char magic[sizeof(RRD_DIMENSION_MAGIC) + 1]; // our magic
1163
+ char id[RRD_STATS_NAME_MAX + 1]; // the id of this dimension (for internal identification)
1164
+ char *name; // the name of this dimension (as presented to user)
1165
char cache_file[FILENAME_MAX+1];
1166
1165
- unsigned long hash; // a simple hash on the id, to speed up searching
1166
- // we first compare hashes, and only if the hashes are equal we do string comparisons
1167
+ unsigned long hash; // a simple hash on the id, to speed up searching
1168
+ // we first compare hashes, and only if the hashes are equal we do string comparisons
1169
+
1170
+ long entries; // how many entries this dimension has
1171
+ // this should be the same to the entries of the data set
1172
1168
- long entries; // how many entries this dimension has
1169
- // this should be the same to the entries of the data set
1170
- long current_entry; // the entry that is currently being updated
1173
+ long current_entry; // the entry that is currently being updated
1174
+ int update_every; // every how many seconds is this updated?
1175
1172
- int hidden; // if set to non zero, this dimension will not be sent to the client
1173
- int mapped; // 1 if the file is mapped
1174
- unsigned long memsize; // the memory allocated for this dimension
1176
+ int hidden; // if set to non zero, this dimension will not be sent to the client
1177
+ int mapped; // 1 if the file is mapped
1178
+ unsigned long memsize; // the memory allocated for this dimension
1179
1180
int algorithm;
1181
long multiplier;
1182
long divisor;
1183
1180
- struct timeval last_collected_time; // when was this dimension last updated
1181
- // this is only used to detect un-updated dimensions
1182
- // which are removed after some time
1184
+ struct timeval last_collected_time; // when was this dimension last updated
1185
+ // this is only used to detect un-updated dimensions
1186
+ // which are removed after some time
1187
1188
calculated_number calculated_value;
1189
calculated_number last_calculated_value;
1190
1187
- collected_number collected_value; // the value collected at this round
1191
+ collected_number collected_value; // the value collected at this round
1192
collected_number last_collected_value; // the value that was collected at the last round
1193
1190
- struct rrd_dimension *next; // linking of dimensions within the same data set
1194
+ struct rrd_dimension *next; // linking of dimensions within the same data set
1195
1192
- storage_number values[]; // the array of values - THIS HAS TO BE THE LAST MEMBER
1196
+ storage_number values[]; // the array of values - THIS HAS TO BE THE LAST MEMBER
1197
};
1198
typedef struct rrd_dimension RRD_DIMENSION;
1199
1200
struct rrd_stats {
1197
- char magic[sizeof(RRD_STATS_MAGIC) + 1];// our magic
1201
+ char magic[sizeof(RRD_STATS_MAGIC) + 1]; // our magic
1202
1199
- char id[RRD_STATS_NAME_MAX + 1]; // id of the data set
1200
- char *name; // name of the data set
1201
- char *cache_dir; // the directory to store dimension maps
1203
+ char id[RRD_STATS_NAME_MAX + 1]; // id of the data set
1204
+ char *name; // name of the data set
1205
+ char *cache_dir; // the directory to store dimension maps
1206
char cache_file[FILENAME_MAX+1];
1207
1204
- char *type; // the type of graph RRD_TYPE_* (a category, for determining graphing options)
1205
- char *family; // the family of this data set (for grouping them together)
1206
- char *title; // title shown to user
1207
- char *units; // units of measurement
1208
+ char *type; // the type of graph RRD_TYPE_* (a category, for determining graphing options)
1209
+ char *family; // the family of this data set (for grouping them together)
1210
+ char *title; // title shown to user
1211
+ char *units; // units of measurement
1212
1213
pthread_rwlock_t rwlock;
1210
- unsigned long counter; // the number of times we added values to this rrd
1211
- unsigned long counter_done; // the number of times we added values to this rrd
1214
+ unsigned long counter; // the number of times we added values to this rrd
1215
+ unsigned long counter_done; // the number of times we added values to this rrd
1216
1213
- int mapped; // if set to 1, this is memory mapped
1214
- unsigned long memsize; // how much mem we have allocated for this (without dimensions)
1217
+ int mapped; // if set to 1, this is memory mapped
1218
+ unsigned long memsize; // how much mem we have allocated for this (without dimensions)
1219
1216
- unsigned long hash_name; // a simple hash on the name
1217
- unsigned long hash; // a simple hash on the id, to speed up searching
1218
- // we first compare hashes, and only if the hashes are equal we do string comparisons
1220
+ unsigned long hash_name; // a simple hash on the name
1221
+ unsigned long hash; // a simple hash on the id, to speed up searching
1222
+ // we first compare hashes, and only if the hashes are equal we do string comparisons
1223
1224
long priority;
1225
1222
- long entries; // total number of entries in the data set
1223
- long current_entry; // the entry that is currently being updated
1224
- // it goes around in a round-robin fashion
1226
+ long entries; // total number of entries in the data set
1227
+ long current_entry; // the entry that is currently being updated
1228
+ // it goes around in a round-robin fashion
1229
1226
- int update_every; // every how many seconds is this updated?
1227
- unsigned long long first_entry_t; // the timestamp (in microseconds) of the oldest entry in the db
1228
- struct timeval last_updated; // when this data set was last updated (updated every time the rrd_stats_done() function)
1229
- struct timeval last_collected_time; //
1230
+ int update_every; // every how many seconds is this updated?
1231
+ unsigned long long first_entry_t; // the timestamp (in microseconds) of the oldest entry in the db
1232
+ struct timeval last_updated; // when this data set was last updated (updated every time the rrd_stats_done() function)
1233
+ struct timeval last_collected_time; //
1234
unsigned long long usec_since_last_update;
1235
1236
total_number collected_total;
@@ -1235,12 +1239,12 @@ struct rrd_stats {
1239
int chart_type;
1240
int debug;
1241
int enabled;
1238
- int isdetail; // if set, the data set should be considered as a detail of another
1239
- // (the master data set should be the one that has the same family and is not detail)
1242
+ int isdetail; // if set, the data set should be considered as a detail of another
1243
+ // (the master data set should be the one that has the same family and is not detail)
1244
1241
- RRD_DIMENSION *dimensions; // the actual data for every dimension
1245
+ RRD_DIMENSION *dimensions; // the actual data for every dimension
1246
1243
- struct rrd_stats *next; // linking of rrd stats
1247
+ struct rrd_stats *next; // linking of rrd stats
1248
};
1249
typedef struct rrd_stats RRD_STATS;
1250
@@ -1294,6 +1298,21 @@ char *rrd_stats_cache_dir(const char *id)
1298
return ret;
1299
}
1300
1301
+void rrd_stats_reset(RRD_STATS *st)
1302
+{
1303
+ st->last_collected_time.tv_sec = 0;
1304
+ st->last_collected_time.tv_usec = 0;
1305
+ st->current_entry = 0;
1306
+ st->counter_done = 0;
1307
+
1308
+ RRD_DIMENSION *rd;
1309
+ for(rd = st->dimensions; rd ; rd = rd->next) {
1310
+ rd->last_collected_time.tv_sec = 0;
1311
+ rd->last_collected_time.tv_usec = 0;
1312
+ rd->current_entry = 0;
1313
+ }
1314
+}
1315
+
1316
RRD_STATS *rrd_stats_create(const char *type, const char *id, const char *name, const char *family, const char *title, const char *units, long priority, int update_every, int chart_type)
1317
{
1318
if(!id || !id[0]) {
@@ -1425,6 +1444,9 @@ RRD_DIMENSION *rrd_stats_dimension_add(RRD_STATS *st, const char *id, const char
1444
snprintf(fullfilename, FILENAME_MAX, "%s/%s.db", st->cache_dir, filename);
1445
rd = (RRD_DIMENSION *)mymmap(fullfilename, size);
1446
if(rd) {
1447
+ struct timeval now;
1448
+ gettimeofday(&now, NULL);
1449
+
1450
if(strcmp(rd->magic, RRD_DIMENSION_MAGIC) != 0) {
1451
errno = 0;
1452
error("File %s does not have our version. Clearing it.", fullfilename);
@@ -1450,6 +1472,16 @@ RRD_DIMENSION *rrd_stats_dimension_add(RRD_STATS *st, const char *id, const char
1472
error("File %s does not have the same algorithm. Clearing it.", fullfilename);
1473
bzero(rd, size);
1474
}
1475
+ else if(rd->update_every != st->update_every) {
1476
+ errno = 0;
1477
+ error("File %s does not have the same refresh frequency. Clearing it.", fullfilename);
1478
+ bzero(rd, size);
1479
+ }
1480
+ else if(usecdiff(&now, &rd->last_collected_time) > (rd->entries * rd->update_every * 1000000ULL)) {
1481
+ errno = 0;
1482
+ error("File %s is too old. Clearing it.", fullfilename);
1483
+ bzero(rd, size);
1484
+ }
1485
else if(strcmp(rd->id, id) != 0) {
1486
errno = 0;
1487
error("File %s does not have our dimension id. Unmapping it.", fullfilename);
@@ -1497,6 +1529,7 @@ RRD_DIMENSION *rrd_stats_dimension_add(RRD_STATS *st, const char *id, const char
1529
if(!rd->divisor) rd->divisor = 1;
1530
1531
rd->entries = st->entries;
1532
+ rd->update_every = st->update_every;
1533
1534
// append this dimension
1535
if(!st->dimensions)
@@ -3996,6 +4029,14 @@ void *socket_listen_main(void *ptr)
4029
struct timeval tv;
4030
int retval;
4031
4032
+ if(ptr) { ; }
4033
+
4034
+ if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
4035
+ error("Cannot set pthread cancel type to DEFERRED.");
4036
+
4037
+ if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
4038
+ error("Cannot set pthread cancel state to ENABLE.");
4039
+
4040
// int listener = create_listen_socket(listen_port);
4041
int listener = listen_fd;
4042
if(listener == -1) fatal("LISTENER: Cannot create listening socket on port 19999.");
@@ -4040,7 +4081,9 @@ void *socket_listen_main(void *ptr)
4081
else debug(D_WEB_CLIENT, "LISTENER: select() didn't do anything.");
4082
4083
}
4043
- //else debug(D_WEB_CLIENT, "LISTENER: select() timeout.");
4084
+ //else {
4085
+ // debug(D_WEB_CLIENT, "LISTENER: select() timeout.");
4086
+ //}
4087
4088
// cleanup unused clients
4089
for(w = web_clients; w ; w = w?w->next:NULL) {
@@ -4071,13 +4114,14 @@ void *socket_listen_main(void *ptr)
4114
int do_proc_net_dev() {
4115
static int enable_new_interfaces = -1;
4116
static int do_bandwidth = -1, do_packets = -1, do_errors = -1, do_fifo = -1, do_compressed = -1;
4117
+ static FILE *fp = NULL;
4118
4119
if(enable_new_interfaces == -1) enable_new_interfaces = config_get_boolean("plugin:proc:/proc/net/dev", "enable new interfaces detected at runtime", 1);
4120
4121
if(do_bandwidth == -1) do_bandwidth = config_get_boolean("plugin:proc:/proc/net/dev", "bandwidth for all interfaces", 1);
4122
if(do_packets == -1) do_packets = config_get_boolean("plugin:proc:/proc/net/dev", "packets for all interfaces", 1);
4079
- if(do_errors == -1) do_errors = config_get_boolean("plugin:proc:/proc/net/dev", "errors for all interfaces", 1);
4080
- if(do_fifo == -1) do_fifo = config_get_boolean("plugin:proc:/proc/net/dev", "fifo for all interfaces", 1);
4123
+ if(do_errors == -1) do_errors = config_get_boolean("plugin:proc:/proc/net/dev", "errors for all interfaces", 1);
4124
+ if(do_fifo == -1) do_fifo = config_get_boolean("plugin:proc:/proc/net/dev", "fifo for all interfaces", 1);
4125
if(do_compressed == -1) do_compressed = config_get_boolean("plugin:proc:/proc/net/dev", "compressed packets for all interfaces", 1);
4126
4127
char buffer[MAX_PROC_NET_DEV_LINE+1] = "";
@@ -4088,10 +4132,20 @@ int do_proc_net_dev() {
4132
int r;
4133
char *p;
4134
4091
- FILE *fp = fopen("/proc/net/dev", "r");
4135
+ if(fp) {
4136
+ if(fseek(fp, 0, SEEK_SET) == -1) {
4137
+ error("Re-opening file /proc/net/dev.");
4138
+ fclose(fp);
4139
+ fp = NULL;
4140
+ }
4141
+ }
4142
+
4143
if(!fp) {
4093
- error("Cannot read /proc/net/dev.");
4094
- return 1;
4144
+ fp = fopen("/proc/net/dev", "r");
4145
+ if(!fp) {
4146
+ error("Cannot read /proc/net/dev.");
4147
+ return 1;
4148
+ }
4149
}
4150
4151
// skip the first two lines
@@ -4216,7 +4270,6 @@ int do_proc_net_dev() {
4270
}
4271
}
4272
4219
- fclose(fp);
4273
return 0;
4274
}
4275
@@ -4229,6 +4282,7 @@ int do_proc_net_dev() {
4282
int do_proc_diskstats() {
4283
static int enable_new_disks = -1;
4284
static int do_io = -1, do_ops = -1, do_merged_ops = -1, do_iotime = -1, do_cur_ops = -1;
4285
+ static FILE *fp = NULL;
4286
4287
if(enable_new_disks == -1) enable_new_disks = config_get_boolean("plugin:proc:/proc/diskstats", "enable new disks detected at runtime", 1);
4288
@@ -4244,10 +4298,20 @@ int do_proc_diskstats() {
4298
int r;
4299
char *p;
4300
4247
- FILE *fp = fopen("/proc/diskstats", "r");
4301
+ if(fp) {
4302
+ if(fseek(fp, 0, SEEK_SET) == -1) {
4303
+ error("Re-opening file /proc/diskstats.");
4304
+ fclose(fp);
4305
+ fp = NULL;
4306
+ }
4307
+ }
4308
+
4309
if(!fp) {
4249
- error("Cannot read /proc/diskstats.");
4250
- return 1;
4310
+ fp = fopen("/proc/diskstats", "r");
4311
+ if(!fp) {
4312
+ error("Cannot read /proc/diskstats.");
4313
+ return 1;
4314
+ }
4315
}
4316
4317
for(;1;) {
@@ -4514,7 +4578,6 @@ int do_proc_diskstats() {
4578
}
4579
}
4580
4517
- fclose(fp);
4581
return 0;
4582
}
4583
@@ -4525,6 +4588,7 @@ int do_proc_net_snmp() {
4588
static int do_ip_packets = -1, do_ip_fragsout = -1, do_ip_fragsin = -1, do_ip_errors = -1,
4589
do_tcp_sockets = -1, do_tcp_packets = -1, do_tcp_errors = -1, do_tcp_handshake = -1,
4590
do_udp_packets = -1, do_udp_errors = -1;
4591
+ static FILE *fp = NULL;
4592
4593
if(do_ip_packets == -1) do_ip_packets = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 packets", 1);
4594
if(do_ip_fragsout == -1) do_ip_fragsout = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 fragrments sent", 1);
@@ -4539,10 +4603,20 @@ int do_proc_net_snmp() {
4603
4604
char buffer[MAX_PROC_NET_SNMP_LINE+1] = "";
4605
4542
- FILE *fp = fopen("/proc/net/snmp", "r");
4606
+ if(fp) {
4607
+ if(fseek(fp, 0, SEEK_SET) == -1) {
4608
+ error("Re-opening file /proc/net/snmp.");
4609
+ fclose(fp);
4610
+ fp = NULL;
4611
+ }
4612
+ }
4613
+
4614
if(!fp) {
4544
- error("Cannot read /proc/net/snmp.");
4545
- return 1;
4615
+ fp = fopen("/proc/net/snmp", "r");
4616
+ if(!fp) {
4617
+ error("Cannot read /proc/net/snmp.");
4618
+ return 1;
4619
+ }
4620
}
4621
4622
RRD_STATS *st;
@@ -4813,7 +4887,6 @@ int do_proc_net_snmp() {
4887
}
4888
}
4889
4816
- fclose(fp);
4890
return 0;
4891
}
4892
@@ -4822,6 +4895,7 @@ int do_proc_net_snmp() {
4895
4896
int do_proc_net_netstat() {
4897
static int do_bandwidth = -1, do_inerrors = -1, do_mcast = -1, do_bcast = -1, do_mcast_p = -1, do_bcast_p = -1;
4898
+ static FILE *fp = NULL;
4899
4900
if(do_bandwidth == -1) do_bandwidth = config_get_boolean("plugin:proc:/proc/net/netstat", "bandwidth", 1);
4901
if(do_inerrors == -1) do_inerrors = config_get_boolean("plugin:proc:/proc/net/netstat", "input errors", 1);
@@ -4832,10 +4906,20 @@ int do_proc_net_netstat() {
4906
4907
char buffer[MAX_PROC_NET_SNMP_LINE+1] = "";
4908
4835
- FILE *fp = fopen("/proc/net/netstat", "r");
4909
+ if(fp) {
4910
+ if(fseek(fp, 0, SEEK_SET) == -1) {
4911
+ error("Re-opening file /proc/net/netstat.");
4912
+ fclose(fp);
4913
+ fp = NULL;
4914
+ }
4915
+ }
4916
+
4917
if(!fp) {
4837
- error("Cannot read /proc/net/netstat.");
4838
- return 1;
4918
+ fp = fopen("/proc/net/netstat", "r");
4919
+ if(!fp) {
4920
+ error("Cannot read /proc/net/netstat.");
4921
+ return 1;
4922
+ }
4923
}
4924
4925
for(;1;) {
@@ -4978,7 +5062,6 @@ int do_proc_net_netstat() {
5062
}
5063
}
5064
4981
- fclose(fp);
5065
return 0;
5066
}
5067
@@ -4987,6 +5070,7 @@ int do_proc_net_netstat() {
5070
5071
int do_proc_net_stat_conntrack() {
5072
static int do_sockets = -1, do_new = -1, do_changes = -1, do_expect = -1, do_search = -1, do_errors = -1;
5073
+ static FILE *fp = NULL;
5074
5075
if(do_sockets == -1) do_sockets = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter connections", 1);
5076
if(do_new == -1) do_new = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter new connections", 1);
@@ -4998,10 +5082,20 @@ int do_proc_net_stat_conntrack() {
5082
5083
char buffer[MAX_PROC_NET_STAT_CONNTRACK_LINE+1] = "";
5084
5001
- FILE *fp = fopen("/proc/net/stat/nf_conntrack", "r");
5085
+ if(fp) {
5086
+ if(fseek(fp, 0, SEEK_SET) == -1) {
5087
+ error("Re-opening file /proc/net/stat/nf_conntrack.");
5088
+ fclose(fp);
5089
+ fp = NULL;
5090
+ }
5091
+ }
5092
+
5093
if(!fp) {
5003
- error("Cannot read /proc/net/stat/nf_conntrack.");
5004
- return 1;
5094
+ fp = fopen("/proc/net/stat/nf_conntrack", "r");
5095
+ if(!fp) {
5096
+ error("Cannot read /proc/net/stat/nf_conntrack.");
5097
+ return 1;
5098
+ }
5099
}
5100
5101
// read and discard the header
@@ -5025,24 +5119,23 @@ int do_proc_net_stat_conntrack() {
5119
if(!aentries) aentries = tentries;
5120
5121
// sum all the cpus together
5028
- asearched += tsearched; // conntrack.search
5029
- afound += tfound; // conntrack.search
5030
- anew += tnew; // conntrack.new
5031
- ainvalid += tinvalid; // conntrack.new
5032
- aignore += tignore; // conntrack.new
5033
- adelete += tdelete; // conntrack.changes
5034
- adelete_list += tdelete_list; // conntrack.changes
5035
- ainsert += tinsert; // conntrack.changes
5036
- ainsert_failed += tinsert_failed; // conntrack.errors
5037
- adrop += tdrop; // conntrack.errors
5038
- aearly_drop += tearly_drop; // conntrack.errors
5039
- aicmp_error += ticmp_error; // conntrack.errors
5040
- aexpect_new += texpect_new; // conntrack.expect
5041
- aexpect_create += texpect_create; // conntrack.expect
5042
- aexpect_delete += texpect_delete; // conntrack.expect
5043
- asearch_restart += tsearch_restart; // conntrack.search
5122
+ asearched += tsearched; // conntrack.search
5123
+ afound += tfound; // conntrack.search
5124
+ anew += tnew; // conntrack.new
5125
+ ainvalid += tinvalid; // conntrack.new
5126
+ aignore += tignore; // conntrack.new
5127
+ adelete += tdelete; // conntrack.changes
5128
+ adelete_list += tdelete_list; // conntrack.changes
5129
+ ainsert += tinsert; // conntrack.changes
5130
+ ainsert_failed += tinsert_failed; // conntrack.errors
5131
+ adrop += tdrop; // conntrack.errors
5132
+ aearly_drop += tearly_drop; // conntrack.errors
5133
+ aicmp_error += ticmp_error; // conntrack.errors
5134
+ aexpect_new += texpect_new; // conntrack.expect
5135
+ aexpect_create += texpect_create; // conntrack.expect
5136
+ aexpect_delete += texpect_delete; // conntrack.expect
5137
+ asearch_restart += tsearch_restart; // conntrack.search
5138
}
5045
- fclose(fp);
5139
5140
RRD_STATS *st;
5141
@@ -5170,6 +5263,7 @@ int do_proc_net_stat_conntrack() {
5263
5264
int do_proc_net_ip_vs_stats() {
5265
static int do_bandwidth = -1, do_sockets = -1, do_packets = -1;
5266
+ static FILE *fp = NULL;
5267
5268
if(do_bandwidth == -1) do_bandwidth = config_get_boolean("plugin:proc:/proc/net/ip_vs_stats", "IPVS bandwidth", 1);
5269
if(do_sockets == -1) do_sockets = config_get_boolean("plugin:proc:/proc/net/ip_vs_stats", "IPVS connections", 1);
@@ -5177,10 +5271,20 @@ int do_proc_net_ip_vs_stats() {
5271
5272
char buffer[MAX_PROC_NET_IPVS_LINE+1] = "";
5273
5180
- FILE *fp = fopen("/proc/net/ip_vs_stats", "r");
5274
+ if(fp) {
5275
+ if(fseek(fp, 0, SEEK_SET) == -1) {
5276
+ error("Re-opening file /proc/net/ip_vs_stats.");
5277
+ fclose(fp);
5278
+ fp = NULL;
5279
+ }
5280
+ }
5281
+
5282
if(!fp) {
5182
- error("Cannot read /proc/net/ip_vs_stats.");
5183
- return 1;
5283
+ fp = fopen("/proc/net/ip_vs_stats", "r");
5284
+ if(!fp) {
5285
+ error("Cannot read /proc/net/ip_vs_stats.");
5286
+ return 1;
5287
+ }
5288
}
5289
5290
// read the discard the 2 header lines
@@ -5212,8 +5316,6 @@ int do_proc_net_ip_vs_stats() {
5316
}
5317
if(r != 5) error("Cannot read /proc/net/ip_vs_stats. Expected 5 params, read %d.", r);
5318
5215
- fclose(fp);
5216
-
5319
RRD_STATS *st;
5320
5321
// --------------------------------------------------------------------
@@ -5270,20 +5372,31 @@ int do_proc_net_ip_vs_stats() {
5372
5373
int do_proc_stat() {
5374
static int do_cpu = -1, do_cpu_cores = -1, do_interrupts = -1, do_context = -1, do_forks = -1, do_processes = -1;
5375
+ static FILE *fp = NULL;
5376
5274
- if(do_cpu == -1) do_cpu = config_get_boolean("plugin:proc:/proc/stat", "cpu utilization", 1);
5377
+ if(do_cpu == -1) do_cpu = config_get_boolean("plugin:proc:/proc/stat", "cpu utilization", 1);
5378
if(do_cpu_cores == -1) do_cpu_cores = config_get_boolean("plugin:proc:/proc/stat", "per cpu core utilization", 1);
5379
if(do_interrupts == -1) do_interrupts = config_get_boolean("plugin:proc:/proc/stat", "cpu interrupts", 1);
5380
if(do_context == -1) do_context = config_get_boolean("plugin:proc:/proc/stat", "context switches", 1);
5278
- if(do_forks == -1) do_forks = config_get_boolean("plugin:proc:/proc/stat", "processes started", 1);
5381
+ if(do_forks == -1) do_forks = config_get_boolean("plugin:proc:/proc/stat", "processes started", 1);
5382
if(do_processes == -1) do_processes = config_get_boolean("plugin:proc:/proc/stat", "processes running", 1);
5383
5384
char buffer[MAX_PROC_STAT_LINE+1] = "";
5385
5283
- FILE *fp = fopen("/proc/stat", "r");
5386
+ if(fp) {
5387
+ if(fseek(fp, 0, SEEK_SET) == -1) {
5388
+ error("Re-opening file /proc/stat.");
5389
+ fclose(fp);
5390
+ fp = NULL;
5391
+ }
5392
+ }
5393
+
5394
if(!fp) {
5285
- error("Cannot read /proc/stat.");
5286
- return 1;
5395
+ fp = fopen("/proc/stat", "r");
5396
+ if(!fp) {
5397
+ error("Cannot read /proc/stat.");
5398
+ return 1;
5399
+ }
5400
}
5401
5402
unsigned long long processes = 0, running = 0 , blocked = 0;
@@ -5433,7 +5546,6 @@ int do_proc_stat() {
5546
blocked = value;
5547
}
5548
}
5436
- fclose(fp);
5549
5550
// --------------------------------------------------------------------
5551
@@ -5479,6 +5591,7 @@ int do_proc_stat() {
5591
5592
int do_proc_meminfo() {
5593
static int do_ram = -1, do_swap = -1, do_hwcorrupt = -1, do_committed = -1, do_writeback = -1, do_kernel = -1, do_slab = -1;
5594
+ static FILE *fp = NULL;
5595
5596
if(do_ram == -1) do_ram = config_get_boolean("plugin:proc:/proc/meminfo", "system ram", 1);
5597
if(do_swap == -1) do_swap = config_get_boolean("plugin:proc:/proc/meminfo", "system swap", 1);
@@ -5490,10 +5603,20 @@ int do_proc_meminfo() {
5603
5604
char buffer[MAX_PROC_MEMINFO_LINE+1] = "";
5605
5493
- FILE *fp = fopen("/proc/meminfo", "r");
5606
+ if(fp) {
5607
+ if(fseek(fp, 0, SEEK_SET) == -1) {
5608
+ error("Re-opening file /proc/meminfo.");
5609
+ fclose(fp);
5610
+ fp = NULL;
5611
+ }
5612
+ }
5613
+
5614
if(!fp) {
5495
- error("Cannot read /proc/meminfo.");
5496
- return 1;
5615
+ fp = fopen("/proc/meminfo", "r");
5616
+ if(!fp) {
5617
+ error("Cannot read /proc/meminfo.");
5618
+ return 1;
5619
+ }
5620
}
5621
5622
int hwcorrupted = 0;
@@ -5565,7 +5688,6 @@ int do_proc_meminfo() {
5688
else if(!DirectMap4k && strcmp(name, "DirectMap4k") == 0) DirectMap4k = value;
5689
else if(!DirectMap2M && strcmp(name, "DirectMap2M") == 0) DirectMap2M = value;
5690
}
5568
- fclose(fp);
5691
5692
RRD_STATS *st;
5693
@@ -5720,17 +5842,28 @@ int do_proc_meminfo() {
5842
5843
int do_proc_vmstat() {
5844
static int do_swapio = -1, do_io = -1, do_pgfaults = -1;
5845
+ static FILE *fp = NULL;
5846
5724
- if(do_swapio == -1) do_swapio = config_get_boolean("plugin:proc:/proc/vmstat", "swap i/o", 1);
5725
- if(do_io == -1) do_io = config_get_boolean("plugin:proc:/proc/vmstat", "disk i/o", 1);
5847
+ if(do_swapio == -1) do_swapio = config_get_boolean("plugin:proc:/proc/vmstat", "swap i/o", 1);
5848
+ if(do_io == -1) do_io = config_get_boolean("plugin:proc:/proc/vmstat", "disk i/o", 1);
5849
if(do_pgfaults == -1) do_pgfaults = config_get_boolean("plugin:proc:/proc/vmstat", "memory page faults", 1);
5850
5851
char buffer[MAX_PROC_VMSTAT_LINE+1] = "";
5852
5730
- FILE *fp = fopen("/proc/vmstat", "r");
5853
+ if(fp) {
5854
+ if(fseek(fp, 0, SEEK_SET) == -1) {
5855
+ error("Re-opening file /proc/vmstat.");
5856
+ fclose(fp);
5857
+ fp = NULL;
5858
+ }
5859
+ }
5860
+
5861
if(!fp) {
5732
- error("Cannot read /proc/vmstat.");
5733
- return 1;
5862
+ fp = fopen("/proc/vmstat", "r");
5863
+ if(!fp) {
5864
+ error("Cannot read /proc/vmstat.");
5865
+ return 1;
5866
+ }
5867
}
5868
5869
unsigned long long nr_free_pages = 0, nr_inactive_anon = 0, nr_active_anon = 0, nr_inactive_file = 0, nr_active_file = 0, nr_unevictable = 0, nr_mlock = 0,
@@ -5855,7 +5988,6 @@ int do_proc_vmstat() {
5988
else if(!thp_collapse_alloc_failed && strcmp(name, "thp_collapse_alloc_failed") == 0) thp_collapse_alloc_failed = value;
5989
else if(!thp_split && strcmp(name, "thp_split") == 0) thp_split = value;
5990
}
5858
- fclose(fp);
5991
5992
RRD_STATS *st;
5993
@@ -5938,7 +6070,7 @@ void *proc_main(void *ptr)
6070
config_get_boolean("plugin:proc:/proc/net/dev", "interface fireqos_monitor", 0);
6071
6072
// when ZERO, attempt to do it
5941
- int vdo_proc_net_dev = !config_get_boolean("plugin:proc", "/proc/net/dev", 1);
6073
+ int vdo_proc_net_dev = !config_get_boolean("plugin:proc", "/proc/net/dev", 1);
6074
int vdo_proc_diskstats = !config_get_boolean("plugin:proc", "/proc/diskstats", 1);
6075
int vdo_proc_net_snmp = !config_get_boolean("plugin:proc", "/proc/net/snmp", 1);
6076
int vdo_proc_net_netstat = !config_get_boolean("plugin:proc", "/proc/net/netstat", 1);
@@ -5958,15 +6090,15 @@ void *proc_main(void *ptr)
6090
for(;1;) {
6091
6092
// BEGIN -- the job to be done
5961
- if(!vdo_proc_net_dev) vdo_proc_net_dev = do_proc_net_dev(usec);
5962
- if(!vdo_proc_diskstats) vdo_proc_diskstats = do_proc_diskstats(usec);
5963
- if(!vdo_proc_net_snmp) vdo_proc_net_snmp = do_proc_net_snmp(usec);
5964
- if(!vdo_proc_net_netstat) vdo_proc_net_netstat = do_proc_net_netstat(usec);
6093
+ if(!vdo_proc_net_dev) vdo_proc_net_dev = do_proc_net_dev(usec);
6094
+ if(!vdo_proc_diskstats) vdo_proc_diskstats = do_proc_diskstats(usec);
6095
+ if(!vdo_proc_net_snmp) vdo_proc_net_snmp = do_proc_net_snmp(usec);
6096
+ if(!vdo_proc_net_netstat) vdo_proc_net_netstat = do_proc_net_netstat(usec);
6097
if(!vdo_proc_net_stat_conntrack) vdo_proc_net_stat_conntrack = do_proc_net_stat_conntrack(usec);
6098
if(!vdo_proc_net_ip_vs_stats) vdo_proc_net_ip_vs_stats = do_proc_net_ip_vs_stats(usec);
5967
- if(!vdo_proc_stat) vdo_proc_stat = do_proc_stat(usec);
5968
- if(!vdo_proc_meminfo) vdo_proc_meminfo = do_proc_meminfo(usec);
5969
- if(!vdo_proc_vmstat) vdo_proc_vmstat = do_proc_vmstat(usec);
6099
+ if(!vdo_proc_stat) vdo_proc_stat = do_proc_stat(usec);
6100
+ if(!vdo_proc_meminfo) vdo_proc_meminfo = do_proc_meminfo(usec);
6101
+ if(!vdo_proc_vmstat) vdo_proc_vmstat = do_proc_vmstat(usec);
6102
// END -- the job is done
6103
6104
// find the time to sleep in order to wait exactly update_every seconds
@@ -6944,7 +7076,25 @@ void *pluginsd_main(void *ptr)
7076
// ----------------------------------------------------------------------------
7077
// main and related functions
7078
6947
-pthread_t *p_proc = NULL, *p_tc = NULL, *p_jitter = NULL, *p_pluginsd = NULL, *p_checks = NULL;
7079
+struct netdata_static_thread {
7080
+ char *name;
7081
+
7082
+ char *config_section;
7083
+ char *config_name;
7084
+
7085
+ pthread_t *thread;
7086
+ void *(*start_routine) (void *);
7087
+};
7088
+
7089
+struct netdata_static_thread static_threads[] = {
7090
+ {"tc", "plugins", "tc", NULL, tc_main},
7091
+ {"idlejitter", "plugins", "idlejitter", NULL, cpuidlejitter_main},
7092
+ {"proc", "plugins", "proc", NULL, proc_main},
7093
+ {"plugins.d", NULL, NULL, NULL, pluginsd_main},
7094
+ {"check", "plugins", "checks", NULL, checks_main},
7095
+ {"web", NULL, NULL, NULL, socket_listen_main},
7096
+ {NULL, NULL, NULL, NULL, NULL}
7097
+};
7098
7099
void kill_childs()
7100
{
@@ -6956,69 +7106,86 @@ void kill_childs()
7106
pthread_cancel(w->thread);
7107
pthread_join(w->thread, NULL);
7108
}
6959
-
6960
- if(p_proc) {
6961
- debug(D_EXIT, "Stopping proc thread");
6962
- pthread_cancel(*p_proc);
6963
- pthread_join(*p_proc, NULL);
6964
- p_proc = NULL;
6965
- }
7109
6967
- if(p_jitter) {
6968
- debug(D_EXIT, "Stopping idlejitter thread");
6969
- pthread_cancel(*p_jitter);
6970
- pthread_join(*p_jitter, NULL);
6971
- p_jitter = NULL;
7110
+ int i;
7111
+ for (i = 0; static_threads[i].name != NULL ; i++) {
7112
+ if(static_threads[i].thread) {
7113
+ debug(D_EXIT, "Stopping %s thread", static_threads[i].name);
7114
+ pthread_cancel(*static_threads[i].thread);
7115
+ pthread_join(*static_threads[i].thread, NULL);
7116
+ static_threads[i].thread = NULL;
7117
+ }
7118
}
7119
6974
- if(p_checks) {
6975
- debug(D_EXIT, "Stopping self-checks thread");
6976
- pthread_cancel(*p_checks);
6977
- pthread_join(*p_checks, NULL);
6978
- p_checks = NULL;
7120
+ if(tc_child_pid) {
7121
+ debug(D_EXIT, "Killing tc-qos-helper procees");
7122
+ kill(tc_child_pid, SIGTERM);
7123
+ waitid(tc_child_pid, 0, &info, WEXITED);
7124
}
7125
+ tc_child_pid = 0;
7126
6981
- if(p_tc) {
6982
- if(tc_child_pid) {
6983
- debug(D_EXIT, "Killing tc-qos-helper procees");
6984
- kill(tc_child_pid, SIGTERM);
6985
- waitid(tc_child_pid, 0, &info, WEXITED);
6986
- }
6987
- tc_child_pid = 0;
7127
+ struct plugind *cd;
7128
+ for(cd = pluginsd_root ; cd ; cd = cd->next) {
7129
+ debug(D_EXIT, "Stopping %s plugin thread", cd->id);
7130
+ pthread_cancel(cd->thread);
7131
+ pthread_join(cd->thread, NULL);
7132
6989
- debug(D_EXIT, "Stopping tc plugin thread");
6990
- pthread_cancel(*p_tc);
6991
- pthread_join(*p_tc, NULL);
6992
- p_tc = NULL;
7133
+ if(cd->pid && !cd->obsolete) {
7134
+ debug(D_EXIT, "killing %s plugin process", cd->id);
7135
+ kill(cd->pid, SIGTERM);
7136
+ waitid(cd->pid, 0, &info, WEXITED);
7137
+ }
7138
}
7139
6995
- if(p_pluginsd) {
6996
- struct plugind *cd;
6997
- for(cd = pluginsd_root ; cd ; cd = cd->next) {
6998
- debug(D_EXIT, "Stopping %s plugin thread", cd->id);
6999
- pthread_cancel(cd->thread);
7000
- pthread_join(cd->thread, NULL);
7140
+ debug(D_EXIT, "All threads/childs stopped.");
7141
+}
7142
7002
- if(cd->pid && !cd->obsolete) {
7003
- debug(D_EXIT, "killing %s plugin process", cd->id);
7004
- kill(cd->pid, SIGTERM);
7005
- waitid(cd->pid, 0, &info, WEXITED);
7006
- }
7143
+void process_childs(int wait)
7144
+{
7145
+ siginfo_t info;
7146
+ int options = WEXITED;
7147
+ if(!wait) options |= WNOHANG;
7148
+
7149
+ info.si_pid = 0;
7150
+ while(waitid(P_ALL, 0, &info, options) == 0) {
7151
+ if(!info.si_pid) break;
7152
+ switch(info.si_code) {
7153
+ case CLD_EXITED:
7154
+ error("pid %d exited with code %d.", info.si_pid, info.si_status);
7155
+ break;
7156
+
7157
+ case CLD_KILLED:
7158
+ error("pid %d killed by signal %d.", info.si_pid, info.si_status);
7159
+ break;
7160
+
7161
+ case CLD_DUMPED:
7162
+ error("pid %d core dumped by signal %d.", info.si_pid, info.si_status);
7163
+ break;
7164
+
7165
+ case CLD_STOPPED:
7166
+ error("pid %d stopped by signal %d.", info.si_pid, info.si_status);
7167
+ break;
7168
+
7169
+ case CLD_TRAPPED:
7170
+ error("pid %d trapped by signal %d.", info.si_pid, info.si_status);
7171
+ break;
7172
+
7173
+ case CLD_CONTINUED:
7174
+ error("pid %d continued by signal %d.", info.si_pid, info.si_status);
7175
+ break;
7176
+
7177
+ default:
7178
+ error("pid %d gave us a SIGCHLD with code %d and status %d.", info.si_pid, info.si_code, info.si_status);
7179
+ break;
7180
}
7181
7009
- debug(D_EXIT, "Stopping plugin manager thread");
7010
- pthread_cancel(*p_pluginsd);
7011
- pthread_join(*p_pluginsd, NULL);
7012
- p_pluginsd = NULL;
7182
+ // prevent an infinite loop
7183
+ info.si_pid = 0;
7184
}
7014
-
7015
- debug(D_EXIT, "All threads/childs stopped.");
7185
}
7186
7187
void sig_handler(int signo)
7188
{
7020
- siginfo_t info;
7021
-
7189
switch(signo) {
7190
case SIGTERM:
7191
case SIGQUIT:
@@ -7034,9 +7201,8 @@ void sig_handler(int signo)
7201
signal(SIGHUP, SIG_IGN);
7202
signal(SIGINT, SIG_IGN);
7203
kill_childs();
7204
+ process_childs(0);
7205
rrd_stats_free_all();
7038
- debug(D_EXIT, "Waiting for any child exits...");
7039
- while(waitid(P_ALL, 0, &info, WEXITED|WNOHANG) == 0) if(!info.si_pid) break;
7206
//unlink("/var/run/netdata.pid");
7207
info("NetData exiting. Bye bye...");
7208
exit(1);
@@ -7049,38 +7215,7 @@ void sig_handler(int signo)
7215
7216
case SIGCHLD:
7217
info("Received SIGCHLD (signal %d).", signo);
7052
- while(waitid(P_ALL, 0, &info, WEXITED|WNOHANG) == 0) {
7053
- if(!info.si_pid) break;
7054
- switch(info.si_code) {
7055
- case CLD_EXITED:
7056
- error("pid %d exited with code %d.", info.si_pid, info.si_status);
7057
- break;
7058
-
7059
- case CLD_KILLED:
7060
- error("pid %d killed by signal %d.", info.si_pid, info.si_status);
7061
- break;
7062
-
7063
- case CLD_DUMPED:
7064
- error("pid %d core dumped by signal %d.", info.si_pid, info.si_status);
7065
- break;
7066
-
7067
- case CLD_STOPPED:
7068
- error("pid %d stopped by signal %d.", info.si_pid, info.si_status);
7069
- break;
7070
-
7071
- case CLD_TRAPPED:
7072
- error("pid %d trapped by signal %d.", info.si_pid, info.si_status);
7073
- break;
7074
-
7075
- case CLD_CONTINUED:
7076
- error("pid %d continued by signal %d.", info.si_pid, info.si_status);
7077
- break;
7078
-
7079
- default:
7080
- error("pid %d gave us a SIGCHLD with code %d and status %d.", info.si_pid, info.si_code, info.si_status);
7081
- break;
7082
- }
7083
- }
7218
+ process_childs(0);
7219
break;
7220
7221
default:
@@ -7305,7 +7440,7 @@ int become_daemon(int close_all_files, const char *input, const char *output, co
7440
if(fd >= 0) {
7441
char b[100];
7442
sprintf(b, "%d\n", getpid());
7308
- write(fd, b, strlen(b));
7443
+ i = write(fd, b, strlen(b));
7444
close(fd);
7445
}
7446
}
@@ -7634,48 +7769,27 @@ int main(int argc, char **argv)
7769
// catch all signals
7770
for (i = 1 ; i < 65 ;i++) if(i != SIGSEGV && i != SIGFPE) signal(i, sig_handler);
7771
7637
- // spawn childs to collect data
7638
- if(config_get_boolean("plugins", "tc", 1)) {
7639
- p_tc = malloc(sizeof(pthread_t));
7640
- if(pthread_create(p_tc, NULL, tc_main, NULL))
7641
- error("failed to create new thread for tc.");
7642
- else if(pthread_detach(*p_tc))
7643
- error("Cannot request detach of newly created tc thread.");
7644
- }
7645
-
7646
- if(config_get_boolean("plugins", "idlejitter", 1)) {
7647
- p_jitter = malloc(sizeof(pthread_t));
7648
- if(pthread_create(p_jitter, NULL, cpuidlejitter_main, NULL))
7649
- error("failed to create new thread for idlejitter.");
7650
- else if(pthread_detach(*p_jitter))
7651
- error("Cannot request detach of newly created idlejitter thread.");
7652
- }
7653
-
7654
- if(config_get_boolean("plugins", "proc", 1)) {
7655
- p_proc = malloc(sizeof(pthread_t));
7656
- if(pthread_create(p_proc, NULL, proc_main, NULL))
7657
- error("failed to create new thread for proc.");
7658
- else if(pthread_detach(*p_proc))
7659
- error("Cannot request detach of newly created proc thread.");
7660
- }
7661
-
7662
- p_pluginsd = malloc(sizeof(pthread_t));
7663
- if(pthread_create(p_pluginsd, NULL, pluginsd_main, NULL))
7664
- error("failed to create new thread for plugins.d.");
7665
- else if(pthread_detach(*p_pluginsd))
7666
- error("Cannot request detach of newly created plugins.d thread.");
7667
-
7668
- if(config_get_boolean("plugins", "checks", (debug_flags & D_CHECKS)?1:0)) {
7669
- p_checks = malloc(sizeof(pthread_t));
7670
- if(pthread_create(p_checks, NULL, checks_main, NULL))
7671
- error("failed to create new thread for checks.");
7672
- else if(pthread_detach(*p_checks))
7673
- error("Cannot request detach of newly created checks thread.");
7772
+ for (i = 0; static_threads[i].name != NULL ; i++) {
7773
+ struct netdata_static_thread *st = &static_threads[i];
7774
+ int doit = 1;
7775
+
7776
+ if(st->config_name) doit = config_get_boolean(st->config_section, st->config_name, doit);
7777
+
7778
+ if(doit) {
7779
+ st->thread = malloc(sizeof(pthread_t));
7780
+
7781
+ if(pthread_create(st->thread, NULL, st->start_routine, NULL))
7782
+ error("failed to create new thread for %s.", st->name);
7783
+
7784
+ else if(pthread_detach(*st->thread))
7785
+ error("Cannot request detach of newly created %s thread.", st->name);
7786
+ }
7787
}
7788
7789
// the main process - the web server listener
7790
// this never ends
7678
- socket_listen_main(NULL);
7791
+ // socket_listen_main(NULL);
7792
+ while(1) process_childs(1);
7793
7794
exit(0);
7795
}