cgroups are now on their own thread; cgroup names are controlled by plugins.d/cgroup-name.sh which uses /etc/netdata/cgroups-names.conf to pick up unique ID (chart names) for the containers
Costa Tsaousis (ktsaou) committed
Apr 25, 2016 at 01:33 UTC
b1dfe19b4f139a7e213d078dab8dd430040851b2
9 files changed
+182
-47
plugins.d/Makefile.am
+1
@@ -8,6 +8,7 @@ dist_plugins_DATA = \
8
$(NULL)
9
10
dist_plugins_SCRIPTS = \
11
+ cgroup-name.sh \
12
charts.d.dryrun-helper.sh \
13
charts.d.plugin \
14
node.d.plugin \
plugins.d/cgroup-name.sh
new
+38
@@ -0,0 +1,38 @@
1
+#!/bin/bash
2
+
3
+export PATH="${PATH}:/sbin:/usr/sbin:/usr/local/sbin"
4
+
5
+NETDATA_CONFIG_DIR="${NETDATA_CONFIG_DIR-/etc/netdata}"
6
+CONFIG="${NETDATA_CONFIG_DIR}/cgroups-names.conf"
7
+CGROUP="${1}"
8
+NAME=
9
+
10
+if [ -z "${CGROUP}" ]
11
+ then
12
+ echo >&2 "${0}: called without a cgroup name. Nothing to do."
13
+ exit 1
14
+fi
15
+
16
+if [ -f "${CONFIG}" ]
17
+ then
18
+ NAME="$(cat "${CONFIG}" | grep "^${CGROUP}" | cut -d ' ' -f 2)"
19
+ if [ -z "${NAME}" ]
20
+ then
21
+ echo >&2 "${0}: cannot find cgroup '${CGROUP}' in '${CONFIG}'."
22
+ fi
23
+else
24
+ echo >&2 "${0}: configuration file '${CONFIG}' is not available."
25
+fi
26
+
27
+if [ -z "${NAME}" ]
28
+ then
29
+ if [ ${#CGROUP} -gt 12 ]
30
+ then
31
+ NAME="${CGROUP:0:12}"
32
+ else
33
+ NAME="${CGROUP}"
34
+ fi
35
+fi
36
+
37
+echo >&2 "${0}: cgroup '${CGROUP}' is named as '${NAME}'"
38
+echo "${NAME}"
src/apps_plugin.c
+2
-8
@@ -2387,12 +2387,6 @@ void parse_args(int argc, char **argv)
2387
}
2388
}
2389
2390
-unsigned long long sutime() {
2391
- struct timeval now;
2392
- gettimeofday(&now, NULL);
2393
- return now.tv_sec * 1000000ULL + now.tv_usec;
2394
-}
2395
-
2390
int main(int argc, char **argv)
2391
{
2392
// debug_flags = D_PROCFILE;
@@ -2456,11 +2450,11 @@ int main(int argc, char **argv)
2450
for(;1; counter++) {
2451
#ifndef PROFILING_MODE
2452
// delay until it is our time to run
2459
- while((sunow = sutime()) < sunext)
2453
+ while((sunow = timems()) < sunext)
2454
usleep((useconds_t)(sunext - sunow));
2455
2456
// find the next time we need to run
2463
- while(sutime() > sunext)
2457
+ while(timems() > sunext)
2458
sunext += update_every * 1000000ULL;
2459
#endif /* PROFILING_MODE */
2460
src/common.c
+7
@@ -20,6 +20,13 @@
20
char *global_host_prefix = "";
21
int enable_ksm = 1;
22
23
+// time(NULL) in milliseconds
24
+unsigned long long timems(void) {
25
+ struct timeval now;
26
+ gettimeofday(&now, NULL);
27
+ return now.tv_sec * 1000000ULL + now.tv_usec;
28
+}
29
+
30
unsigned char netdata_map_chart_names[256] = {
31
[0] = '\0', //
32
[1] = '_', //
src/common.h
+2
@@ -37,6 +37,8 @@ extern void get_HZ(void);
37
38
extern pid_t gettid(void);
39
40
+extern unsigned long long timems(void);
41
+
42
/* fix for alpine linux */
43
#ifndef RUSAGE_THREAD
44
#ifdef RUSAGE_CHILDREN
src/main.c
+3
-1
@@ -36,7 +36,8 @@
36
#include "plugin_nfacct.h"
37
38
#include "main.h"
39
-#include "../config.h"
39
+
40
+extern void *cgroups_main(void *ptr);
41
42
int netdata_exit = 0;
43
@@ -84,6 +85,7 @@ struct netdata_static_thread static_threads[] = {
85
{"tc", "plugins", "tc", 1, NULL, NULL, tc_main},
86
{"idlejitter", "plugins", "idlejitter", 1, NULL, NULL, cpuidlejitter_main},
87
{"proc", "plugins", "proc", 1, NULL, NULL, proc_main},
88
+ {"cgroups", "plugins", "cgroups", 1, NULL, NULL, cgroups_main},
89
90
#ifdef INTERNAL_PLUGIN_NFACCT
91
// nfacct requires root access
src/plugin_proc.c
+19
-35
@@ -15,12 +15,6 @@
15
#include "plugin_proc.h"
16
#include "main.h"
17
18
-unsigned long long sutime() {
19
- struct timeval now;
20
- gettimeofday(&now, NULL);
21
- return now.tv_sec * 1000000ULL + now.tv_usec;
22
-}
23
-
18
void *proc_main(void *ptr)
19
{
20
if(ptr) { ; }
@@ -58,7 +52,6 @@ void *proc_main(void *ptr)
52
int vdo_proc_loadavg = !config_get_boolean("plugin:proc", "/proc/loadavg", 1);
53
int vdo_sys_kernel_mm_ksm = !config_get_boolean("plugin:proc", "/sys/kernel/mm/ksm", 1);
54
int vdo_cpu_netdata = !config_get_boolean("plugin:proc", "netdata server resources", 1);
61
- int vdo_sys_fs_cgroup = !config_get_boolean("plugin:proc", "cgroups", 1);
55
56
// keep track of the time each module was called
57
unsigned long long sutime_proc_net_dev = 0ULL;
@@ -78,7 +71,6 @@ void *proc_main(void *ptr)
71
unsigned long long sutime_proc_softirqs = 0ULL;
72
unsigned long long sutime_proc_loadavg = 0ULL;
73
unsigned long long sutime_sys_kernel_mm_ksm = 0ULL;
81
- unsigned long long sutime_sys_fs_cgroup = 0ULL;
74
75
// the next time we will run - aligned properly
76
unsigned long long sunext = (time(NULL) - (time(NULL) % rrd_update_every) + rrd_update_every) * 1000000ULL;
@@ -90,11 +82,11 @@ void *proc_main(void *ptr)
82
if(unlikely(netdata_exit)) break;
83
84
// delay until it is our time to run
93
- while((sunow = sutime()) < sunext)
85
+ while((sunow = timems()) < sunext)
86
usleep((useconds_t)(sunext - sunow));
87
88
// find the next time we need to run
97
- while(sutime() > sunext)
89
+ while(timems() > sunext)
90
sunext += rrd_update_every * 1000000ULL;
91
92
if(unlikely(netdata_exit)) break;
@@ -104,7 +96,7 @@ void *proc_main(void *ptr)
96
if(!vdo_sys_kernel_mm_ksm) {
97
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_sys_kernel_mm_ksm().");
98
107
- sunow = sutime();
99
+ sunow = timems();
100
vdo_sys_kernel_mm_ksm = do_sys_kernel_mm_ksm(rrd_update_every, (sutime_sys_kernel_mm_ksm > 0)?sunow - sutime_sys_kernel_mm_ksm:0ULL);
101
sutime_sys_kernel_mm_ksm = sunow;
102
}
@@ -112,7 +104,7 @@ void *proc_main(void *ptr)
104
105
if(!vdo_proc_loadavg) {
106
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_loadavg().");
115
- sunow = sutime();
107
+ sunow = timems();
108
vdo_proc_loadavg = do_proc_loadavg(rrd_update_every, (sutime_proc_loadavg > 0)?sunow - sutime_proc_loadavg:0ULL);
109
sutime_proc_loadavg = sunow;
110
}
@@ -120,7 +112,7 @@ void *proc_main(void *ptr)
112
113
if(!vdo_proc_interrupts) {
114
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_interrupts().");
123
- sunow = sutime();
115
+ sunow = timems();
116
vdo_proc_interrupts = do_proc_interrupts(rrd_update_every, (sutime_proc_interrupts > 0)?sunow - sutime_proc_interrupts:0ULL);
117
sutime_proc_interrupts = sunow;
118
}
@@ -128,7 +120,7 @@ void *proc_main(void *ptr)
120
121
if(!vdo_proc_softirqs) {
122
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_softirqs().");
131
- sunow = sutime();
123
+ sunow = timems();
124
vdo_proc_softirqs = do_proc_softirqs(rrd_update_every, (sutime_proc_softirqs > 0)?sunow - sutime_proc_softirqs:0ULL);
125
sutime_proc_softirqs = sunow;
126
}
@@ -136,7 +128,7 @@ void *proc_main(void *ptr)
128
129
if(!vdo_proc_sys_kernel_random_entropy_avail) {
130
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_sys_kernel_random_entropy_avail().");
139
- sunow = sutime();
131
+ sunow = timems();
132
vdo_proc_sys_kernel_random_entropy_avail = do_proc_sys_kernel_random_entropy_avail(rrd_update_every, (sutime_proc_sys_kernel_random_entropy_avail > 0)?sunow - sutime_proc_sys_kernel_random_entropy_avail:0ULL);
133
sutime_proc_sys_kernel_random_entropy_avail = sunow;
134
}
@@ -144,7 +136,7 @@ void *proc_main(void *ptr)
136
137
if(!vdo_proc_net_dev) {
138
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_dev().");
147
- sunow = sutime();
139
+ sunow = timems();
140
vdo_proc_net_dev = do_proc_net_dev(rrd_update_every, (sutime_proc_net_dev > 0)?sunow - sutime_proc_net_dev:0ULL);
141
sutime_proc_net_dev = sunow;
142
}
@@ -152,7 +144,7 @@ void *proc_main(void *ptr)
144
145
if(!vdo_proc_diskstats) {
146
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_diskstats().");
155
- sunow = sutime();
147
+ sunow = timems();
148
vdo_proc_diskstats = do_proc_diskstats(rrd_update_every, (sutime_proc_diskstats > 0)?sunow - sutime_proc_diskstats:0ULL);
149
sutime_proc_diskstats = sunow;
150
}
@@ -160,7 +152,7 @@ void *proc_main(void *ptr)
152
153
if(!vdo_proc_net_snmp) {
154
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_snmp().");
163
- sunow = sutime();
155
+ sunow = timems();
156
vdo_proc_net_snmp = do_proc_net_snmp(rrd_update_every, (sutime_proc_net_snmp > 0)?sunow - sutime_proc_net_snmp:0ULL);
157
sutime_proc_net_snmp = sunow;
158
}
@@ -168,7 +160,7 @@ void *proc_main(void *ptr)
160
161
if(!vdo_proc_net_snmp6) {
162
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_snmp6().");
171
- sunow = sutime();
163
+ sunow = timems();
164
vdo_proc_net_snmp6 = do_proc_net_snmp6(rrd_update_every, (sutime_proc_net_snmp6 > 0)?sunow - sutime_proc_net_snmp6:0ULL);
165
sutime_proc_net_snmp6 = sunow;
166
}
@@ -176,7 +168,7 @@ void *proc_main(void *ptr)
168
169
if(!vdo_proc_net_netstat) {
170
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_netstat().");
179
- sunow = sutime();
171
+ sunow = timems();
172
vdo_proc_net_netstat = do_proc_net_netstat(rrd_update_every, (sutime_proc_net_netstat > 0)?sunow - sutime_proc_net_netstat:0ULL);
173
sutime_proc_net_netstat = sunow;
174
}
@@ -184,7 +176,7 @@ void *proc_main(void *ptr)
176
177
if(!vdo_proc_net_stat_conntrack) {
178
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_stat_conntrack().");
187
- sunow = sutime();
179
+ sunow = timems();
180
vdo_proc_net_stat_conntrack = do_proc_net_stat_conntrack(rrd_update_every, (sutime_proc_net_stat_conntrack > 0)?sunow - sutime_proc_net_stat_conntrack:0ULL);
181
sutime_proc_net_stat_conntrack = sunow;
182
}
@@ -192,7 +184,7 @@ void *proc_main(void *ptr)
184
185
if(!vdo_proc_net_ip_vs_stats) {
186
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_net_ip_vs_stats().");
195
- sunow = sutime();
187
+ sunow = timems();
188
vdo_proc_net_ip_vs_stats = do_proc_net_ip_vs_stats(rrd_update_every, (sutime_proc_net_ip_vs_stats > 0)?sunow - sutime_proc_net_ip_vs_stats:0ULL);
189
sutime_proc_net_ip_vs_stats = sunow;
190
}
@@ -200,7 +192,7 @@ void *proc_main(void *ptr)
192
193
if(!vdo_proc_net_stat_synproxy) {
194
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_net_stat_synproxy().");
203
- sunow = sutime();
195
+ sunow = timems();
196
vdo_proc_net_stat_synproxy = do_proc_net_stat_synproxy(rrd_update_every, (sutime_proc_net_stat_synproxy > 0)?sunow - sutime_proc_net_stat_synproxy:0ULL);
197
sutime_proc_net_stat_synproxy = sunow;
198
}
@@ -208,7 +200,7 @@ void *proc_main(void *ptr)
200
201
if(!vdo_proc_stat) {
202
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_stat().");
211
- sunow = sutime();
203
+ sunow = timems();
204
vdo_proc_stat = do_proc_stat(rrd_update_every, (sutime_proc_stat > 0)?sunow - sutime_proc_stat:0ULL);
205
sutime_proc_stat = sunow;
206
}
@@ -216,7 +208,7 @@ void *proc_main(void *ptr)
208
209
if(!vdo_proc_meminfo) {
210
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_meminfo().");
219
- sunow = sutime();
211
+ sunow = timems();
212
vdo_proc_meminfo = do_proc_meminfo(rrd_update_every, (sutime_proc_meminfo > 0)?sunow - sutime_proc_meminfo:0ULL);
213
sutime_proc_meminfo = sunow;
214
}
@@ -224,7 +216,7 @@ void *proc_main(void *ptr)
216
217
if(!vdo_proc_vmstat) {
218
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_vmstat().");
227
- sunow = sutime();
219
+ sunow = timems();
220
vdo_proc_vmstat = do_proc_vmstat(rrd_update_every, (sutime_proc_vmstat > 0)?sunow - sutime_proc_vmstat:0ULL);
221
sutime_proc_vmstat = sunow;
222
}
@@ -232,20 +224,12 @@ void *proc_main(void *ptr)
224
225
if(!vdo_proc_net_rpc_nfsd) {
226
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_rpc_nfsd().");
235
- sunow = sutime();
227
+ sunow = timems();
228
vdo_proc_net_rpc_nfsd = do_proc_net_rpc_nfsd(rrd_update_every, (sutime_proc_net_rpc_nfsd > 0)?sunow - sutime_proc_net_rpc_nfsd:0ULL);
229
sutime_proc_net_rpc_nfsd = sunow;
230
}
231
if(unlikely(netdata_exit)) break;
232
241
- if(!vdo_sys_fs_cgroup) {
242
- debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_sys_fs_cgroup().");
243
- sunow = sutime();
244
- vdo_sys_fs_cgroup = do_sys_fs_cgroup(rrd_update_every, (sutime_sys_fs_cgroup > 0)?sunow - sutime_sys_fs_cgroup:0ULL);
245
- sutime_sys_fs_cgroup = sunow;
246
- }
247
- if(unlikely(netdata_exit)) break;
248
-
233
// END -- the job is done
234
235
// --------------------------------------------------------------------
src/plugin_proc.h
-1
@@ -20,6 +20,5 @@ extern int do_proc_softirqs(int update_every, unsigned long long dt);
20
extern int do_sys_kernel_mm_ksm(int update_every, unsigned long long dt);
21
extern int do_proc_loadavg(int update_every, unsigned long long dt);
22
extern int do_proc_net_stat_synproxy(int update_every, unsigned long long dt);
23
-extern int do_sys_fs_cgroup(int update_every, unsigned long long dt);
23
24
#endif /* NETDATA_PLUGIN_PROC_H */
src/sys_fs_cgroup.c
+110
-2
@@ -14,6 +14,8 @@
14
#include "procfile.h"
15
#include "log.h"
16
#include "rrd.h"
17
+#include "main.h"
18
+#include "popen.h"
19
20
// ----------------------------------------------------------------------------
21
// cgroup globals
@@ -545,6 +547,33 @@ void read_all_cgroups(struct cgroup *cg) {
547
// ----------------------------------------------------------------------------
548
// add/remove/find cgroup objects
549
550
+#define CGROUP_NAME_LINE_MAX 1024
551
+
552
+void cgroup_get_name(struct cgroup *cg) {
553
+ pid_t cgroup_pid;
554
+ char buffer[CGROUP_NAME_LINE_MAX + 1];
555
+
556
+ snprintf(buffer, CGROUP_NAME_LINE_MAX, "exec %s '%s'",
557
+ config_get("plugin:cgroups", "script to get cgroup names", PLUGINS_DIR "/cgroup-name.sh"), cg->name);
558
+
559
+ FILE *fp = mypopen(buffer, &cgroup_pid);
560
+ if(!fp) {
561
+ error("CGROUP: Cannot popen(\"%s\", \"r\").", buffer);
562
+ return;
563
+ }
564
+ char *s = fgets(buffer, CGROUP_NAME_LINE_MAX, fp);
565
+ mypclose(fp, cgroup_pid);
566
+
567
+ if(s && *s && *s != '\n') {
568
+ trim(s);
569
+ netdata_fix_chart_name(s);
570
+ free(cg->name);
571
+ cg->name = strdup(s);
572
+ if(!cg->name)
573
+ fatal("CGROUP: Cannot allocate memory for name cgroup %s name: '%s'", cg->id, s);
574
+ }
575
+}
576
+
577
struct cgroup *cgroup_add(const char *id) {
578
if(cgroup_root_count >= cgroup_root_max) {
579
info("Maximum number of cgroups reached (%d). Not adding cgroup '%s'", cgroup_root_count, id);
@@ -595,6 +624,9 @@ struct cgroup *cgroup_add(const char *id) {
624
cgroup_root_count++;
625
626
// fprintf(stderr, " > added cgroup No %d, with id '%s' (%u) and name '%s'\n", cgroup_root_count, cg->id, cg->hash, cg->name);
627
+
628
+ // fix the name by calling the external script
629
+ cgroup_get_name(cg);
630
}
631
else fatal("Cannot allocate memory for cgroup '%s'", id);
632
@@ -808,9 +840,9 @@ void update_cgroup_charts(int update_every) {
840
if(cg->id[0] == '\0')
841
strcpy(type, "cgroup_host");
842
else if(cg->id[0] == '/')
811
- snprintf(type, RRD_ID_LENGTH_MAX, "cgroup%s", cg->id);
843
+ snprintf(type, RRD_ID_LENGTH_MAX, "cgroup_%s", cg->name);
844
else
813
- snprintf(type, RRD_ID_LENGTH_MAX, "cgroup_%s", cg->id);
845
+ snprintf(type, RRD_ID_LENGTH_MAX, "cgroup_%s", cg->name);
846
847
netdata_fix_chart_id(type);
848
@@ -1061,3 +1093,79 @@ int do_sys_fs_cgroup(int update_every, unsigned long long dt) {
1093
1094
return 0;
1095
}
1096
+
1097
+void *cgroups_main(void *ptr)
1098
+{
1099
+ if(ptr) { ; }
1100
+
1101
+ info("CGROUP Plugin thread created with task id %d", gettid());
1102
+
1103
+ if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
1104
+ error("Cannot set pthread cancel type to DEFERRED.");
1105
+
1106
+ if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
1107
+ error("Cannot set pthread cancel state to ENABLE.");
1108
+
1109
+ struct rusage thread;
1110
+
1111
+ // when ZERO, attempt to do it
1112
+ int vdo_sys_fs_cgroup = 0;
1113
+ int vdo_cpu_netdata = !config_get_boolean("plugin:cgroups", "netdata server resources", 1);
1114
+
1115
+ // keep track of the time each module was called
1116
+ unsigned long long sutime_sys_fs_cgroup = 0ULL;
1117
+
1118
+ // the next time we will run - aligned properly
1119
+ unsigned long long sunext = (time(NULL) - (time(NULL) % rrd_update_every) + rrd_update_every) * 1000000ULL;
1120
+ unsigned long long sunow;
1121
+
1122
+ RRDSET *stcpu_thread = NULL;
1123
+
1124
+ for(;1;) {
1125
+ if(unlikely(netdata_exit)) break;
1126
+
1127
+ // delay until it is our time to run
1128
+ while((sunow = timems()) < sunext)
1129
+ usleep((useconds_t)(sunext - sunow));
1130
+
1131
+ // find the next time we need to run
1132
+ while(timems() > sunext)
1133
+ sunext += rrd_update_every * 1000000ULL;
1134
+
1135
+ if(unlikely(netdata_exit)) break;
1136
+
1137
+ // BEGIN -- the job to be done
1138
+
1139
+ if(!vdo_sys_fs_cgroup) {
1140
+ debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_sys_fs_cgroup().");
1141
+ sunow = timems();
1142
+ vdo_sys_fs_cgroup = do_sys_fs_cgroup(rrd_update_every, (sutime_sys_fs_cgroup > 0)?sunow - sutime_sys_fs_cgroup:0ULL);
1143
+ sutime_sys_fs_cgroup = sunow;
1144
+ }
1145
+ if(unlikely(netdata_exit)) break;
1146
+
1147
+ // END -- the job is done
1148
+
1149
+ // --------------------------------------------------------------------
1150
+
1151
+ if(!vdo_cpu_netdata) {
1152
+ getrusage(RUSAGE_THREAD, &thread);
1153
+
1154
+ if(!stcpu_thread) stcpu_thread = rrdset_find("netdata.plugin_cgroups_cpu");
1155
+ if(!stcpu_thread) {
1156
+ stcpu_thread = rrdset_create("netdata", "plugin_cgroups_cpu", NULL, "proc.internal", NULL, "NetData CGroups Plugin CPU usage", "milliseconds/s", 131000, rrd_update_every, RRDSET_TYPE_STACKED);
1157
+
1158
+ rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRDDIM_INCREMENTAL);
1159
+ rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
1160
+ }
1161
+ else rrdset_next(stcpu_thread);
1162
+
1163
+ rrddim_set(stcpu_thread, "user" , thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec);
1164
+ rrddim_set(stcpu_thread, "system", thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec);
1165
+ rrdset_done(stcpu_thread);
1166
+ }
1167
+ }
1168
+
1169
+ pthread_exit(NULL);
1170
+ return NULL;
1171
+}