summaryrefslogtreecommitdiffstats
path: root/src/libnetdata/locks
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/libnetdata/locks/README.md107
-rw-r--r--src/libnetdata/locks/locks.c (renamed from libnetdata/locks/locks.c)291
-rw-r--r--src/libnetdata/locks/locks.h (renamed from libnetdata/locks/locks.h)50
3 files changed, 305 insertions, 143 deletions
diff --git a/src/libnetdata/locks/README.md b/src/libnetdata/locks/README.md
new file mode 100644
index 000000000..35d602f2a
--- /dev/null
+++ b/src/libnetdata/locks/README.md
@@ -0,0 +1,107 @@
+<!--
+title: "Locks"
+custom_edit_url: https://github.com/netdata/netdata/edit/master/src/libnetdata/locks/README.md
+sidebar_label: "Locks"
+learn_status: "Published"
+learn_topic_type: "Tasks"
+learn_rel_path: "Developers/libnetdata"
+-->
+
+# Locks
+
+## How to trace netdata locks
+
+To enable tracing rwlocks in netdata, compile netdata by setting `CFLAGS="-DNETDATA_TRACE_RWLOCKS=1"`, like this:
+
+```
+CFLAGS="-O1 -ggdb -DNETDATA_TRACE_RWLOCKS=1" ./netdata-installer.sh
+```
+
+During compilation, the compiler will log:
+
+```
+libnetdata/locks/locks.c:105:2: warning: #warning NETDATA_TRACE_RWLOCKS ENABLED - EXPECT A LOT OF OUTPUT [-Wcpp]
+ 105 | #warning NETDATA_TRACE_RWLOCKS ENABLED - EXPECT A LOT OF OUTPUT
+ | ^~~~~~~
+```
+
+Once compiled, netdata will do the following:
+
+Every call to `netdata_rwlock_*()` is now measured in time.
+
+### logging of slow locks/unlocks
+
+If any call takes more than 10 usec, it will be logged like this:
+
+```
+RW_LOCK ON LOCK 0x0x7fbe1f2e5190: 4157038, 'ACLK_Query_2' (function build_context_param_list() 99@web/api/formatters/rrd2json.c) WAITED to UNLOCK for 29 usec.
+```
+
+The time can be changed by setting this `-DNETDATA_TRACE_RWLOCKS_WAIT_TIME_TO_IGNORE_USEC=20` (or whatever number) to the CFLAGS.
+
+### logging of long hold times
+
+If any lock is holded for more than 10000 usec, it will be logged like this:
+
+```
+RW_LOCK ON LOCK 0x0x55a20afc1b20: 4187198, 'ANALYTICS' (function analytics_gather_mutable_meta_data() 532@daemon/analytics.c) holded a 'R' for 13232 usec.
+```
+
+The time can be changed by setting this `-DNETDATA_TRACE_RWLOCKS_HOLD_TIME_TO_IGNORE_USEC=20000` (or whatever number) to the CFLAGS.
+
+### logging for probable pauses (predictive)
+
+The library maintains a linked-list of all the lock holders (one entry per thread). For this linked-list a mutex is used. So every call to the r/w locks now also has a mutex lock.
+
+If any call is expected to pause the caller (ie the caller is attempting a read lock while there is a write lock in place and vice versa), the library will log something like this:
+
+```
+RW_LOCK ON LOCK 0x0x5651c9fcce20: 4190039 'HEALTH' (function health_execute_pending_updates() 661@health/health.c) WANTS a 'W' lock (while holding 1 rwlocks and 1 mutexes).
+There are 7 readers and 0 writers are holding the lock:
+ => 1: RW_LOCK: process 4190091 'WEB_SERVER[static14]' (function web_client_api_request_v1_data() 526@web/api/web_api_v1.c) is having 1 'R' lock for 709847 usec.
+ => 2: RW_LOCK: process 4190079 'WEB_SERVER[static6]' (function web_client_api_request_v1_data() 526@web/api/web_api_v1.c) is having 1 'R' lock for 709869 usec.
+ => 3: RW_LOCK: process 4190084 'WEB_SERVER[static10]' (function web_client_api_request_v1_data() 526@web/api/web_api_v1.c) is having 1 'R' lock for 709948 usec.
+ => 4: RW_LOCK: process 4190076 'WEB_SERVER[static3]' (function web_client_api_request_v1_data() 526@web/api/web_api_v1.c) is having 1 'R' lock for 710190 usec.
+ => 5: RW_LOCK: process 4190092 'WEB_SERVER[static15]' (function web_client_api_request_v1_data() 526@web/api/web_api_v1.c) is having 1 'R' lock for 710195 usec.
+ => 6: RW_LOCK: process 4190077 'WEB_SERVER[static4]' (function web_client_api_request_v1_data() 526@web/api/web_api_v1.c) is having 1 'R' lock for 710208 usec.
+ => 7: RW_LOCK: process 4190044 'WEB_SERVER[static1]' (function web_client_api_request_v1_data() 526@web/api/web_api_v1.c) is having 1 'R' lock for 710221 usec.
+```
+
+And each of the above is paired with a `GOT` log, like this:
+
+```
+RW_LOCK ON LOCK 0x0x5651c9fcce20: 4190039 'HEALTH' (function health_execute_pending_updates() 661@health/health.c) GOT a 'W' lock (while holding 2 rwlocks and 1 mutexes).
+There are 0 readers and 1 writers are holding the lock:
+ => 1: RW_LOCK: process 4190039 'HEALTH' (function health_execute_pending_updates() 661@health/health.c) is having 1 'W' lock for 36 usec.
+```
+
+Keep in mind that the lock and log are not atomic. The list of callers is indicative (and sometimes just empty because the original holders of the lock, unlocked it until we had the chance to print their names).
+
+### POSIX compliance check
+
+The library may also log messages about POSIX unsupported cases, like this:
+
+```
+RW_LOCK FATAL ON LOCK 0x0x622000109290: 3609368 'PLUGIN[proc]' (function __rrdset_check_rdlock() 10@database/rrdset.c) attempts to acquire a 'W' lock.
+But it is not supported by POSIX because: ALREADY HAS THIS LOCK
+At this attempt, the task is holding 1 rwlocks and 1 mutexes.
+There are 1 readers and 0 writers are holding the lock requested now:
+ => 1: RW_LOCK: process 3609368 'PLUGIN[proc]' (function rrdset_done() 1398@database/rrdset.c) is having 1 'R' lock for 0 usec.
+```
+
+### nested read locks
+
+When compiled with `-DNETDATA_TRACE_RWLOCKS_LOG_NESTED=1` the library will also detect nested read locks and print them like this:
+
+```
+RW_LOCK ON LOCK 0x0x7ff6ea46d190: 4140225 'WEB_SERVER[static14]' (function rrdr_json_wrapper_begin() 34@web/api/formatters/json_wrapper.c) NESTED READ LOCK REQUEST a 'R' lock (while holding 1 rwlocks and 1 mutexes).
+There are 5 readers and 0 writers are holding the lock:
+ => 1: RW_LOCK: process 4140225 'WEB_SERVER[static14]' (function rrdr_lock_rrdset() 70@web/api/queries/rrdr.c) is having 1 'R' lock for 216667 usec.
+ => 2: RW_LOCK: process 4140211 'WEB_SERVER[static6]' (function rrdr_lock_rrdset() 70@web/api/queries/rrdr.c) is having 1 'R' lock for 220001 usec.
+ => 3: RW_LOCK: process 4140218 'WEB_SERVER[static8]' (function rrdr_lock_rrdset() 70@web/api/queries/rrdr.c) is having 1 'R' lock for 220001 usec.
+ => 4: RW_LOCK: process 4140224 'WEB_SERVER[static13]' (function rrdr_lock_rrdset() 70@web/api/queries/rrdr.c) is having 1 'R' lock for 220001 usec.
+ => 5: RW_LOCK: process 4140227 'WEB_SERVER[static16]' (function rrdr_lock_rrdset() 70@web/api/queries/rrdr.c) is having 1 'R' lock for 220001 usec.
+```
+
+
+
diff --git a/libnetdata/locks/locks.c b/src/libnetdata/locks/locks.c
index 625dd052c..424b86ce9 100644
--- a/libnetdata/locks/locks.c
+++ b/src/libnetdata/locks/locks.c
@@ -19,64 +19,6 @@
#endif // NETDATA_TRACE_RWLOCKS
// ----------------------------------------------------------------------------
-// automatic thread cancelability management, based on locks
-
-static __thread int netdata_thread_first_cancelability = 0;
-static __thread int netdata_thread_nested_disables = 0;
-
-static __thread size_t netdata_locks_acquired_rwlocks = 0;
-static __thread size_t netdata_locks_acquired_mutexes = 0;
-
-inline void netdata_thread_disable_cancelability(void) {
- if(!netdata_thread_nested_disables) {
- int old;
- int ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old);
-
- if(ret != 0)
- netdata_log_error("THREAD_CANCELABILITY: pthread_setcancelstate() on thread %s returned error %d",
- netdata_thread_tag(), ret);
-
- netdata_thread_first_cancelability = old;
- }
-
- netdata_thread_nested_disables++;
-}
-
-inline void netdata_thread_enable_cancelability(void) {
- if(unlikely(netdata_thread_nested_disables < 1)) {
- internal_fatal(true, "THREAD_CANCELABILITY: trying to enable cancelability, but it was not not disabled");
-
- netdata_log_error("THREAD_CANCELABILITY: netdata_thread_enable_cancelability(): invalid thread cancelability count %d "
- "on thread %s - results will be undefined - please report this!",
- netdata_thread_nested_disables, netdata_thread_tag());
-
- netdata_thread_nested_disables = 1;
- }
-
- if(netdata_thread_nested_disables == 1) {
- int old = 1;
- int ret = pthread_setcancelstate(netdata_thread_first_cancelability, &old);
- if(ret != 0)
- netdata_log_error("THREAD_CANCELABILITY: pthread_setcancelstate() on thread %s returned error %d",
- netdata_thread_tag(),
- ret);
- else {
- if(old != PTHREAD_CANCEL_DISABLE) {
- internal_fatal(true, "THREAD_CANCELABILITY: invalid old state cancelability");
-
- netdata_log_error("THREAD_CANCELABILITY: netdata_thread_enable_cancelability(): old thread cancelability "
- "on thread %s was changed, expected DISABLED (%d), found %s (%d) - please report this!",
- netdata_thread_tag(), PTHREAD_CANCEL_DISABLE,
- (old == PTHREAD_CANCEL_ENABLE) ? "ENABLED" : "UNKNOWN",
- old);
- }
- }
- }
-
- netdata_thread_nested_disables--;
-}
-
-// ----------------------------------------------------------------------------
// mutex
int __netdata_mutex_init(netdata_mutex_t *mutex) {
@@ -94,27 +36,22 @@ int __netdata_mutex_destroy(netdata_mutex_t *mutex) {
}
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();
netdata_log_error("MUTEX_LOCK: failed to get lock (code %d)", ret);
}
else
- netdata_locks_acquired_mutexes++;
+ nd_thread_mutex_locked();
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();
+ ;
else
- netdata_locks_acquired_mutexes++;
+ nd_thread_mutex_locked();
return ret;
}
@@ -123,10 +60,8 @@ int __netdata_mutex_unlock(netdata_mutex_t *mutex) {
int ret = pthread_mutex_unlock(mutex);
if(unlikely(ret != 0))
netdata_log_error("MUTEX_LOCK: failed to unlock (code %d).", ret);
- else {
- netdata_locks_acquired_mutexes--;
- netdata_thread_enable_cancelability();
- }
+ else
+ nd_thread_mutex_unlocked();
return ret;
}
@@ -226,65 +161,61 @@ int __netdata_rwlock_init(netdata_rwlock_t *rwlock) {
}
int __netdata_rwlock_rdlock(netdata_rwlock_t *rwlock) {
- netdata_thread_disable_cancelability();
-
int ret = pthread_rwlock_rdlock(&rwlock->rwlock_t);
- if(unlikely(ret != 0)) {
- netdata_thread_enable_cancelability();
+ if(unlikely(ret != 0))
netdata_log_error("RW_LOCK: failed to obtain read lock (code %d)", ret);
- }
else
- netdata_locks_acquired_rwlocks++;
+ nd_thread_rwlock_read_locked();
return ret;
}
int __netdata_rwlock_wrlock(netdata_rwlock_t *rwlock) {
- netdata_thread_disable_cancelability();
-
int ret = pthread_rwlock_wrlock(&rwlock->rwlock_t);
- if(unlikely(ret != 0)) {
+ if(unlikely(ret != 0))
netdata_log_error("RW_LOCK: failed to obtain write lock (code %d)", ret);
- netdata_thread_enable_cancelability();
- }
else
- netdata_locks_acquired_rwlocks++;
+ nd_thread_rwlock_write_locked();
return ret;
}
-int __netdata_rwlock_unlock(netdata_rwlock_t *rwlock) {
+int __netdata_rwlock_rdunlock(netdata_rwlock_t *rwlock) {
int ret = pthread_rwlock_unlock(&rwlock->rwlock_t);
if(unlikely(ret != 0))
netdata_log_error("RW_LOCK: failed to release lock (code %d)", ret);
- else {
- netdata_thread_enable_cancelability();
- netdata_locks_acquired_rwlocks--;
- }
+ else
+ nd_thread_rwlock_read_unlocked();
return ret;
}
-int __netdata_rwlock_tryrdlock(netdata_rwlock_t *rwlock) {
- netdata_thread_disable_cancelability();
+int __netdata_rwlock_wrunlock(netdata_rwlock_t *rwlock) {
+ int ret = pthread_rwlock_unlock(&rwlock->rwlock_t);
+ if(unlikely(ret != 0))
+ netdata_log_error("RW_LOCK: failed to release lock (code %d)", ret);
+ else
+ nd_thread_rwlock_write_unlocked();
+ return ret;
+}
+
+int __netdata_rwlock_tryrdlock(netdata_rwlock_t *rwlock) {
int ret = pthread_rwlock_tryrdlock(&rwlock->rwlock_t);
if(ret != 0)
- netdata_thread_enable_cancelability();
+ ;
else
- netdata_locks_acquired_rwlocks++;
+ nd_thread_rwlock_read_locked();
return ret;
}
int __netdata_rwlock_trywrlock(netdata_rwlock_t *rwlock) {
- netdata_thread_disable_cancelability();
-
int ret = pthread_rwlock_trywrlock(&rwlock->rwlock_t);
if(ret != 0)
- netdata_thread_enable_cancelability();
+ ;
else
- netdata_locks_acquired_rwlocks++;
+ nd_thread_rwlock_write_locked();
return ret;
}
@@ -293,18 +224,24 @@ int __netdata_rwlock_trywrlock(netdata_rwlock_t *rwlock) {
// spinlock implementation
// https://www.youtube.com/watch?v=rmGJc9PXpuE&t=41s
-void spinlock_init(SPINLOCK *spinlock) {
+#ifdef SPINLOCK_IMPL_WITH_MUTEX
+void spinlock_init(SPINLOCK *spinlock)
+{
+ netdata_mutex_init(&spinlock->inner);
+}
+#else
+void spinlock_init(SPINLOCK *spinlock)
+{
memset(spinlock, 0, sizeof(SPINLOCK));
}
-
-void spinlock_lock(SPINLOCK *spinlock) {
- static const struct timespec ns = { .tv_sec = 0, .tv_nsec = 1 };
-
-#ifdef NETDATA_INTERNAL_CHECKS
- size_t spins = 0;
#endif
- netdata_thread_disable_cancelability();
+#ifndef SPINLOCK_IMPL_WITH_MUTEX
+static inline void spinlock_lock_internal(SPINLOCK *spinlock)
+{
+ #ifdef NETDATA_INTERNAL_CHECKS
+ size_t spins = 0;
+ #endif
for(int i = 1;
__atomic_load_n(&spinlock->locked, __ATOMIC_RELAXED) ||
@@ -312,43 +249,124 @@ void spinlock_lock(SPINLOCK *spinlock) {
; i++
) {
-#ifdef NETDATA_INTERNAL_CHECKS
+ #ifdef NETDATA_INTERNAL_CHECKS
spins++;
-#endif
+ #endif
+
if(unlikely(i == 8)) {
i = 0;
- nanosleep(&ns, NULL);
+ tinysleep();
}
}
// we have the lock
-#ifdef NETDATA_INTERNAL_CHECKS
+ #ifdef NETDATA_INTERNAL_CHECKS
spinlock->spins += spins;
- spinlock->locker_pid = gettid();
-#endif
+ spinlock->locker_pid = gettid_cached();
+ #endif
+
+ nd_thread_spinlock_locked();
}
+#endif // SPINLOCK_IMPL_WITH_MUTEX
-void spinlock_unlock(SPINLOCK *spinlock) {
-#ifdef NETDATA_INTERNAL_CHECKS
+#ifndef SPINLOCK_IMPL_WITH_MUTEX
+static inline void spinlock_unlock_internal(SPINLOCK *spinlock)
+{
+ #ifdef NETDATA_INTERNAL_CHECKS
spinlock->locker_pid = 0;
-#endif
+ #endif
+
__atomic_clear(&spinlock->locked, __ATOMIC_RELEASE);
- netdata_thread_enable_cancelability();
-}
-bool spinlock_trylock(SPINLOCK *spinlock) {
- netdata_thread_disable_cancelability();
+ nd_thread_spinlock_unlocked();
+}
+#endif // SPINLOCK_IMPL_WITH_MUTEX
+#ifndef SPINLOCK_IMPL_WITH_MUTEX
+static inline bool spinlock_trylock_internal(SPINLOCK *spinlock) {
if(!__atomic_load_n(&spinlock->locked, __ATOMIC_RELAXED) &&
- !__atomic_test_and_set(&spinlock->locked, __ATOMIC_ACQUIRE))
+ !__atomic_test_and_set(&spinlock->locked, __ATOMIC_ACQUIRE)) {
// we got the lock
+ nd_thread_spinlock_locked();
return true;
+ }
- // we didn't get the lock
- netdata_thread_enable_cancelability();
return false;
}
+#endif // SPINLOCK_IMPL_WITH_MUTEX
+
+#ifdef SPINLOCK_IMPL_WITH_MUTEX
+void spinlock_lock(SPINLOCK *spinlock)
+{
+ netdata_mutex_lock(&spinlock->inner);
+}
+#else
+void spinlock_lock(SPINLOCK *spinlock)
+{
+ spinlock_lock_internal(spinlock);
+}
+#endif
+
+#ifdef SPINLOCK_IMPL_WITH_MUTEX
+void spinlock_unlock(SPINLOCK *spinlock)
+{
+ netdata_mutex_unlock(&spinlock->inner);
+}
+#else
+void spinlock_unlock(SPINLOCK *spinlock)
+{
+ spinlock_unlock_internal(spinlock);
+}
+#endif
+
+#ifdef SPINLOCK_IMPL_WITH_MUTEX
+bool spinlock_trylock(SPINLOCK *spinlock)
+{
+ return netdata_mutex_trylock(&spinlock->inner) == 0;
+}
+#else
+bool spinlock_trylock(SPINLOCK *spinlock)
+{
+ return spinlock_trylock_internal(spinlock);
+}
+#endif
+
+#ifdef SPINLOCK_IMPL_WITH_MUTEX
+void spinlock_lock_cancelable(SPINLOCK *spinlock)
+{
+ netdata_mutex_lock(&spinlock->inner);
+}
+#else
+void spinlock_lock_cancelable(SPINLOCK *spinlock)
+{
+ spinlock_lock_internal(spinlock);
+}
+#endif
+
+#ifdef SPINLOCK_IMPL_WITH_MUTEX
+void spinlock_unlock_cancelable(SPINLOCK *spinlock)
+{
+ netdata_mutex_unlock(&spinlock->inner);
+}
+#else
+void spinlock_unlock_cancelable(SPINLOCK *spinlock)
+{
+ spinlock_unlock_internal(spinlock);
+}
+#endif
+
+#ifdef SPINLOCK_IMPL_WITH_MUTEX
+bool spinlock_trylock_cancelable(SPINLOCK *spinlock)
+{
+ return netdata_mutex_trylock(&spinlock->inner) == 0;
+}
+#else
+bool spinlock_trylock_cancelable(SPINLOCK *spinlock)
+{
+ return spinlock_trylock_internal(spinlock);
+}
+#endif
// ----------------------------------------------------------------------------
// rw_spinlock implementation
@@ -359,11 +377,11 @@ void rw_spinlock_init(RW_SPINLOCK *rw_spinlock) {
}
void rw_spinlock_read_lock(RW_SPINLOCK *rw_spinlock) {
- netdata_thread_disable_cancelability();
-
spinlock_lock(&rw_spinlock->spinlock);
__atomic_add_fetch(&rw_spinlock->readers, 1, __ATOMIC_RELAXED);
spinlock_unlock(&rw_spinlock->spinlock);
+
+ nd_thread_rwspinlock_read_locked();
}
void rw_spinlock_read_unlock(RW_SPINLOCK *rw_spinlock) {
@@ -375,12 +393,10 @@ void rw_spinlock_read_unlock(RW_SPINLOCK *rw_spinlock) {
fatal("RW_SPINLOCK: readers is negative %d", x);
#endif
- netdata_thread_enable_cancelability();
+ nd_thread_rwspinlock_read_unlocked();
}
void rw_spinlock_write_lock(RW_SPINLOCK *rw_spinlock) {
- static const struct timespec ns = { .tv_sec = 0, .tv_nsec = 1 };
-
size_t spins = 0;
while(1) {
spins++;
@@ -391,21 +407,24 @@ void rw_spinlock_write_lock(RW_SPINLOCK *rw_spinlock) {
// Busy wait until all readers have released their locks.
spinlock_unlock(&rw_spinlock->spinlock);
- nanosleep(&ns, NULL);
+ tinysleep();
}
(void)spins;
+
+ nd_thread_rwspinlock_write_locked();
}
void rw_spinlock_write_unlock(RW_SPINLOCK *rw_spinlock) {
spinlock_unlock(&rw_spinlock->spinlock);
+ nd_thread_rwspinlock_write_unlocked();
}
bool rw_spinlock_tryread_lock(RW_SPINLOCK *rw_spinlock) {
if(spinlock_trylock(&rw_spinlock->spinlock)) {
__atomic_add_fetch(&rw_spinlock->readers, 1, __ATOMIC_RELAXED);
spinlock_unlock(&rw_spinlock->spinlock);
- netdata_thread_disable_cancelability();
+ nd_thread_rwspinlock_read_locked();
return true;
}
@@ -416,6 +435,7 @@ bool rw_spinlock_trywrite_lock(RW_SPINLOCK *rw_spinlock) {
if(spinlock_trylock(&rw_spinlock->spinlock)) {
if (__atomic_load_n(&rw_spinlock->readers, __ATOMIC_RELAXED) == 0) {
// No readers, we've successfully acquired the write lock
+ nd_thread_rwspinlock_write_locked();
return true;
}
else {
@@ -548,7 +568,22 @@ int netdata_rwlock_wrlock_debug(const char *file __maybe_unused, const char *fun
return ret;
}
-int netdata_rwlock_unlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
+int netdata_rwlock_rdunlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
+ const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
+
+ netdata_rwlock_locker *locker = find_rwlock_locker(file, function, line, rwlock);
+
+ if(unlikely(!locker))
+ fatal("UNLOCK WITHOUT LOCK");
+
+ int ret = __netdata_rwlock_rdunlock(rwlock);
+ if(likely(!ret))
+ remove_rwlock_locker(file, function, line, rwlock, locker);
+
+ return ret;
+}
+
+int netdata_rwlock_wrunlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
netdata_rwlock_locker *locker = find_rwlock_locker(file, function, line, rwlock);
@@ -556,7 +591,7 @@ int netdata_rwlock_unlock_debug(const char *file __maybe_unused, const char *fun
if(unlikely(!locker))
fatal("UNLOCK WITHOUT LOCK");
- int ret = __netdata_rwlock_unlock(rwlock);
+ int ret = __netdata_rwlock_wrunlock(rwlock);
if(likely(!ret))
remove_rwlock_locker(file, function, line, rwlock, locker);
diff --git a/libnetdata/locks/locks.h b/src/libnetdata/locks/locks.h
index 6b492ae47..c05c65fe2 100644
--- a/libnetdata/locks/locks.h
+++ b/src/libnetdata/locks/locks.h
@@ -6,25 +6,44 @@
#include "../libnetdata.h"
#include "../clocks/clocks.h"
+// #ifdef OS_WINDOWS
+// #define SPINLOCK_IMPL_WITH_MUTEX
+// #endif
+
typedef pthread_mutex_t netdata_mutex_t;
#define NETDATA_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
-typedef struct netdata_spinlock {
- bool locked;
-#ifdef NETDATA_INTERNAL_CHECKS
- pid_t locker_pid;
- size_t spins;
+#ifdef SPINLOCK_IMPL_WITH_MUTEX
+ typedef struct netdata_spinlock
+ {
+ netdata_mutex_t inner;
+ } SPINLOCK;
+#else
+ typedef struct netdata_spinlock
+ {
+ bool locked;
+ #ifdef NETDATA_INTERNAL_CHECKS
+ pid_t locker_pid;
+ size_t spins;
+ #endif
+ } SPINLOCK;
#endif
-} SPINLOCK;
-#define NETDATA_SPINLOCK_INITIALIZER \
- { .locked = false }
+#ifdef SPINLOCK_IMPL_WITH_MUTEX
+#define NETDATA_SPINLOCK_INITIALIZER { .inner = PTHREAD_MUTEX_INITIALIZER }
+#else
+#define NETDATA_SPINLOCK_INITIALIZER { .locked = false }
+#endif
void spinlock_init(SPINLOCK *spinlock);
void spinlock_lock(SPINLOCK *spinlock);
void spinlock_unlock(SPINLOCK *spinlock);
bool spinlock_trylock(SPINLOCK *spinlock);
+void spinlock_lock_cancelable(SPINLOCK *spinlock);
+void spinlock_unlock_cancelable(SPINLOCK *spinlock);
+bool spinlock_trylock_cancelable(SPINLOCK *spinlock);
+
typedef struct netdata_rw_spinlock {
int32_t readers;
SPINLOCK spinlock;
@@ -102,13 +121,11 @@ int __netdata_rwlock_destroy(netdata_rwlock_t *rwlock);
int __netdata_rwlock_init(netdata_rwlock_t *rwlock);
int __netdata_rwlock_rdlock(netdata_rwlock_t *rwlock);
int __netdata_rwlock_wrlock(netdata_rwlock_t *rwlock);
-int __netdata_rwlock_unlock(netdata_rwlock_t *rwlock);
+int __netdata_rwlock_rdunlock(netdata_rwlock_t *rwlock);
+int __netdata_rwlock_wrunlock(netdata_rwlock_t *rwlock);
int __netdata_rwlock_tryrdlock(netdata_rwlock_t *rwlock);
int __netdata_rwlock_trywrlock(netdata_rwlock_t *rwlock);
-void netdata_thread_disable_cancelability(void);
-void netdata_thread_enable_cancelability(void);
-
#ifdef NETDATA_TRACE_RWLOCKS
int netdata_mutex_init_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex);
@@ -121,7 +138,8 @@ int netdata_rwlock_destroy_debug( const char *file, const char *function, const
int netdata_rwlock_init_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock);
int netdata_rwlock_rdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock);
int netdata_rwlock_wrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock);
-int netdata_rwlock_unlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock);
+int netdata_rwlock_rdunlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock);
+int netdata_rwlock_wrunlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock);
int netdata_rwlock_tryrdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock);
int netdata_rwlock_trywrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock);
@@ -135,7 +153,8 @@ int netdata_rwlock_trywrlock_debug( const char *file, const char *function, cons
#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)
#define netdata_rwlock_wrlock(rwlock) netdata_rwlock_wrlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
-#define netdata_rwlock_unlock(rwlock) netdata_rwlock_unlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
+#define netdata_rwlock_rdunlock(rwlock) netdata_rwlock_rdunlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
+#define netdata_rwlock_wrunlock(rwlock) netdata_rwlock_wrunlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
#define netdata_rwlock_tryrdlock(rwlock) netdata_rwlock_tryrdlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
#define netdata_rwlock_trywrlock(rwlock) netdata_rwlock_trywrlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
@@ -151,7 +170,8 @@ int netdata_rwlock_trywrlock_debug( const char *file, const char *function, cons
#define netdata_rwlock_init(rwlock) __netdata_rwlock_init(rwlock)
#define netdata_rwlock_rdlock(rwlock) __netdata_rwlock_rdlock(rwlock)
#define netdata_rwlock_wrlock(rwlock) __netdata_rwlock_wrlock(rwlock)
-#define netdata_rwlock_unlock(rwlock) __netdata_rwlock_unlock(rwlock)
+#define netdata_rwlock_rdunlock(rwlock) __netdata_rwlock_rdunlock(rwlock)
+#define netdata_rwlock_wrunlock(rwlock) __netdata_rwlock_wrunlock(rwlock)
#define netdata_rwlock_tryrdlock(rwlock) __netdata_rwlock_tryrdlock(rwlock)
#define netdata_rwlock_trywrlock(rwlock) __netdata_rwlock_trywrlock(rwlock)