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
}