diff options
-rwxr-xr-x | CMakeLists.txt | 10 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/locks.c | 319 | ||||
-rw-r--r-- | src/locks.h | 289 | ||||
-rw-r--r-- | src/main.c | 62 | ||||
-rw-r--r-- | src/main.h | 4 | ||||
-rw-r--r-- | src/plugin_tc.c | 31 | ||||
-rw-r--r-- | src/plugins_d.c | 85 | ||||
-rw-r--r-- | src/plugins_d.h | 7 | ||||
-rw-r--r-- | src/popen.c | 2 | ||||
-rw-r--r-- | src/popen.h | 2 | ||||
-rw-r--r-- | src/statsd.c | 33 | ||||
-rw-r--r-- | src/web_server.c | 87 |
13 files changed, 546 insertions, 389 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index f0c0d519b1..71d6d94fd8 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,7 +63,8 @@ set(NETDATA_LINUX_FILES src/proc_uptime.c src/sys_kernel_mm_ksm.c src/sys_fs_cgroup.c - src/sys_fs_btrfs.c) + src/sys_fs_btrfs.c + ) set(NETDATA_COMMON_FILES src/adaptive_resortable_list.c @@ -94,6 +95,7 @@ set(NETDATA_COMMON_FILES src/health_json.c src/health_log.c src/inlined.h + src/locks.c src/locks.h src/log.c src/log.h @@ -189,6 +191,8 @@ set(APPS_PLUGIN_SOURCE_FILES src/clocks.c src/clocks.h src/inlined.h + src/locks.c + src/locks.h src/log.c src/log.h src/procfile.c @@ -205,6 +209,8 @@ set(FREEIPMI_PLUGIN_SOURCE_FILES src/clocks.c src/clocks.h src/inlined.h + src/locks.c + src/locks.h src/log.c src/log.h src/procfile.c @@ -219,6 +225,8 @@ set(CGROUP_NETWORK_SOURCE_FILES src/clocks.c src/clocks.h src/inlined.h + src/locks.c + src/locks.h src/log.c src/log.h src/procfile.c diff --git a/src/Makefile.am b/src/Makefile.am index 577871392f..f6589da7ba 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -70,6 +70,7 @@ netdata_SOURCES = \ health_json.c \ health_log.c \ inlined.h \ + locks.c \ locks.h \ log.c \ log.h \ @@ -227,6 +228,7 @@ apps_plugin_SOURCES = \ clocks.c clocks.h \ common.c common.h \ inlined.h \ + locks.c locks.h \ log.c log.h \ procfile.c procfile.h \ web_buffer.c web_buffer.h \ @@ -248,6 +250,7 @@ freeipmi_plugin_SOURCES = \ clocks.c clocks.h \ common.c common.h \ inlined.h \ + locks.c locks.h \ log.c log.h \ procfile.c procfile.h \ $(NULL) @@ -261,6 +264,7 @@ cgroup_network_SOURCES = \ clocks.c clocks.h \ common.c common.h \ inlined.h \ + locks.c locks.h \ log.c log.h \ procfile.c procfile.h \ popen.c popen.h \ diff --git a/src/locks.c b/src/locks.c new file mode 100644 index 0000000000..bec45175be --- /dev/null +++ b/src/locks.c @@ -0,0 +1,319 @@ +#include "common.h" + +// ---------------------------------------------------------------------------- +// automatic thread cancelability management, based on locks + +static __thread int netdata_thread_first_cancelability = 0; +static __thread int netdata_thread_lock_cancelability = 0; + +static inline void netdata_thread_disable_cancelability(void) { + int old; + int ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old); + if(ret != 0) + error("THREAD_CANCELABILITY: pthread_setcancelstate() returned error %d", ret); + else { + if(!netdata_thread_lock_cancelability) + netdata_thread_first_cancelability = old; + + netdata_thread_lock_cancelability++; + } +} + +static inline void netdata_thread_enable_cancelability(void) { + if(netdata_thread_lock_cancelability < 1) { + error("THREAD_CANCELABILITY: netdata_thread_enable_cancelability(): oops! invalid thread cancelability count %d - results will be undefined - please report this!", netdata_thread_lock_cancelability); + } + else if(netdata_thread_lock_cancelability == 1) { + int old = 1; + int ret = pthread_setcancelstate(netdata_thread_first_cancelability, &old); + if(ret != 0) + error("THREAD_CANCELABILITY: pthread_setcancelstate() returned error %d", ret); + else { + if(!old) + error("THREAD_CANCELABILITY: netdata_thread_enable_cancelability(): oops! old thread cancelability was changed, expected ENABLED, found DISABLED - please report this!"); + } + + netdata_thread_lock_cancelability = 0; + } + else + netdata_thread_lock_cancelability--; +} + +// ---------------------------------------------------------------------------- +// mutex + +int __netdata_mutex_init(netdata_mutex_t *mutex) { + int ret = pthread_mutex_init(mutex, NULL); + if(unlikely(ret != 0)) + error("MUTEX_LOCK: failed to initialize (code %d).", ret); + return ret; +} + +int __netdata_mutex_lock(netdata_mutex_t *mutex) { + netdata_thread_disable_cancelability(); + + int ret = pthread_mutex_lock(mutex); + if(unlikely(ret != 0)) { + netdata_thread_enable_cancelability(); + error("MUTEX_LOCK: failed to get lock (code %d)", ret); + } + return ret; +} + +int __netdata_mutex_trylock(netdata_mutex_t *mutex) { + netdata_thread_disable_cancelability(); + + int ret = pthread_mutex_trylock(mutex); + if(ret != 0) + netdata_thread_enable_cancelability(); + + return ret; +} + +int __netdata_mutex_unlock(netdata_mutex_t *mutex) { + int ret = pthread_mutex_unlock(mutex); + if(unlikely(ret != 0)) + error("MUTEX_LOCK: failed to unlock (code %d).", ret); + else + netdata_thread_enable_cancelability(); + + return ret; +} + +int netdata_mutex_init_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) { + usec_t start = 0; + + if(unlikely(debug_flags & D_LOCKS)) { + start = now_boottime_usec(); + debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_init(0x%p) from %lu@%s, %s()", mutex, line, file, function); + } + + int ret = __netdata_mutex_init(mutex); + + 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); + + return ret; +} + +int netdata_mutex_lock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) { + usec_t start = 0; + + if(unlikely(debug_flags & D_LOCKS)) { + start = now_boottime_usec(); + debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_lock(0x%p) from %lu@%s, %s()", mutex, line, file, function); + } + + int ret = __netdata_mutex_lock(mutex); + + 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); + + return ret; +} + +int netdata_mutex_trylock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) { + usec_t start = 0; + + if(unlikely(debug_flags & D_LOCKS)) { + start = now_boottime_usec(); + debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_trylock(0x%p) from %lu@%s, %s()", mutex, line, file, function); + } + + int ret = __netdata_mutex_trylock(mutex); + + 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); + + return ret; +} + +int netdata_mutex_unlock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) { + usec_t start = 0; + + if(unlikely(debug_flags & D_LOCKS)) { + start = now_boottime_usec(); + debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_unlock(0x%p) from %lu@%s, %s()", mutex, line, file, function); + } + + int ret = __netdata_mutex_unlock(mutex); + + 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); + + return ret; +} + + +// ---------------------------------------------------------------------------- +// r/w lock + +int __netdata_rwlock_destroy(netdata_rwlock_t *rwlock) { + int ret = pthread_rwlock_destroy(rwlock); + if(unlikely(ret != 0)) + error("RW_LOCK: failed to destroy lock (code %d)", ret); + return ret; +} + +int __netdata_rwlock_init(netdata_rwlock_t *rwlock) { + int ret = pthread_rwlock_init(rwlock, NULL); + if(unlikely(ret != 0)) + error("RW_LOCK: failed to initialize lock (code %d)", ret); + return ret; +} + +int __netdata_rwlock_rdlock(netdata_rwlock_t *rwlock) { + netdata_thread_disable_cancelability(); + + int ret = pthread_rwlock_rdlock(rwlock); + if(unlikely(ret != 0)) { + netdata_thread_enable_cancelability(); + error("RW_LOCK: failed to obtain read lock (code %d)", ret); + } + + return ret; +} + +int __netdata_rwlock_wrlock(netdata_rwlock_t *rwlock) { + netdata_thread_disable_cancelability(); + + int ret = pthread_rwlock_wrlock(rwlock); + if(unlikely(ret != 0)) { + error("RW_LOCK: failed to obtain write lock (code %d)", ret); + netdata_thread_enable_cancelability(); + } + + return ret; +} + +int __netdata_rwlock_unlock(netdata_rwlock_t *rwlock) { + int ret = pthread_rwlock_unlock(rwlock); + if(unlikely(ret != 0)) + error("RW_LOCK: failed to release lock (code %d)", ret); + else + netdata_thread_enable_cancelability(); + + return ret; +} + +int __netdata_rwlock_tryrdlock(netdata_rwlock_t *rwlock) { + netdata_thread_disable_cancelability(); + + int ret = pthread_rwlock_tryrdlock(rwlock); + if(ret != 0) + netdata_thread_enable_cancelability(); + + return ret; +} + +int __netdata_rwlock_trywrlock(netdata_rwlock_t *rwlock) { + netdata_thread_disable_cancelability(); + + int ret = pthread_rwlock_trywrlock(rwlock); + if(ret != 0) + netdata_thread_enable_cancelability(); + + return ret; +} + + +int netdata_rwlock_destroy_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) { + usec_t start = 0; + + if(unlikely(debug_flags & D_LOCKS)) { + start = now_boottime_usec(); + debug(D_LOCKS, "RW_LOCK: netdata_rwlock_destroy(0x%p) from %lu@%s, %s()", rwlock, line, file, function); + } + + int ret = __netdata_rwlock_destroy(rwlock); + + 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); + + return ret; +} + +int netdata_rwlock_init_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) { + usec_t start = 0; + + if(unlikely(debug_flags & D_LOCKS)) { + start = now_boottime_usec(); + debug(D_LOCKS, "RW_LOCK: netdata_rwlock_init(0x%p) from %lu@%s, %s()", rwlock, line, file, function); + } + + int ret = __netdata_rwlock_init(rwlock); + + 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); + + return ret; +} + +int netdata_rwlock_rdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) { + usec_t start = 0; + + if(unlikely(debug_flags & D_LOCKS)) { + start = now_boottime_usec(); + debug(D_LOCKS, "RW_LOCK: netdata_rwlock_rdlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function); + } + + int ret = __netdata_rwlock_rdlock(rwlock); + + 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); + + return ret; +} + +int netdata_rwlock_wrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) { + usec_t start = 0; + + if(unlikely(debug_flags & D_LOCKS)) { + start = now_boottime_usec(); + debug(D_LOCKS, "RW_LOCK: netdata_rwlock_wrlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function); + } + + int ret = __netdata_rwlock_wrlock(rwlock); + + 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); + + return ret; +} + +int netdata_rwlock_unlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) { + usec_t start = 0; + + if(unlikely(debug_flags & D_LOCKS)) { + start = now_boottime_usec(); + debug(D_LOCKS, "RW_LOCK: netdata_rwlock_unlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function); + } + + int ret = __netdata_rwlock_unlock(rwlock); + + 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); + + return ret; +} + +int netdata_rwlock_tryrdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) { + usec_t start = 0; + + if(unlikely(debug_flags & D_LOCKS)) { + start = now_boottime_usec(); + debug(D_LOCKS, "RW_LOCK: netdata_rwlock_tryrdlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function); + } + + int ret = __netdata_rwlock_tryrdlock(rwlock); + + 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); + + return ret; +} + +int netdata_rwlock_trywrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) { + usec_t start = 0; + + if(unlikely(debug_flags & D_LOCKS)) { + start = now_boottime_usec(); + debug(D_LOCKS, "RW_LOCK: netdata_rwlock_trywrlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function); + } + + int ret = __netdata_rwlock_trywrlock(rwlock); + + 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); + + return ret; +} diff --git a/src/locks.h b/src/locks.h index 76533f636e..39cfe849fa 100644 --- a/src/locks.h +++ b/src/locks.h @@ -1,276 +1,46 @@ #ifndef NETDATA_LOCKS_H #define NETDATA_LOCKS_H -// ---------------------------------------------------------------------------- -// mutex - typedef pthread_mutex_t netdata_mutex_t; - #define NETDATA_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER -static inline int __netdata_mutex_init(netdata_mutex_t *mutex) { - int ret = pthread_mutex_init(mutex, NULL); - if(unlikely(ret != 0)) - error("MUTEX_LOCK: failed to initialize (code %d).", ret); - return ret; -} - -static inline int __netdata_mutex_lock(netdata_mutex_t *mutex) { - int ret = pthread_mutex_lock(mutex); - if(unlikely(ret != 0)) - error("MUTEX_LOCK: failed to get lock (code %d)", ret); - return ret; -} +typedef pthread_rwlock_t netdata_rwlock_t; +#define NETDATA_RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER -static inline int __netdata_mutex_trylock(netdata_mutex_t *mutex) { - int ret = pthread_mutex_trylock(mutex); - return ret; -} +extern int __netdata_mutex_init(netdata_mutex_t *mutex); +extern int __netdata_mutex_lock(netdata_mutex_t *mutex); +extern int __netdata_mutex_trylock(netdata_mutex_t *mutex); +extern int __netdata_mutex_unlock(netdata_mutex_t *mutex); + +extern int __netdata_rwlock_destroy(netdata_rwlock_t *rwlock); +extern int __netdata_rwlock_init(netdata_rwlock_t *rwlock); +extern int __netdata_rwlock_rdlock(netdata_rwlock_t *rwlock); +extern int __netdata_rwlock_wrlock(netdata_rwlock_t *rwlock); +extern int __netdata_rwlock_unlock(netdata_rwlock_t *rwlock); +extern int __netdata_rwlock_tryrdlock(netdata_rwlock_t *rwlock); +extern int __netdata_rwlock_trywrlock(netdata_rwlock_t *rwlock); + +extern int netdata_mutex_init_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex); +extern int netdata_mutex_lock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex); +extern int netdata_mutex_trylock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex); +extern int netdata_mutex_unlock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex); + +extern int netdata_rwlock_destroy_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock); +extern int netdata_rwlock_init_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock); +extern int netdata_rwlock_rdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock); +extern int netdata_rwlock_wrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock); +extern int netdata_rwlock_unlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock); +extern int netdata_rwlock_tryrdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock); +extern int netdata_rwlock_trywrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock); -static inline int __netdata_mutex_unlock(netdata_mutex_t *mutex) { - int ret = pthread_mutex_unlock(mutex); - if(unlikely(ret != 0)) - error("MUTEX_LOCK: failed to unlock (code %d).", ret); - return ret; -} #ifdef NETDATA_INTERNAL_CHECKS -static inline int netdata_mutex_init_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) { - usec_t start = 0; - - if(unlikely(debug_flags & D_LOCKS)) { - start = now_boottime_usec(); - debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_init(0x%p) from %lu@%s, %s()", mutex, line, file, function); - } - - int ret = __netdata_mutex_init(mutex); - - 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); - - return ret; -} - -static inline int netdata_mutex_lock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) { - usec_t start = 0; - - if(unlikely(debug_flags & D_LOCKS)) { - start = now_boottime_usec(); - debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_lock(0x%p) from %lu@%s, %s()", mutex, line, file, function); - } - - int ret = __netdata_mutex_lock(mutex); - - 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); - - return ret; -} - -static inline int netdata_mutex_trylock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) { - usec_t start = 0; - - if(unlikely(debug_flags & D_LOCKS)) { - start = now_boottime_usec(); - debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_trylock(0x%p) from %lu@%s, %s()", mutex, line, file, function); - } - - int ret = __netdata_mutex_trylock(mutex); - - 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); - - return ret; -} - -static inline int netdata_mutex_unlock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) { - usec_t start = 0; - - if(unlikely(debug_flags & D_LOCKS)) { - start = now_boottime_usec(); - debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_unlock(0x%p) from %lu@%s, %s()", mutex, line, file, function); - } - - int ret = __netdata_mutex_unlock(mutex); - - 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); - - return ret; -} - #define netdata_mutex_init(mutex) netdata_mutex_init_debug(__FILE__, __FUNCTION__, __LINE__, mutex) #define netdata_mutex_lock(mutex) netdata_mutex_lock_debug(__FILE__, __FUNCTION__, __LINE__, mutex) #define netdata_mutex_trylock(mutex) netdata_mutex_trylock_debug(__FILE__, __FUNCTION__, __LINE__, mutex) #define netdata_mutex_unlock(mutex) netdata_mutex_unlock_debug(__FILE__, __FUNCTION__, __LINE__, mutex) -#else // !NETDATA_INTERNAL_CHECKS - -#define netdata_mutex_init(mutex) __netdata_mutex_init(mutex) -#define netdata_mutex_lock(mutex) __netdata_mutex_lock(mutex) -#define netdata_mutex_trylock(mutex) __netdata_mutex_trylock(mutex) -#define netdata_mutex_unlock(mutex) __netdata_mutex_unlock(mutex) - -#endif // NETDATA_INTERNAL_CHECKS - - -// ---------------------------------------------------------------------------- -// r/w lock - -typedef pthread_rwlock_t netdata_rwlock_t; - -#define NETDATA_RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER - -static inline int __netdata_rwlock_destroy(netdata_rwlock_t *rwlock) { - int ret = pthread_rwlock_destroy(rwlock); - if(unlikely(ret != 0)) - error("RW_LOCK: failed to destroy lock (code %d)", ret); - return ret; -} - -static inline int __netdata_rwlock_init(netdata_rwlock_t *rwlock) { - int ret = pthread_rwlock_init(rwlock, NULL); - if(unlikely(ret != 0)) - error("RW_LOCK: failed to initialize lock (code %d)", ret); - return ret; -} - -static inline int __netdata_rwlock_rdlock(netdata_rwlock_t *rwlock) { - int ret = pthread_rwlock_rdlock(rwlock); - if(unlikely(ret != 0)) - error("RW_LOCK: failed to obtain read lock (code %d)", ret); - return ret; -} - -static inline int __netdata_rwlock_wrlock(netdata_rwlock_t *rwlock) { - int ret = pthread_rwlock_wrlock(rwlock); - if(unlikely(ret != 0)) - error("RW_LOCK: failed to obtain write lock (code %d)", ret); - return ret; -} - -static inline int __netdata_rwlock_unlock(netdata_rwlock_t *rwlock) { - int ret = pthread_rwlock_unlock(rwlock); - if(unlikely(ret != 0)) - error("RW_LOCK: failed to release lock (code %d)", ret); - return ret; -} - -static inline int __netdata_rwlock_tryrdlock(netdata_rwlock_t *rwlock) { - int ret = pthread_rwlock_tryrdlock(rwlock); - return ret; -} - -static inline int __netdata_rwlock_trywrlock(netdata_rwlock_t *rwlock) { - int ret = pthread_rwlock_trywrlock(rwlock); - return ret; -} - - -#ifdef NETDATA_INTERNAL_CHECKS - -static inline int netdata_rwlock_destroy_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) { - usec_t start = 0; - - if(unlikely(debug_flags & D_LOCKS)) { - start = now_boottime_usec(); - debug(D_LOCKS, "RW_LOCK: netdata_rwlock_destroy(0x%p) from %lu@%s, %s()", rwlock, line, file, function); - } - - int ret = __netdata_rwlock_destroy(rwlock); - - 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); - - return ret; -} - -static inline int netdata_rwlock_init_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) { - usec_t start = 0; - - if(unlikely(debug_flags & D_LOCKS)) { - start = now_boottime_usec(); - debug(D_LOCKS, "RW_LOCK: netdata_rwlock_init(0x%p) from %lu@%s, %s()", rwlock, line, file, function); - } - - int ret = __netdata_rwlock_init(rwlock); - - 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); - - return ret; -} - -static inline int netdata_rwlock_rdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) { - usec_t start = 0; - - if(unlikely(debug_flags & D_LOCKS)) { - start = now_boottime_usec(); - debug(D_LOCKS, "RW_LOCK: netdata_rwlock_rdlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function); - } - - int ret = __netdata_rwlock_rdlock(rwlock); - - 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); - - return ret; -} - -static inline int netdata_rwlock_wrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) { - usec_t start = 0; - - if(unlikely(debug_flags & D_LOCKS)) { - start = now_boottime_usec(); - debug(D_LOCKS, "RW_LOCK: netdata_rwlock_wrlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function); - } - - int ret = __netdata_rwlock_wrlock(rwlock); - - 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); - - return ret; -} - -static inline int netdata_rwlock_unlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) { - usec_t start = 0; - - if(unlikely(debug_flags & D_LOCKS)) { - start = now_boottime_usec(); - debug(D_LOCKS, "RW_LOCK: netdata_rwlock_unlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function); - } - - int ret = __netdata_rwlock_unlock(rwlock); - - 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); - - return ret; -} - -static inline int netdata_rwlock_tryrdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) { - usec_t start = 0; - - if(unlikely(debug_flags & D_LOCKS)) { - start = now_boottime_usec(); - debug(D_LOCKS, "RW_LOCK: netdata_rwlock_tryrdlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function); - } - - int ret = __netdata_rwlock_tryrdlock(rwlock); - - 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); - - return ret; -} - -static inline int netdata_rwlock_trywrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) { - usec_t start = 0; - - if(unlikely(debug_flags & D_LOCKS)) { - start = now_boottime_usec(); - debug(D_LOCKS, "RW_LOCK: netdata_rwlock_trywrlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function); - } - - int ret = __netdata_rwlock_trywrlock(rwlock); - - 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); - - return ret; -} - #define netdata_rwlock_destroy(rwlock) netdata_rwlock_destroy_debug(__FILE__, __FUNCTION__, __LINE__, rwlock) #define netdata_rwlock_init(rwlock) netdata_rwlock_init_debug(__FILE__, __FUNCTION__, __LINE__, rwlock) #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 * #else // !NETDATA_INTERNAL_CHECKS +#define netdata_mutex_init(mutex) __netdata_mutex_init(mutex) +#define netdata_mutex_lock(mutex) __netdata_mutex_lock(mutex) +#define netdata_mutex_trylock(mutex) __netdata_mutex_trylock(mutex) +#define netdata_mutex_unlock(mutex) __netdata_mutex_unlock(mutex) + #define netdata_rwlock_destroy(rwlock) __netdata_rwlock_destroy(rwlock) #define netdata_rwlock_init(rwlock) __netdata_rwlock_init(rwlock) #define netdata_rwlock_rdlock(rwlock) __netdata_rwlock_rdlock(rwlock) diff --git a/src/main.c b/src/main.c index 806028d476..3b7c479d58 100644 --- a/src/main.c +++ b/src/main.c @@ -6,33 +6,28 @@ void netdata_cleanup_and_exit(int ret) { netdata_exit = 1; error_log_limit_unlimited(); - info("netdata is preparing to exit..."); + info("MAIN: netdata prepares to exit..."); - // allow all the threads to cleanup by themselves - unsigned int w = (unsigned int)default_rrd_update_every + 2; - info("Giving %u secs to background threads to cleanup...", w); - sleep(w); - - // kill all threads and childs - //info("Stopping all threads and child processes..."); - //kill_childs(); + // stop everything + info("MAIN: stopping all threads and child processes..."); + cancel_main_threads(); // cleanup the database (delete files not needed) - info("Cleaning up the database..."); + info("MAIN: cleaning up the database..."); rrdhost_cleanup_all(); // free the database - //info("Freeing database memory..."); - //rrdhost_free_all(); + info("MAIN: freeing database memory..."); + rrdhost_free_all(); // unlink the pid if(pidfile[0]) { - info("Removing netdata PID file '%s'...", pidfile); + info("MAIN: removing netdata PID file '%s'...", pidfile); if(unlink(pidfile) != 0) - error("Cannot unlink pidfile '%s'.", pidfile); + error("MAIN: cannot unlink pidfile '%s'.", pidfile); } - info("All done - netdata is now exiting - bye bye..."); + info("MAIN: all done - netdata is now exiting - bye bye..."); exit(ret); } @@ -182,50 +177,29 @@ int killpid(pid_t pid, int sig) return ret; } -void kill_childs() { +void cancel_main_threads() { error_log_limit_unlimited(); - siginfo_t info; - - struct web_client *w; - for(w = web_clients; w ; w = w->next) { - info("Stopping web client %s", w->client_ip); - int ret; - if((ret = pthread_cancel(w->thread)) != 0) - error("pthread_cancel() failed with code %d.", ret); - - WEB_CLIENT_IS_OBSOLETE(w); - } - int i; for (i = 0; static_threads[i].name != NULL ; i++) { if(static_threads[i].enabled) { - info("Stopping %s thread", static_threads[i].name); + info("MAIN: Calling pthread_cancel() on %s thread", static_threads[i].name); int ret; if((ret = pthread_cancel(*static_threads[i].thread)) != 0) - error("pthread_cancel() failed with code %d.", ret); + error("MAIN: pthread_cancel() failed with code %d.", ret); + else + info("MAIN: thread %s cancelled", static_threads[i].name); static_threads[i].enabled = 0; } } - if(tc_child_pid) { - info("Killing tc-qos-helper process %d", tc_child_pid); - if(killpid(tc_child_pid, SIGTERM) != -1) - waitid(P_PID, (id_t) tc_child_pid, &info, WEXITED); - - tc_child_pid = 0; - } - - // stop all running plugins - pluginsd_stop_all_external_plugins(); - // if, for any reason there is any child exited // catch it here - info("Cleaning up an other children"); + info("MAIN: waiting for any unfinished child processes"); + siginfo_t info; waitid(P_PID, 0, &info, WEXITED|WNOHANG); - - info("All threads/childs stopped."); + info("MAIN: all threads/childs stopped."); } struct option_def option_definitions[] = { diff --git a/src/main.h b/src/main.h index 09567bc7c9..e9d0fcc92e 100644 --- a/src/main.h +++ b/src/main.h @@ -22,7 +22,7 @@ struct netdata_static_thread { char *config_section; char *config_name; - volatile int enabled; + volatile sig_atomic_t enabled; pthread_t *thread; @@ -30,7 +30,7 @@ struct netdata_static_thread { void *(*start_routine) (void *); }; -extern void kill_childs(void); +extern void cancel_main_threads(void); extern int killpid(pid_t pid, int signal); extern void netdata_cleanup_and_exit(int ret) NORETURN; diff --git a/src/plugin_tc.c b/src/plugin_tc.c index 0d8fd3d6b8..fbfc9d342c 100644 --- a/src/plugin_tc.c +++ b/src/plugin_tc.c @@ -829,9 +829,30 @@ static inline void tc_split_words(char *str, char **words, int max_words) { } volatile pid_t tc_child_pid = 0; -void *tc_main(void *ptr) { + +static void tc_main_cleanup(void *ptr) { struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr; + if(static_thread->enabled) { + static_thread->enabled = 0; + + info("TC: cleaning up..."); + + if(tc_child_pid) { + info("TC: killing with SIGTERM tc-qos-helper process %d", tc_child_pid); + if(killpid(tc_child_pid, SIGTERM) != -1) { + siginfo_t info; + + info("TC: waiting for tc plugin child process pid %d to exit...", tc_child_pid); + waitid(P_PID, (id_t) tc_child_pid, &info, WEXITED); + // info("TC: finished tc plugin child process pid %d.", tc_child_pid); + } + tc_child_pid = 0; + } + } +} + +void *tc_main(void *ptr) { info("TC thread created with task id %d", gettid()); if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0) @@ -863,10 +884,10 @@ void *tc_main(void *ptr) { snprintfz(buffer, TC_LINE_MAX, "%s/tc-qos-helper.sh", netdata_configured_plugins_dir); char *tc_script = config_get("plugin:tc", "script to run to get tc values", |