@cryptotaxi247 / netdata-1 / commits / 2bf3dac5c

synchronized exit for all threads

Costa Tsaousis (ktsaou) committed Dec 27, 2017 at 19:43 UTC 2bf3dac5cf2f290502451ccea1a8d02c6f35c04d
13 files changed +546 -389
CMakeLists.txt
+9 -1
@@ -63,7 +63,8 @@ set(NETDATA_LINUX_FILES
63 src/proc_uptime.c
64 src/sys_kernel_mm_ksm.c
65 src/sys_fs_cgroup.c
66 - src/sys_fs_btrfs.c)
66 + src/sys_fs_btrfs.c
67 + )
68
69 set(NETDATA_COMMON_FILES
70 src/adaptive_resortable_list.c
@@ -94,6 +95,7 @@ set(NETDATA_COMMON_FILES
95 src/health_json.c
96 src/health_log.c
97 src/inlined.h
98 + src/locks.c
99 src/locks.h
100 src/log.c
101 src/log.h
@@ -189,6 +191,8 @@ set(APPS_PLUGIN_SOURCE_FILES
191 src/clocks.c
192 src/clocks.h
193 src/inlined.h
194 + src/locks.c
195 + src/locks.h
196 src/log.c
197 src/log.h
198 src/procfile.c
@@ -205,6 +209,8 @@ set(FREEIPMI_PLUGIN_SOURCE_FILES
209 src/clocks.c
210 src/clocks.h
211 src/inlined.h
212 + src/locks.c
213 + src/locks.h
214 src/log.c
215 src/log.h
216 src/procfile.c
@@ -219,6 +225,8 @@ set(CGROUP_NETWORK_SOURCE_FILES
225 src/clocks.c
226 src/clocks.h
227 src/inlined.h
228 + src/locks.c
229 + src/locks.h
230 src/log.c
231 src/log.h
232 src/procfile.c
src/Makefile.am
+4
@@ -70,6 +70,7 @@ netdata_SOURCES = \
70 health_json.c \
71 health_log.c \
72 inlined.h \
73 + locks.c \
74 locks.h \
75 log.c \
76 log.h \
@@ -227,6 +228,7 @@ apps_plugin_SOURCES = \
228 clocks.c clocks.h \
229 common.c common.h \
230 inlined.h \
231 + locks.c locks.h \
232 log.c log.h \
233 procfile.c procfile.h \
234 web_buffer.c web_buffer.h \
@@ -248,6 +250,7 @@ freeipmi_plugin_SOURCES = \
250 clocks.c clocks.h \
251 common.c common.h \
252 inlined.h \
253 + locks.c locks.h \
254 log.c log.h \
255 procfile.c procfile.h \
256 $(NULL)
@@ -261,6 +264,7 @@ cgroup_network_SOURCES = \
264 clocks.c clocks.h \
265 common.c common.h \
266 inlined.h \
267 + locks.c locks.h \
268 log.c log.h \
269 procfile.c procfile.h \
270 popen.c popen.h \
src/locks.c new
+319
@@ -0,0 +1,319 @@
1 +#include "common.h"
2 +
3 +// ----------------------------------------------------------------------------
4 +// automatic thread cancelability management, based on locks
5 +
6 +static __thread int netdata_thread_first_cancelability = 0;
7 +static __thread int netdata_thread_lock_cancelability = 0;
8 +
9 +static inline void netdata_thread_disable_cancelability(void) {
10 + int old;
11 + int ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old);
12 + if(ret != 0)
13 + error("THREAD_CANCELABILITY: pthread_setcancelstate() returned error %d", ret);
14 + else {
15 + if(!netdata_thread_lock_cancelability)
16 + netdata_thread_first_cancelability = old;
17 +
18 + netdata_thread_lock_cancelability++;
19 + }
20 +}
21 +
22 +static inline void netdata_thread_enable_cancelability(void) {
23 + if(netdata_thread_lock_cancelability < 1) {
24 + error("THREAD_CANCELABILITY: netdata_thread_enable_cancelability(): oops! invalid thread cancelability count %d - results will be undefined - please report this!", netdata_thread_lock_cancelability);
25 + }
26 + else if(netdata_thread_lock_cancelability == 1) {
27 + int old = 1;
28 + int ret = pthread_setcancelstate(netdata_thread_first_cancelability, &old);
29 + if(ret != 0)
30 + error("THREAD_CANCELABILITY: pthread_setcancelstate() returned error %d", ret);
31 + else {
32 + if(!old)
33 + error("THREAD_CANCELABILITY: netdata_thread_enable_cancelability(): oops! old thread cancelability was changed, expected ENABLED, found DISABLED - please report this!");
34 + }
35 +
36 + netdata_thread_lock_cancelability = 0;
37 + }
38 + else
39 + netdata_thread_lock_cancelability--;
40 +}
41 +
42 +// ----------------------------------------------------------------------------
43 +// mutex
44 +
45 +int __netdata_mutex_init(netdata_mutex_t *mutex) {
46 + int ret = pthread_mutex_init(mutex, NULL);
47 + if(unlikely(ret != 0))
48 + error("MUTEX_LOCK: failed to initialize (code %d).", ret);
49 + return ret;
50 +}
51 +
52 +int __netdata_mutex_lock(netdata_mutex_t *mutex) {
53 + netdata_thread_disable_cancelability();
54 +
55 + int ret = pthread_mutex_lock(mutex);
56 + if(unlikely(ret != 0)) {
57 + netdata_thread_enable_cancelability();
58 + error("MUTEX_LOCK: failed to get lock (code %d)", ret);
59 + }
60 + return ret;
61 +}
62 +
63 +int __netdata_mutex_trylock(netdata_mutex_t *mutex) {
64 + netdata_thread_disable_cancelability();
65 +
66 + int ret = pthread_mutex_trylock(mutex);
67 + if(ret != 0)
68 + netdata_thread_enable_cancelability();
69 +
70 + return ret;
71 +}
72 +
73 +int __netdata_mutex_unlock(netdata_mutex_t *mutex) {
74 + int ret = pthread_mutex_unlock(mutex);
75 + if(unlikely(ret != 0))
76 + error("MUTEX_LOCK: failed to unlock (code %d).", ret);
77 + else
78 + netdata_thread_enable_cancelability();
79 +
80 + return ret;
81 +}
82 +
83 +int netdata_mutex_init_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) {
84 + usec_t start = 0;
85 +
86 + if(unlikely(debug_flags & D_LOCKS)) {
87 + start = now_boottime_usec();
88 + debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_init(0x%p) from %lu@%s, %s()", mutex, line, file, function);
89 + }
90 +
91 + int ret = __netdata_mutex_init(mutex);
92 +
93 + debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_init(0x%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, now_boottime_usec() - start, line, file, function);
94 +
95 + return ret;
96 +}
97 +
98 +int netdata_mutex_lock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) {
99 + usec_t start = 0;
100 +
101 + if(unlikely(debug_flags & D_LOCKS)) {
102 + start = now_boottime_usec();
103 + debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_lock(0x%p) from %lu@%s, %s()", mutex, line, file, function);
104 + }
105 +
106 + int ret = __netdata_mutex_lock(mutex);
107 +
108 + debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_lock(0x%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, now_boottime_usec() - start, line, file, function);
109 +
110 + return ret;
111 +}
112 +
113 +int netdata_mutex_trylock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) {
114 + usec_t start = 0;
115 +
116 + if(unlikely(debug_flags & D_LOCKS)) {
117 + start = now_boottime_usec();
118 + debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_trylock(0x%p) from %lu@%s, %s()", mutex, line, file, function);
119 + }
120 +
121 + int ret = __netdata_mutex_trylock(mutex);
122 +
123 + debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_trylock(0x%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, now_boottime_usec() - start, line, file, function);
124 +
125 + return ret;
126 +}
127 +
128 +int netdata_mutex_unlock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) {
129 + usec_t start = 0;
130 +
131 + if(unlikely(debug_flags & D_LOCKS)) {
132 + start = now_boottime_usec();
133 + debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_unlock(0x%p) from %lu@%s, %s()", mutex, line, file, function);
134 + }
135 +
136 + int ret = __netdata_mutex_unlock(mutex);
137 +
138 + debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_unlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, now_boottime_usec() - start, line, file, function);
139 +
140 + return ret;
141 +}
142 +
143 +
144 +// ----------------------------------------------------------------------------
145 +// r/w lock
146 +
147 +int __netdata_rwlock_destroy(netdata_rwlock_t *rwlock) {
148 + int ret = pthread_rwlock_destroy(rwlock);
149 + if(unlikely(ret != 0))
150 + error("RW_LOCK: failed to destroy lock (code %d)", ret);
151 + return ret;
152 +}
153 +
154 +int __netdata_rwlock_init(netdata_rwlock_t *rwlock) {
155 + int ret = pthread_rwlock_init(rwlock, NULL);
156 + if(unlikely(ret != 0))
157 + error("RW_LOCK: failed to initialize lock (code %d)", ret);
158 + return ret;
159 +}
160 +
161 +int __netdata_rwlock_rdlock(netdata_rwlock_t *rwlock) {
162 + netdata_thread_disable_cancelability();
163 +
164 + int ret = pthread_rwlock_rdlock(rwlock);
165 + if(unlikely(ret != 0)) {
166 + netdata_thread_enable_cancelability();
167 + error("RW_LOCK: failed to obtain read lock (code %d)", ret);
168 + }
169 +
170 + return ret;
171 +}
172 +
173 +int __netdata_rwlock_wrlock(netdata_rwlock_t *rwlock) {
174 + netdata_thread_disable_cancelability();
175 +
176 + int ret = pthread_rwlock_wrlock(rwlock);
177 + if(unlikely(ret != 0)) {
178 + error("RW_LOCK: failed to obtain write lock (code %d)", ret);
179 + netdata_thread_enable_cancelability();
180 + }
181 +
182 + return ret;
183 +}
184 +
185 +int __netdata_rwlock_unlock(netdata_rwlock_t *rwlock) {
186 + int ret = pthread_rwlock_unlock(rwlock);
187 + if(unlikely(ret != 0))
188 + error("RW_LOCK: failed to release lock (code %d)", ret);
189 + else
190 + netdata_thread_enable_cancelability();
191 +
192 + return ret;
193 +}
194 +
195 +int __netdata_rwlock_tryrdlock(netdata_rwlock_t *rwlock) {
196 + netdata_thread_disable_cancelability();
197 +
198 + int ret = pthread_rwlock_tryrdlock(rwlock);
199 + if(ret != 0)
200 + netdata_thread_enable_cancelability();
201 +
202 + return ret;
203 +}
204 +
205 +int __netdata_rwlock_trywrlock(netdata_rwlock_t *rwlock) {
206 + netdata_thread_disable_cancelability();
207 +
208 + int ret = pthread_rwlock_trywrlock(rwlock);
209 + if(ret != 0)
210 + netdata_thread_enable_cancelability();
211 +
212 + return ret;
213 +}
214 +
215 +
216 +int netdata_rwlock_destroy_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
217 + usec_t start = 0;
218 +
219 + if(unlikely(debug_flags & D_LOCKS)) {
220 + start = now_boottime_usec();
221 + debug(D_LOCKS, "RW_LOCK: netdata_rwlock_destroy(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
222 + }
223 +
224 + int ret = __netdata_rwlock_destroy(rwlock);
225 +
226 + debug(D_LOCKS, "RW_LOCK: netdata_rwlock_destroy(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
227 +
228 + return ret;
229 +}
230 +
231 +int netdata_rwlock_init_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
232 + usec_t start = 0;
233 +
234 + if(unlikely(debug_flags & D_LOCKS)) {
235 + start = now_boottime_usec();
236 + debug(D_LOCKS, "RW_LOCK: netdata_rwlock_init(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
237 + }
238 +
239 + int ret = __netdata_rwlock_init(rwlock);
240 +
241 + debug(D_LOCKS, "RW_LOCK: netdata_rwlock_init(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
242 +
243 + return ret;
244 +}
245 +
246 +int netdata_rwlock_rdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
247 + usec_t start = 0;
248 +
249 + if(unlikely(debug_flags & D_LOCKS)) {
250 + start = now_boottime_usec();
251 + debug(D_LOCKS, "RW_LOCK: netdata_rwlock_rdlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
252 + }
253 +
254 + int ret = __netdata_rwlock_rdlock(rwlock);
255 +
256 + debug(D_LOCKS, "RW_LOCK: netdata_rwlock_rdlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
257 +
258 + return ret;
259 +}
260 +
261 +int netdata_rwlock_wrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
262 + usec_t start = 0;
263 +
264 + if(unlikely(debug_flags & D_LOCKS)) {
265 + start = now_boottime_usec();
266 + debug(D_LOCKS, "RW_LOCK: netdata_rwlock_wrlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
267 + }
268 +
269 + int ret = __netdata_rwlock_wrlock(rwlock);
270 +
271 + debug(D_LOCKS, "RW_LOCK: netdata_rwlock_wrlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
272 +
273 + return ret;
274 +}
275 +
276 +int netdata_rwlock_unlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
277 + usec_t start = 0;
278 +
279 + if(unlikely(debug_flags & D_LOCKS)) {
280 + start = now_boottime_usec();
281 + debug(D_LOCKS, "RW_LOCK: netdata_rwlock_unlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
282 + }
283 +
284 + int ret = __netdata_rwlock_unlock(rwlock);
285 +
286 + debug(D_LOCKS, "RW_LOCK: netdata_rwlock_unlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
287 +
288 + return ret;
289 +}
290 +
291 +int netdata_rwlock_tryrdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
292 + usec_t start = 0;
293 +
294 + if(unlikely(debug_flags & D_LOCKS)) {
295 + start = now_boottime_usec();
296 + debug(D_LOCKS, "RW_LOCK: netdata_rwlock_tryrdlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
297 + }
298 +
299 + int ret = __netdata_rwlock_tryrdlock(rwlock);
300 +
301 + debug(D_LOCKS, "RW_LOCK: netdata_rwlock_tryrdlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
302 +
303 + return ret;
304 +}
305 +
306 +int netdata_rwlock_trywrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
307 + usec_t start = 0;
308 +
309 + if(unlikely(debug_flags & D_LOCKS)) {
310 + start = now_boottime_usec();
311 + debug(D_LOCKS, "RW_LOCK: netdata_rwlock_trywrlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
312 + }
313 +
314 + int ret = __netdata_rwlock_trywrlock(rwlock);
315 +
316 + debug(D_LOCKS, "RW_LOCK: netdata_rwlock_trywrlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
317 +
318 + return ret;
319 +}
src/locks.h
+32 -257
@@ -1,276 +1,46 @@
1 #ifndef NETDATA_LOCKS_H
2 #define NETDATA_LOCKS_H
3
4 -// ----------------------------------------------------------------------------
5 -// mutex
6 -
4 typedef pthread_mutex_t netdata_mutex_t;
8 -
5 #define NETDATA_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
6
11 -static inline int __netdata_mutex_init(netdata_mutex_t *mutex) {
12 - int ret = pthread_mutex_init(mutex, NULL);
13 - if(unlikely(ret != 0))
14 - error("MUTEX_LOCK: failed to initialize (code %d).", ret);
15 - return ret;
16 -}
17 -
18 -static inline int __netdata_mutex_lock(netdata_mutex_t *mutex) {
19 - int ret = pthread_mutex_lock(mutex);
20 - if(unlikely(ret != 0))
21 - error("MUTEX_LOCK: failed to get lock (code %d)", ret);
22 - return ret;
23 -}
7 +typedef pthread_rwlock_t netdata_rwlock_t;
8 +#define NETDATA_RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER
9
25 -static inline int __netdata_mutex_trylock(netdata_mutex_t *mutex) {
26 - int ret = pthread_mutex_trylock(mutex);
27 - return ret;
28 -}
10 +extern int __netdata_mutex_init(netdata_mutex_t *mutex);
11 +extern int __netdata_mutex_lock(netdata_mutex_t *mutex);
12 +extern int __netdata_mutex_trylock(netdata_mutex_t *mutex);
13 +extern int __netdata_mutex_unlock(netdata_mutex_t *mutex);
14 +
15 +extern int __netdata_rwlock_destroy(netdata_rwlock_t *rwlock);
16 +extern int __netdata_rwlock_init(netdata_rwlock_t *rwlock);
17 +extern int __netdata_rwlock_rdlock(netdata_rwlock_t *rwlock);
18 +extern int __netdata_rwlock_wrlock(netdata_rwlock_t *rwlock);
19 +extern int __netdata_rwlock_unlock(netdata_rwlock_t *rwlock);
20 +extern int __netdata_rwlock_tryrdlock(netdata_rwlock_t *rwlock);
21 +extern int __netdata_rwlock_trywrlock(netdata_rwlock_t *rwlock);
22 +
23 +extern int netdata_mutex_init_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex);
24 +extern int netdata_mutex_lock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex);
25 +extern int netdata_mutex_trylock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex);
26 +extern int netdata_mutex_unlock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex);
27 +
28 +extern int netdata_rwlock_destroy_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock);
29 +extern int netdata_rwlock_init_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock);
30 +extern int netdata_rwlock_rdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock);
31 +extern int netdata_rwlock_wrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock);
32 +extern int netdata_rwlock_unlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock);
33 +extern int netdata_rwlock_tryrdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock);
34 +extern int netdata_rwlock_trywrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock);
35
30 -static inline int __netdata_mutex_unlock(netdata_mutex_t *mutex) {
31 - int ret = pthread_mutex_unlock(mutex);
32 - if(unlikely(ret != 0))
33 - error("MUTEX_LOCK: failed to unlock (code %d).", ret);
34 - return ret;
35 -}
36
37 #ifdef NETDATA_INTERNAL_CHECKS
38
39 -static inline int netdata_mutex_init_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) {
40 - usec_t start = 0;
41 -
42 - if(unlikely(debug_flags & D_LOCKS)) {
43 - start = now_boottime_usec();
44 - debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_init(0x%p) from %lu@%s, %s()", mutex, line, file, function);
45 - }
46 -
47 - int ret = __netdata_mutex_init(mutex);
48 -
49 - debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_init(0x%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, now_boottime_usec() - start, line, file, function);
50 -
51 - return ret;
52 -}
53 -
54 -static inline int netdata_mutex_lock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) {
55 - usec_t start = 0;
56 -
57 - if(unlikely(debug_flags & D_LOCKS)) {
58 - start = now_boottime_usec();
59 - debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_lock(0x%p) from %lu@%s, %s()", mutex, line, file, function);
60 - }
61 -
62 - int ret = __netdata_mutex_lock(mutex);
63 -
64 - debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_lock(0x%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, now_boottime_usec() - start, line, file, function);
65 -
66 - return ret;
67 -}
68 -
69 -static inline int netdata_mutex_trylock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) {
70 - usec_t start = 0;
71 -
72 - if(unlikely(debug_flags & D_LOCKS)) {
73 - start = now_boottime_usec();
74 - debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_trylock(0x%p) from %lu@%s, %s()", mutex, line, file, function);
75 - }
76 -
77 - int ret = __netdata_mutex_trylock(mutex);
78 -
79 - debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_trylock(0x%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, now_boottime_usec() - start, line, file, function);
80 -
81 - return ret;
82 -}
83 -
84 -static inline int netdata_mutex_unlock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) {
85 - usec_t start = 0;
86 -
87 - if(unlikely(debug_flags & D_LOCKS)) {
88 - start = now_boottime_usec();
89 - debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_unlock(0x%p) from %lu@%s, %s()", mutex, line, file, function);
90 - }
91 -
92 - int ret = __netdata_mutex_unlock(mutex);
93 -
94 - debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_unlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, now_boottime_usec() - start, line, file, function);
95 -
96 - return ret;
97 -}
98 -
39 #define netdata_mutex_init(mutex) netdata_mutex_init_debug(__FILE__, __FUNCTION__, __LINE__, mutex)
40 #define netdata_mutex_lock(mutex) netdata_mutex_lock_debug(__FILE__, __FUNCTION__, __LINE__, mutex)
41 #define netdata_mutex_trylock(mutex) netdata_mutex_trylock_debug(__FILE__, __FUNCTION__, __LINE__, mutex)
42 #define netdata_mutex_unlock(mutex) netdata_mutex_unlock_debug(__FILE__, __FUNCTION__, __LINE__, mutex)
43
104 -#else // !NETDATA_INTERNAL_CHECKS
105 -
106 -#define netdata_mutex_init(mutex) __netdata_mutex_init(mutex)
107 -#define netdata_mutex_lock(mutex) __netdata_mutex_lock(mutex)
108 -#define netdata_mutex_trylock(mutex) __netdata_mutex_trylock(mutex)
109 -#define netdata_mutex_unlock(mutex) __netdata_mutex_unlock(mutex)
110 -
111 -#endif // NETDATA_INTERNAL_CHECKS
112 -
113 -
114 -// ----------------------------------------------------------------------------
115 -// r/w lock
116 -
117 -typedef pthread_rwlock_t netdata_rwlock_t;
118 -
119 -#define NETDATA_RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER
120 -
121 -static inline int __netdata_rwlock_destroy(netdata_rwlock_t *rwlock) {
122 - int ret = pthread_rwlock_destroy(rwlock);
123 - if(unlikely(ret != 0))
124 - error("RW_LOCK: failed to destroy lock (code %d)", ret);
125 - return ret;
126 -}
127 -
128 -static inline int __netdata_rwlock_init(netdata_rwlock_t *rwlock) {
129 - int ret = pthread_rwlock_init(rwlock, NULL);
130 - if(unlikely(ret != 0))
131 - error("RW_LOCK: failed to initialize lock (code %d)", ret);
132 - return ret;
133 -}
134 -
135 -static inline int __netdata_rwlock_rdlock(netdata_rwlock_t *rwlock) {
136 - int ret = pthread_rwlock_rdlock(rwlock);
137 - if(unlikely(ret != 0))
138 - error("RW_LOCK: failed to obtain read lock (code %d)", ret);
139 - return ret;
140 -}
141 -
142 -static inline int __netdata_rwlock_wrlock(netdata_rwlock_t *rwlock) {
143 - int ret = pthread_rwlock_wrlock(rwlock);
144 - if(unlikely(ret != 0))
145 - error("RW_LOCK: failed to obtain write lock (code %d)", ret);
146 - return ret;
147 -}
148 -
149 -static inline int __netdata_rwlock_unlock(netdata_rwlock_t *rwlock) {
150 - int ret = pthread_rwlock_unlock(rwlock);
151 - if(unlikely(ret != 0))
152 - error("RW_LOCK: failed to release lock (code %d)", ret);
153 - return ret;
154 -}
155 -
156 -static inline int __netdata_rwlock_tryrdlock(netdata_rwlock_t *rwlock) {
157 - int ret = pthread_rwlock_tryrdlock(rwlock);
158 - return ret;
159 -}
160 -
161 -static inline int __netdata_rwlock_trywrlock(netdata_rwlock_t *rwlock) {
162 - int ret = pthread_rwlock_trywrlock(rwlock);
163 - return ret;
164 -}
165 -
166 -
167 -#ifdef NETDATA_INTERNAL_CHECKS
168 -
169 -static inline int netdata_rwlock_destroy_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
170 - usec_t start = 0;
171 -
172 - if(unlikely(debug_flags & D_LOCKS)) {
173 - start = now_boottime_usec();
174 - debug(D_LOCKS, "RW_LOCK: netdata_rwlock_destroy(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
175 - }
176 -
177 - int ret = __netdata_rwlock_destroy(rwlock);
178 -
179 - debug(D_LOCKS, "RW_LOCK: netdata_rwlock_destroy(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
180 -
181 - return ret;
182 -}
183 -
184 -static inline int netdata_rwlock_init_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
185 - usec_t start = 0;
186 -
187 - if(unlikely(debug_flags & D_LOCKS)) {
188 - start = now_boottime_usec();
189 - debug(D_LOCKS, "RW_LOCK: netdata_rwlock_init(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
190 - }
191 -
192 - int ret = __netdata_rwlock_init(rwlock);
193 -
194 - debug(D_LOCKS, "RW_LOCK: netdata_rwlock_init(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
195 -
196 - return ret;
197 -}
198 -
199 -static inline int netdata_rwlock_rdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
200 - usec_t start = 0;
201 -
202 - if(unlikely(debug_flags & D_LOCKS)) {
203 - start = now_boottime_usec();
204 - debug(D_LOCKS, "RW_LOCK: netdata_rwlock_rdlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
205 - }
206 -
207 - int ret = __netdata_rwlock_rdlock(rwlock);
208 -
209 - debug(D_LOCKS, "RW_LOCK: netdata_rwlock_rdlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
210 -
211 - return ret;
212 -}
213 -
214 -static inline int netdata_rwlock_wrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
215 - usec_t start = 0;
216 -
217 - if(unlikely(debug_flags & D_LOCKS)) {
218 - start = now_boottime_usec();
219 - debug(D_LOCKS, "RW_LOCK: netdata_rwlock_wrlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
220 - }
221 -
222 - int ret = __netdata_rwlock_wrlock(rwlock);
223 -
224 - debug(D_LOCKS, "RW_LOCK: netdata_rwlock_wrlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
225 -
226 - return ret;
227 -}
228 -
229 -static inline int netdata_rwlock_unlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
230 - usec_t start = 0;
231 -
232 - if(unlikely(debug_flags & D_LOCKS)) {
233 - start = now_boottime_usec();
234 - debug(D_LOCKS, "RW_LOCK: netdata_rwlock_unlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
235 - }
236 -
237 - int ret = __netdata_rwlock_unlock(rwlock);
238 -
239 - debug(D_LOCKS, "RW_LOCK: netdata_rwlock_unlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
240 -
241 - return ret;
242 -}
243 -
244 -static inline int netdata_rwlock_tryrdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
245 - usec_t start = 0;
246 -
247 - if(unlikely(debug_flags & D_LOCKS)) {
248 - start = now_boottime_usec();
249 - debug(D_LOCKS, "RW_LOCK: netdata_rwlock_tryrdlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
250 - }
251 -
252 - int ret = __netdata_rwlock_tryrdlock(rwlock);
253 -
254 - debug(D_LOCKS, "RW_LOCK: netdata_rwlock_tryrdlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
255 -
256 - return ret;
257 -}
258 -
259 -static inline int netdata_rwlock_trywrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
260 - usec_t start = 0;
261 -
262 - if(unlikely(debug_flags & D_LOCKS)) {
263 - start = now_boottime_usec();
264 - debug(D_LOCKS, "RW_LOCK: netdata_rwlock_trywrlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
265 - }
266 -
267 - int ret = __netdata_rwlock_trywrlock(rwlock);
268 -
269 - debug(D_LOCKS, "RW_LOCK: netdata_rwlock_trywrlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
270 -
271 - return ret;
272 -}
273 -
44 #define netdata_rwlock_destroy(rwlock) netdata_rwlock_destroy_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
45 #define netdata_rwlock_init(rwlock) netdata_rwlock_init_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
46 #define netdata_rwlock_rdlock(rwlock) netdata_rwlock_rdlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
@@ -281,6 +51,11 @@ static inline int netdata_rwlock_trywrlock_debug( const char *file, const char *
51
52 #else // !NETDATA_INTERNAL_CHECKS
53
54 +#define netdata_mutex_init(mutex) __netdata_mutex_init(mutex)
55 +#define netdata_mutex_lock(mutex) __netdata_mutex_lock(mutex)
56 +#define netdata_mutex_trylock(mutex) __netdata_mutex_trylock(mutex)
57 +#define netdata_mutex_unlock(mutex) __netdata_mutex_unlock(mutex)
58 +
59 #define netdata_rwlock_destroy(rwlock) __netdata_rwlock_destroy(rwlock)
60 #define netdata_rwlock_init(rwlock) __netdata_rwlock_init(rwlock)
61 #define netdata_rwlock_rdlock(rwlock) __netdata_rwlock_rdlock(rwlock)
src/main.c
+18 -44
@@ -6,33 +6,28 @@ void netdata_cleanup_and_exit(int ret) {
6 netdata_exit = 1;
7
8 error_log_limit_unlimited();
9 - info("netdata is preparing to exit...");
9 + info("MAIN: netdata prepares to exit...");
10
11 - // allow all the threads to cleanup by themselves
12 - unsigned int w = (unsigned int)default_rrd_update_every + 2;
13 - info("Giving %u secs to background threads to cleanup...", w);
14 - sleep(w);
15 -
16 - // kill all threads and childs
17 - //info("Stopping all threads and child processes...");
18 - //kill_childs();
11 + // stop everything
12 + info("MAIN: stopping all threads and child processes...");
13 + cancel_main_threads();
14
15 // cleanup the database (delete files not needed)
21 - info("Cleaning up the database...");
16 + info("MAIN: cleaning up the database...");
17 rrdhost_cleanup_all();
18
19 // free the database
25 - //info("Freeing database memory...");
26 - //rrdhost_free_all();
20 + info("MAIN: freeing database memory...");
21 + rrdhost_free_all();
22
23 // unlink the pid
24 if(pidfile[0]) {
30 - info("Removing netdata PID file '%s'...", pidfile);
25 + info("MAIN: removing netdata PID file '%s'...", pidfile);
26 if(unlink(pidfile) != 0)
32 - error("Cannot unlink pidfile '%s'.", pidfile);
27 + error("MAIN: cannot unlink pidfile '%s'.", pidfile);
28 }
29
35 - info("All done - netdata is now exiting - bye bye...");
30 + info("MAIN: all done - netdata is now exiting - bye bye...");
31 exit(ret);
32 }
33
@@ -182,50 +177,29 @@ int killpid(pid_t pid, int sig)
177 return ret;
178 }
179
185 -void kill_childs() {
180 +void cancel_main_threads() {
181 error_log_limit_unlimited();
182
188 - siginfo_t info;
189 -
190 - struct web_client *w;
191 - for(w = web_clients; w ; w = w->next) {
192 - info("Stopping web client %s", w->client_ip);
193 - int ret;
194 - if((ret = pthread_cancel(w->thread)) != 0)
195 - error("pthread_cancel() failed with code %d.", ret);
196 -
197 - WEB_CLIENT_IS_OBSOLETE(w);
198 - }
199 -
183 int i;
184 for (i = 0; static_threads[i].name != NULL ; i++) {
185 if(static_threads[i].enabled) {
203 - info("Stopping %s thread", static_threads[i].name);
186 + info("MAIN: Calling pthread_cancel() on %s thread", static_threads[i].name);
187 int ret;
188 if((ret = pthread_cancel(*static_threads[i].thread)) != 0)
206 - error("pthread_cancel() failed with code %d.", ret);
189 + error("MAIN: pthread_cancel() failed with code %d.", ret);
190 + else
191 + info("MAIN: thread %s cancelled", static_threads[i].name);
192
193 static_threads[i].enabled = 0;
194 }
195 }
196
212 - if(tc_child_pid) {
213 - info("Killing tc-qos-helper process %d", tc_child_pid);
214 - if(killpid(tc_child_pid, SIGTERM) != -1)
215 - waitid(P_PID, (id_t) tc_child_pid, &info, WEXITED);
216 -
217 - tc_child_pid = 0;
218 - }
219 -
220 - // stop all running plugins
221 - pluginsd_stop_all_external_plugins();
222 -
197 // if, for any reason there is any child exited
198 // catch it here
225 - info("Cleaning up an other children");
199 + info("MAIN: waiting for any unfinished child processes");
200 + siginfo_t info;
201 waitid(P_PID, 0, &info, WEXITED|WNOHANG);
227 -
228 - info("All threads/childs stopped.");
202 + info("MAIN: all threads/childs stopped.");
203 }
204
205 struct option_def option_definitions[] = {
src/main.h
+2 -2
@@ -22,7 +22,7 @@ struct netdata_static_thread {
22 char *config_section;
23 char *config_name;
24
25 - volatile int enabled;
25 + volatile sig_atomic_t enabled;
26
27 pthread_t *thread;
28
@@ -30,7 +30,7 @@ struct netdata_static_thread {
30 void *(*start_routine) (void *);
31 };
32
33 -extern void kill_childs(void);
33 +extern void cancel_main_threads(void);
34 extern int killpid(pid_t pid, int signal);
35 extern void netdata_cleanup_and_exit(int ret) NORETURN;
36
src/plugin_tc.c
+26 -5
@@ -829,9 +829,30 @@ static inline void tc_split_words(char *str, char **words, int max_words) {
829 }
830
831 volatile pid_t tc_child_pid = 0;
832 -void *tc_main(void *ptr) {
832 +
833 +static void tc_main_cleanup(void *ptr) {
834 struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
835 + if(static_thread->enabled) {
836 + static_thread->enabled = 0;
837 +
838 + info("TC: cleaning up...");
839 +
840 + if(tc_child_pid) {
841 + info("TC: killing with SIGTERM tc-qos-helper process %d", tc_child_pid);
842 + if(killpid(tc_child_pid, SIGTERM) != -1) {
843 + siginfo_t info;
844 +
845 + info("TC: waiting for tc plugin child process pid %d to exit...", tc_child_pid);
846 + waitid(P_PID, (id_t) tc_child_pid, &info, WEXITED);
847 + // info("TC: finished tc plugin child process pid %d.", tc_child_pid);
848 + }
849
850 + tc_child_pid = 0;
851 + }
852 + }
853 +}
854 +
855 +void *tc_main(void *ptr) {
856 info("TC thread created with task id %d", gettid());
857
858 if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
@@ -863,10 +884,10 @@ void *tc_main(void *ptr) {
884
885 snprintfz(buffer, TC_LINE_MAX, "%s/tc-qos-helper.sh", netdata_configured_plugins_dir);
886 char *tc_script = config_get("plugin:tc", "script to run to get tc values", buffer);
866 -
867 - for(;1;) {
868 - if(unlikely(netdata_exit)) break;
887
888 + pthread_cleanup_push(tc_main_cleanup, ptr);
889 +
890 + while(!netdata_exit) {
891 FILE *fp;
892 struct tc_device *device = NULL;
893 struct tc_class *class = NULL;
@@ -1151,8 +1172,8 @@ void *tc_main(void *ptr) {
1172
1173 cleanup:
1174 info("TC thread exiting");
1175 + pthread_cleanup_pop(1);
1176
1155 - static_thread->enabled = 0;
1177 pthread_exit(NULL);
1178 return NULL;
1179 }
src/plugins_d.c
+49 -36
@@ -476,15 +476,36 @@ cleanup:
476 return count;
477 }
478
479 +static void pluginsd_worker_thread_cleanup(void *arg) {
480 + struct plugind *cd = (struct plugind *)arg;
481 +
482 + info("PLUGINSD: '%s' thread exiting", cd->fullfilename);
483 +
484 + if(cd->enabled && !cd->obsolete) {
485 + cd->obsolete = 1;
486 +
487 + if (cd->pid) {
488 + siginfo_t info;
489 + info("PLUGINSD: killing %s plugin child process pid %d", cd->id, cd->pid);
490 + if (killpid(cd->pid, SIGTERM) != -1) {
491 + info("PLUGINSD: waiting for %s plugin child process pid %d to exit...", cd->id, cd->pid);
492 + waitid(P_PID, (id_t) cd->pid, &info, WEXITED);
493 + info("PLUGINSD: finished %s plugin child process pid %d.", cd->id, cd->pid);
494 + }
495 + cd->pid = 0;
496 + }
497 + }
498 +}
499 +
500 void *pluginsd_worker_thread(void *arg) {
501 struct plugind *cd = (struct plugind *)arg;
502 cd->obsolete = 0;
503
504 size_t count = 0;
505
485 - for(;;) {
486 - if(unlikely(netdata_exit)) break;
506 + pthread_cleanup_push(pluginsd_worker_thread_cleanup, arg);
507
508 + while(!netdata_exit) {
509 FILE *fp = mypopen(cd->cmd, &cd->pid);
510 if(unlikely(!fp)) {
511 error("Cannot popen(\"%s\", \"r\").", cd->cmd);
@@ -503,8 +524,7 @@ void *pluginsd_worker_thread(void *arg) {
524 // get the return code
525 int code = mypclose(fp, cd->pid);
526
506 - if(unlikely(netdata_exit)) break;
507 - else if(code != 0) {
527 + if(code != 0) {
528 // the plugin reports failure
529
530 if(likely(!cd->successful_collections)) {
@@ -548,16 +568,33 @@ void *pluginsd_worker_thread(void *arg) {
568 if(unlikely(!cd->enabled)) break;
569 }
570
551 - info("PLUGINSD: '%s' thread exiting", cd->fullfilename);
552 -
553 - cd->obsolete = 1;
571 + pthread_cleanup_pop(1);
572 pthread_exit(NULL);
573 return NULL;
574 }
575
558 -void *pluginsd_main(void *ptr) {
559 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
576 +static void pluginsd_main_cleanup(void *data) {
577 + struct netdata_static_thread *static_thread = (struct netdata_static_thread *)data;
578 + if(static_thread->enabled) {
579 + static_thread->enabled = 0;
580 +
581 + info("PLUGINSD: cleaning up plugin threads...");
582 + struct plugind *cd;
583 +
584 + for (cd = pluginsd_root; cd; cd = cd->next) {
585 + if (cd->enabled && !cd->obsolete) {
586 + info("PLUGINSD: Calling pthread_cancel() on %s plugin thread", cd->id);
587 + int ret;
588 + if ((ret = pthread_cancel(cd->thread)) != 0)
589 + error("PLUGINSD: pthread_cancel() failed with code %d.", ret);
590 + }
591 + }
592 +
593 + info("PLUGINSD: cleanup completed.");
594 + }
595 +}
596
597 +void *pluginsd_main(void *ptr) {
598 info("PLUGINS.D thread created with task id %d", gettid());
599
600 if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
@@ -574,9 +611,9 @@ void *pluginsd_main(void *ptr) {
611 // so that we don't log broken directories on each loop
612 int directory_errors[PLUGINSD_MAX_DIRECTORIES] = { 0 };
613
577 - for(;;) {
578 - if(unlikely(netdata_exit)) break;
614 + pthread_cleanup_push(pluginsd_main_cleanup, ptr);
615
616 + while(!netdata_exit) {
617 int idx;
618 const char *directory_name;
619
@@ -668,31 +705,7 @@ void *pluginsd_main(void *ptr) {
705 sleep((unsigned int) scan_frequency);
706 }
707
671 - info("PLUGINS.D thread exiting");
672 -
673 - static_thread->enabled = 0;
708 + pthread_cleanup_pop(1);
709 pthread_exit(NULL);
710 return NULL;
711 }
677 -
678 -
679 -void pluginsd_stop_all_external_plugins() {
680 - siginfo_t info;
681 - struct plugind *cd;
682 - for(cd = pluginsd_root ; cd ; cd = cd->next) {
683 - if(cd->enabled && !cd->obsolete) {
684 - info("Stopping %s plugin thread", cd->id);
685 - pthread_cancel(cd->thread);
686 -
687 - if(cd->pid) {
688 - info("killing %s plugin child process pid %d", cd->id, cd->pid);
689 - if(killpid(cd->pid, SIGTERM) != -1)
690 - waitid(P_PID, (id_t) cd->pid, &info, WEXITED);
691 -
692 - cd->pid = 0;
693 - }
694 -
695 - cd->obsolete = 1;
696 - }
697 - }
698 -}
src/plugins_d.h
+3 -4
@@ -26,7 +26,7 @@ struct plugind {
26 char fullfilename[FILENAME_MAX+1]; // with path
27 char cmd[PLUGINSD_CMD_MAX+1]; // the command that it executes
28
29 - pid_t pid;
29 + volatile pid_t pid;
30 pthread_t thread;
31
32 size_t successful_collections; // the number of times we have seen
@@ -36,8 +36,8 @@ struct plugind {
36 // without collecting values
37
38 int update_every; // the plugin default data collection frequency
39 - volatile int obsolete; // do not touch this structure after setting this to 1
40 - volatile int enabled; // if this is enabled or not
39 + volatile sig_atomic_t obsolete; // do not touch this structure after setting this to 1
40 + volatile sig_atomic_t enabled; // if this is enabled or not
41
42 time_t started_t;
43
@@ -47,7 +47,6 @@ struct plugind {
47 extern struct plugind *pluginsd_root;
48
49 extern void *pluginsd_main(void *ptr);
50 -extern void pluginsd_stop_all_external_plugins(void);
50
51 extern size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int trust_durations);
52 extern int pluginsd_split_words(char *str, char **words, int max_words);
src/popen.c
+1 -1
@@ -43,7 +43,7 @@ static void mypopen_del(FILE *fp) {
43 #define PIPE_READ 0
44 #define PIPE_WRITE 1
45
46 -FILE *mypopen(const char *command, pid_t *pidptr)
46 +FILE *mypopen(const char *command, volatile pid_t *pidptr)
47 {
48 int pipefd[2];
49
src/popen.h
+1 -1
@@ -4,7 +4,7 @@
4 #define PIPE_READ 0
5 #define PIPE_WRITE 1
6
7 -extern FILE *mypopen(const char *command, pid_t *pidptr);
7 +extern FILE *mypopen(const char *command, volatile pid_t *pidptr);
8 extern int mypclose(FILE *fp, pid_t pid);
9
10 #endif /* NETDATA_POPEN_H */
src/statsd.c
+17 -16
@@ -1968,32 +1968,33 @@ static inline void statsd_flush_index_metrics(STATSD_INDEX *index, void (*flush_
1968 // --------------------------------------------------------------------------------------
1969 // statsd main thread
1970
1971 -int statsd_listen_sockets_setup(void) {
1971 +static int statsd_listen_sockets_setup(void) {
1972 return listen_sockets_setup(&statsd.sockets);
1973 }
1974
1975 -void statsd_main_cleanup(void *data) {
1976 - (void)data;
1975 +static void statsd_main_cleanup(void *data) {
1976 + struct netdata_static_thread *static_thread = (struct netdata_static_thread *)data;
1977 + if(static_thread->enabled) {
1978 + static_thread->enabled = 0;
1979
1978 - info("STATSD: cleaning up...");
1980 + info("STATSD: cleaning up...");
1981
1980 - if(statsd.collection_threads) {
1981 - int i;
1982 - for (i = 0; i < statsd.threads; i++) {
1983 - info("STATSD: stopping data collection thread %d...", i);
1984 - pthread_cancel(statsd.collection_threads[i]);
1982 + if (statsd.collection_threads) {
1983 + int i;
1984 + for (i = 0; i < statsd.threads; i++) {
1985 + info("STATSD: stopping data collection thread %d...", i);
1986 + pthread_cancel(statsd.collection_threads[i]);
1987 + }
1988 }
1986 - }
1989
1988 - info("STATSD: closing sockets...");
1989 - listen_sockets_close(&statsd.sockets);
1990 + info("STATSD: closing sockets...");
1991 + listen_sockets_close(&statsd.sockets);
1992
1991 - info("STATSD: cleanup completed.");
1993 + info("STATSD: cleanup completed.");
1994 + }
1995 }
1996
1997 void *statsd_main(void *ptr) {
1995 - (void)ptr;
1996 -
1998 info("STATSD main thread created with task id %d", gettid());
1999
2000 if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
@@ -2102,7 +2103,7 @@ void *statsd_main(void *ptr) {
2103 error("STATSD: cannot request detach of child thread.");
2104 }
2105
2105 - pthread_cleanup_push(statsd_main_cleanup, NULL);
2106 + pthread_cleanup_push(statsd_main_cleanup, ptr);
2107
2108 // ----------------------------------------------------------------------------------------------------------------
2109 // statsd monitoring charts
src/web_server.c
+65 -22
@@ -109,9 +109,40 @@ static inline void cleanup_web_clients(void) {
109
110 #define CLEANUP_EVERY_EVENTS 100
111
112 -void *socket_listen_main_multi_threaded(void *ptr) {
113 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
112 +static struct pollfd *socket_listen_main_multi_threaded_fds = NULL;
113 +
114 +static void socket_listen_main_multi_threaded_cleanup(void *data) {
115 + struct netdata_static_thread *static_thread = (struct netdata_static_thread *)data;
116 + if(static_thread->enabled) {
117 + static_thread->enabled = 0;
118 +
119 + info("LISTENER: multi-threaded web server cleaning up...");
120 +
121 + info("LISTENER: releasing allocated memory...");
122 + freez(socket_listen_main_multi_threaded_fds);
123 +
124 + info("LISTENER: closing all sockets...");
125 + listen_sockets_close(&api_sockets);
126 +
127 + info("LISTENER: cleanup completed.");
128 + }
129
130 + struct web_client *w;
131 + for(w = web_clients; w ; w = w->next) {
132 + if(!web_client_check_obsolete(w)) {
133 + WEB_CLIENT_IS_OBSOLETE(w);
134 +
135 + info("LISTENER: Calling pthread_cancel() on web client %s, id %llu", w->client_ip, w->id);
136 + int ret;
137 + if ((ret = pthread_cancel(w->thread)) != 0)
138 + error("LISTENER: pthread_cancel() failed with code %d, id %llu.", ret, w->id);
139 + //else
140 + // info("LISTENER: web client thread %s cancelled, id %llu", w->client_ip, w->id);
141 + }
142 + }
143 +}
144 +
145 +void *socket_listen_main_multi_threaded(void *ptr) {
146 web_server_mode = WEB_SERVER_MODE_MULTI_THREADED;
147 info("Multi-threaded WEB SERVER thread created with task id %d", gettid());
148
@@ -127,22 +158,25 @@ void *socket_listen_main_multi_threaded(void *ptr) {
158 if(!api_sockets.opened)
159 fatal("LISTENER: No sockets to listen to.");
160
130 - struct pollfd *fds = callocz(sizeof(struct pollfd), api_sockets.opened);
161 + pthread_cleanup_push(socket_listen_main_multi_threaded_cleanup, ptr);
162 +
163 + socket_listen_main_multi_threaded_fds = callocz(sizeof(struct pollfd), api_sockets.opened);
164
165 size_t i;
166 for(i = 0; i < api_sockets.opened ;i++) {
134 - fds[i].fd = api_sockets.fds[i];
135 - fds[i].events = POLLIN;
136 - fds[i].revents = 0;
167 + socket_listen_main_multi_threaded_fds[i].fd = api_sockets.fds[i];
168 + socket_listen_main_multi_threaded_fds[i].events = POLLIN;
169 + socket_listen_main_multi_threaded_fds[i].revents = 0;
170
171 info("Listening on '%s'", (api_sockets.fds_names[i])?api_sockets.fds_names[i]:"UNKNOWN");
172 }
173
174 int timeout = 10 * 1000;
175
143 - for(;;) {
176 + while(!netdata_exit) {
177 +
178 // debug(D_WEB_CLIENT, "LISTENER: Waiting...");
145 - retval = poll(fds, api_sockets.opened, timeout);
179 + retval = poll(socket_listen_main_multi_threaded_fds, api_sockets.opened, timeout);
180
181 if(unlikely(retval == -1)) {
182 error("LISTENER: poll() failed.");
@@ -156,13 +190,13 @@ void *socket_listen_main_multi_threaded(void *ptr) {
190 }
191
192 for(i = 0 ; i < api_sockets.opened ; i++) {
159 - short int revents = fds[i].revents;
193 + short int revents = socket_listen_main_multi_threaded_fds[i].revents;
194
195 // check for new incoming connections
196 if(revents & POLLIN || revents & POLLPRI) {
163 - fds[i].revents = 0;
197 + socket_listen_main_multi_threaded_fds[i].revents = 0;
198
165 - w = web_client_create(fds[i].fd);
199 + w = web_client_create(socket_listen_main_multi_threaded_fds[i].fd);
200 if(unlikely(!w)) {
201 // no need for error log - web_client_create already logged the error
202 continue;
@@ -192,12 +226,8 @@ void *socket_listen_main_multi_threaded(void *ptr) {
226 }
227 }
228
195 - debug(D_WEB_CLIENT, "LISTENER: exit!");
196 - listen_sockets_close(&api_sockets);
229 + pthread_cleanup_pop(1);
230
198 - freez(fds);
199 -
200 - static_thread->enabled = 0;
231 pthread_exit(NULL);
232 return NULL;
233 }
@@ -246,9 +276,22 @@ static inline int single_threaded_unlink_client(struct web_client *w, fd_set *if
276 return 0;
277 }
278
249 -void *socket_listen_main_single_threaded(void *ptr) {
250 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
279 +static void socket_listen_main_single_threaded_cleanup(void *data) {
280 + struct netdata_static_thread *static_thread = (struct netdata_static_thread *)data;
281 + if(static_thread->enabled) {
282 + static_thread->enabled = 0;
283 +
284 + info("LISTENER: single-threaded web server cleaning up...");
285 +
286 + info("LISTENER: closing all sockets...");
287 + listen_sockets_close(&api_sockets);
288
289 + info("LISTENER: cleanup completed.");
290 + debug(D_WEB_CLIENT, "LISTENER: exit!");
291 + }
292 +}
293 +
294 +void *socket_listen_main_single_threaded(void *ptr) {
295 web_server_mode = WEB_SERVER_MODE_SINGLE_THREADED;
296
297 info("Single-threaded WEB SERVER thread created with task id %d", gettid());
@@ -275,6 +318,8 @@ void *socket_listen_main_single_threaded(void *ptr) {
318 FD_ZERO (&efds);
319 int fdmax = 0;
320
321 + pthread_cleanup_push(socket_listen_main_single_threaded_cleanup, ptr);
322 +
323 for(i = 0; i < api_sockets.opened ; i++) {
324 if (api_sockets.fds[i] < 0 || api_sockets.fds[i] >= (int)FD_SETSIZE)
325 fatal("LISTENER: Listen socket %d is not ready, or invalid.", api_sockets.fds[i]);
@@ -287,7 +332,7 @@ void *socket_listen_main_single_threaded(void *ptr) {
332 fdmax = api_sockets.fds[i];
333 }
334
290 - for(;;) {
335 + while(!netdata_exit) {
336 debug(D_WEB_CLIENT_ACCESS, "LISTENER: single threaded web server waiting (fdmax = %d)...", fdmax);
337
338 struct timeval tv = { .tv_sec = 1, .tv_usec = 0 };
@@ -370,10 +415,8 @@ void *socket_listen_main_single_threaded(void *ptr) {
415 }
416 }
417
373 - debug(D_WEB_CLIENT, "LISTENER: exit!");
374 - listen_sockets_close(&api_sockets);
418 + pthread_cleanup_pop(1);
419
376 - static_thread->enabled = 0;
420 pthread_exit(NULL);
421 return NULL;
422 }