123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726 |
- // SPDX-License-Identifier: GPL-3.0-or-later
- #include "../libnetdata.h"
- #ifdef NETDATA_TRACE_RWLOCKS
- #ifndef NETDATA_TRACE_RWLOCKS_WAIT_TIME_TO_IGNORE_USEC
- #define NETDATA_TRACE_RWLOCKS_WAIT_TIME_TO_IGNORE_USEC 10
- #endif
- #ifndef NETDATA_TRACE_RWLOCKS_HOLD_TIME_TO_IGNORE_USEC
- #define NETDATA_TRACE_RWLOCKS_HOLD_TIME_TO_IGNORE_USEC 10000
- #endif
- #ifndef NETDATA_THREAD_LOCKS_ARRAY_SIZE
- #define NETDATA_THREAD_LOCKS_ARRAY_SIZE 10
- #endif
- static __thread netdata_rwlock_t *netdata_thread_locks[NETDATA_THREAD_LOCKS_ARRAY_SIZE];
- #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) {
- int old;
- int ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old);
- if(ret != 0)
- error("THREAD_CANCELABILITY: pthread_setcancelstate() on thread %s returned error %d", netdata_thread_tag(), ret);
- else {
- if(!netdata_thread_nested_disables)
- netdata_thread_first_cancelability = old;
- netdata_thread_nested_disables++;
- }
- }
- inline void netdata_thread_enable_cancelability(void) {
- if(netdata_thread_nested_disables < 1) {
- 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());
- }
- else if(netdata_thread_nested_disables == 1) {
- int old = 1;
- int ret = pthread_setcancelstate(netdata_thread_first_cancelability, &old);
- if(ret != 0)
- error("THREAD_CANCELABILITY: pthread_setcancelstate() on thread %s returned error %d", netdata_thread_tag(), ret);
- else {
- if(old != PTHREAD_CANCEL_DISABLE)
- 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 = 0;
- }
- else
- netdata_thread_nested_disables--;
- }
- // ----------------------------------------------------------------------------
- // 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_destroy(netdata_mutex_t *mutex) {
- int ret = pthread_mutex_destroy(mutex);
- if(unlikely(ret != 0))
- error("MUTEX_LOCK: failed to destroy (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);
- }
- else
- netdata_locks_acquired_mutexes++;
- 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++;
- 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_locks_acquired_mutexes--;
- netdata_thread_enable_cancelability();
- }
- return ret;
- }
- #ifdef NETDATA_TRACE_RWLOCKS
- #warning NETDATA_TRACE_RWLOCKS ENABLED - EXPECT A LOT OF OUTPUT
- int netdata_mutex_init_debug(const char *file __maybe_unused, const char *function __maybe_unused,
- const unsigned long line __maybe_unused, netdata_mutex_t *mutex) {
- debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_init(%p) from %lu@%s, %s()", mutex, line, file, function);
- int ret = __netdata_mutex_init(mutex);
- debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_init(%p) = %d, from %lu@%s, %s()", mutex, ret, line, file, function);
- return ret;
- }
- int netdata_mutex_destroy_debug(const char *file __maybe_unused, const char *function __maybe_unused,
- const unsigned long line __maybe_unused, netdata_mutex_t *mutex) {
- debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_destroy(%p) from %lu@%s, %s()", mutex, line, file, function);
- int ret = __netdata_mutex_destroy(mutex);
- debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_destroy(%p) = %d, from %lu@%s, %s()", mutex, ret, line, file, function);
- return ret;
- }
- int netdata_mutex_lock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
- const unsigned long line __maybe_unused, netdata_mutex_t *mutex) {
- debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_lock(%p) from %lu@%s, %s()", mutex, line, file, function);
- usec_t start_s = now_monotonic_high_precision_usec();
- int ret = __netdata_mutex_lock(mutex);
- usec_t end_s = now_monotonic_high_precision_usec();
- // remove compiler unused variables warning
- (void)start_s;
- (void)end_s;
- debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_lock(%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, end_s - start_s, line, file, function);
- return ret;
- }
- int netdata_mutex_trylock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
- const unsigned long line __maybe_unused, netdata_mutex_t *mutex) {
- debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_trylock(%p) from %lu@%s, %s()", mutex, line, file, function);
- usec_t start_s = now_monotonic_high_precision_usec();
- int ret = __netdata_mutex_trylock(mutex);
- usec_t end_s = now_monotonic_high_precision_usec();
- // remove compiler unused variables warning
- (void)start_s;
- (void)end_s;
- debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_trylock(%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, end_s - start_s, line, file, function);
- return ret;
- }
- int netdata_mutex_unlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
- const unsigned long line __maybe_unused, netdata_mutex_t *mutex) {
- debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_unlock(%p) from %lu@%s, %s()", mutex, line, file, function);
- usec_t start_s = now_monotonic_high_precision_usec();
- int ret = __netdata_mutex_unlock(mutex);
- usec_t end_s = now_monotonic_high_precision_usec();
- // remove compiler unused variables warning
- (void)start_s;
- (void)end_s;
- debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_unlock(%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, end_s - start_s, line, file, function);
- return ret;
- }
- #endif // NETDATA_TRACE_RWLOCKS
- // ----------------------------------------------------------------------------
- // rwlock
- int __netdata_rwlock_destroy(netdata_rwlock_t *rwlock) {
- int ret = pthread_rwlock_destroy(&rwlock->rwlock_t);
- 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->rwlock_t, 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->rwlock_t);
- if(unlikely(ret != 0)) {
- netdata_thread_enable_cancelability();
- error("RW_LOCK: failed to obtain read lock (code %d)", ret);
- }
- else
- netdata_locks_acquired_rwlocks++;
- 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)) {
- error("RW_LOCK: failed to obtain write lock (code %d)", ret);
- netdata_thread_enable_cancelability();
- }
- else
- netdata_locks_acquired_rwlocks++;
- return ret;
- }
- int __netdata_rwlock_unlock(netdata_rwlock_t *rwlock) {
- int ret = pthread_rwlock_unlock(&rwlock->rwlock_t);
- if(unlikely(ret != 0))
- error("RW_LOCK: failed to release lock (code %d)", ret);
- else {
- netdata_thread_enable_cancelability();
- netdata_locks_acquired_rwlocks--;
- }
- return ret;
- }
- int __netdata_rwlock_tryrdlock(netdata_rwlock_t *rwlock) {
- netdata_thread_disable_cancelability();
- int ret = pthread_rwlock_tryrdlock(&rwlock->rwlock_t);
- if(ret != 0)
- netdata_thread_enable_cancelability();
- else
- netdata_locks_acquired_rwlocks++;
- 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++;
- return ret;
- }
- #ifdef NETDATA_TRACE_RWLOCKS
- // ----------------------------------------------------------------------------
- // lockers list
- void not_supported_by_posix_rwlocks(const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock, char locktype, const char *reason) {
- __netdata_mutex_lock(&rwlock->lockers_mutex);
- fprintf(stderr,
- "RW_LOCK FATAL ON LOCK %p: %d '%s' (function %s() %lu@%s) attempts to acquire a '%c' lock, but it is not supported by POSIX because: %s. At this attempt, the task is holding %zu rwlocks and %zu mutexes. There are %zu readers and %zu writers holding this lock:\n",
- rwlock,
- gettid(), netdata_thread_tag(),
- function, line, file,
- locktype,
- reason,
- netdata_locks_acquired_rwlocks, netdata_locks_acquired_mutexes,
- rwlock->readers, rwlock->writers);
- int i;
- usec_t now = now_monotonic_high_precision_usec();
- netdata_rwlock_locker *p;
- for(i = 1, p = rwlock->lockers; p ;p = p->next, i++) {
- fprintf(stderr,
- " => %i: RW_LOCK %p: process %d '%s' (function %s() %lu@%s) is having %zu '%c' lock for %llu usec.\n",
- i, rwlock,
- p->pid, p->tag,
- p->function, p->line, p->file,
- p->callers, p->lock,
- (now - p->start_s));
- }
- __netdata_mutex_unlock(&rwlock->lockers_mutex);
- }
- static void log_rwlock_lockers(const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock, const char *reason, char locktype) {
- // this function can only be used by one thread at a time
- // because otherwise, the threads may deadlock waiting for each other
- static netdata_mutex_t log_lockers_mutex = NETDATA_MUTEX_INITIALIZER;
- __netdata_mutex_lock(&log_lockers_mutex);
- // now work on this locker
- __netdata_mutex_lock(&rwlock->lockers_mutex);
- fprintf(stderr,
- "RW_LOCK ON LOCK %p: %d '%s' (function %s() %lu@%s) %s a '%c' lock (while holding %zu rwlocks and %zu mutexes). There are %zu readers and %zu writers holding this lock:\n",
- rwlock,
- gettid(), netdata_thread_tag(),
- function, line, file,
- reason, locktype,
- netdata_locks_acquired_rwlocks, netdata_locks_acquired_mutexes,
- rwlock->readers, rwlock->writers);
- int i;
- usec_t now = now_monotonic_high_precision_usec();
- netdata_rwlock_locker *p;
- for(i = 1, p = rwlock->lockers; p ;p = p->next, i++) {
- fprintf(stderr,
- " => %i: RW_LOCK %p: process %d '%s' (function %s() %lu@%s) is having %zu '%c' lock for %llu usec.\n",
- i, rwlock,
- p->pid, p->tag,
- p->function, p->line, p->file,
- p->callers, p->lock,
- (now - p->start_s));
- if(p->all_caller_locks) {
- // find the lock in the netdata_thread_locks[]
- // and remove it
- int k;
- for(k = 0; k < NETDATA_THREAD_LOCKS_ARRAY_SIZE ;k++) {
- if (p->all_caller_locks[k] && p->all_caller_locks[k] != rwlock) {
- // lock the other lock lockers list
- __netdata_mutex_lock(&p->all_caller_locks[k]->lockers_mutex);
- // print the list of lockers of the other lock
- netdata_rwlock_locker *r;
- int j;
- for(j = 1, r = p->all_caller_locks[k]->lockers; r ;r = r->next, j++) {
- fprintf(
- stderr,
- " ~~~> %i: RW_LOCK %p: process %d '%s' (function %s() %lu@%s) is having %zu '%c' lock for %llu usec.\n",
- j,
- p->all_caller_locks[k],
- r->pid,
- r->tag,
- r->function,
- r->line,
- r->file,
- r->callers,
- r->lock,
- (now - r->start_s));
- }
- // unlock the other lock lockers list
- __netdata_mutex_unlock(&p->all_caller_locks[k]->lockers_mutex);
- }
- }
- }
- }
- __netdata_mutex_unlock(&rwlock->lockers_mutex);
- // unlock this function for other threads
- __netdata_mutex_unlock(&log_lockers_mutex);
- }
- static netdata_rwlock_locker *add_rwlock_locker(const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock, char lock_type) {
- netdata_rwlock_locker *p = mallocz(sizeof(netdata_rwlock_locker));
- p->pid = gettid();
- p->tag = netdata_thread_tag();
- p->lock = lock_type;
- p->file = file;
- p->function = function;
- p->line = line;
- p->callers = 1;
- p->all_caller_locks = netdata_thread_locks;
- p->start_s = now_monotonic_high_precision_usec();
- // find a slot in the netdata_thread_locks[]
- int i;
- for(i = 0; i < NETDATA_THREAD_LOCKS_ARRAY_SIZE ;i++) {
- if (!netdata_thread_locks[i]) {
- netdata_thread_locks[i] = rwlock;
- break;
- }
- }
- __netdata_mutex_lock(&rwlock->lockers_mutex);
- p->next = rwlock->lockers;
- rwlock->lockers = p;
- if(lock_type == 'R') rwlock->readers++;
- if(lock_type == 'W') rwlock->writers++;
- __netdata_mutex_unlock(&rwlock->lockers_mutex);
- return p;
- }
- static void remove_rwlock_locker(const char *file __maybe_unused, const char *function __maybe_unused, const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock, netdata_rwlock_locker *locker) {
- usec_t end_s = now_monotonic_high_precision_usec();
- if(locker->callers == 0)
- fprintf(stderr,
- "RW_LOCK ON LOCK %p: %d, '%s' (function %s() %lu@%s) callers should be positive but it is zero\n",
- rwlock,
- locker->pid, locker->tag,
- locker->function, locker->line, locker->file);
- if(locker->callers > 1 && locker->lock != 'R')
- fprintf(stderr,
- "RW_LOCK ON LOCK %p: %d, '%s' (function %s() %lu@%s) only 'R' locks support multiple holders, but here we have %zu callers holding a '%c' lock.\n",
- rwlock,
- locker->pid, locker->tag,
- locker->function, locker->line, locker->file,
- locker->callers, locker->lock);
- __netdata_mutex_lock(&rwlock->lockers_mutex);
- locker->callers--;
- if(!locker->callers) {
- int doit = 0;
- if (rwlock->lockers == locker) {
- rwlock->lockers = locker->next;
- doit = 1;
- } else {
- netdata_rwlock_locker *p;
- for (p = rwlock->lockers; p && p->next != locker; p = p->next)
- ;
- if (p && p->next == locker) {
- p->next = locker->next;
- doit = 1;
- }
- }
- if(doit) {
- if(locker->lock == 'R') rwlock->readers--;
- if(locker->lock == 'W') rwlock->writers--;
- }
- if(!doit) {
- fprintf(stderr,
- "RW_LOCK ON LOCK %p: %d, '%s' (function %s() %lu@%s) with %zu x '%c' lock is not found.\n",
- rwlock,
- locker->pid, locker->tag,
- locker->function, locker->line, locker->file,
- locker->callers, locker->lock);
- }
- else {
- // find the lock in the netdata_thread_locks[]
- // and remove it
- int i;
- for(i = 0; i < NETDATA_THREAD_LOCKS_ARRAY_SIZE ;i++) {
- if (netdata_thread_locks[i] == rwlock)
- netdata_thread_locks[i] = NULL;
- }
- if(end_s - locker->start_s >= NETDATA_TRACE_RWLOCKS_HOLD_TIME_TO_IGNORE_USEC)
- fprintf(stderr,
- "RW_LOCK ON LOCK %p: %d, '%s' (function %s() %lu@%s) holded a '%c' for %llu usec.\n",
- rwlock,
- locker->pid, locker->tag,
- locker->function, locker->line, locker->file,
- locker->lock, end_s - locker->start_s);
- freez(locker);
- }
- }
- __netdata_mutex_unlock(&rwlock->lockers_mutex);
- }
- static netdata_rwlock_locker *find_rwlock_locker(const char *file __maybe_unused, const char *function __maybe_unused, const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
- pid_t pid = gettid();
- netdata_rwlock_locker *p;
- __netdata_mutex_lock(&rwlock->lockers_mutex);
- for(p = rwlock->lockers; p ;p = p->next) {
- if(p->pid == pid) break;
- }
- __netdata_mutex_unlock(&rwlock->lockers_mutex);
- return p;
- }
- static netdata_rwlock_locker *update_or_add_rwlock_locker(const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock, netdata_rwlock_locker *locker, char locktype) {
- if(!locker) {
- return add_rwlock_locker(file, function, line, rwlock, locktype);
- }
- else if(locker->lock == 'R' && locktype == 'R') {
- __netdata_mutex_lock(&rwlock->lockers_mutex);
- locker->callers++;
- __netdata_mutex_unlock(&rwlock->lockers_mutex);
- return locker;
- }
- else {
- not_supported_by_posix_rwlocks(file, function, line, rwlock, locktype, "DEADLOCK - WANTS TO CHANGE LOCK TYPE BUT ALREADY HAS THIS LOCKED");
- return locker;
- }
- }
- // ----------------------------------------------------------------------------
- // debug versions of rwlock
- int netdata_rwlock_destroy_debug(const char *file __maybe_unused, const char *function __maybe_unused,
- const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
- debug(D_LOCKS, "RW_LOCK: netdata_rwlock_destroy(%p) from %lu@%s, %s()", rwlock, line, file, function);
- if(rwlock->readers)
- error("RW_LOCK: destroying a rwlock with %zu readers in it", rwlock->readers);
- if(rwlock->writers)
- error("RW_LOCK: destroying a rwlock with %zu writers in it", rwlock->writers);
- int ret = __netdata_rwlock_destroy(rwlock);
- if(!ret) {
- while (rwlock->lockers)
- remove_rwlock_locker(file, function, line, rwlock, rwlock->lockers);
- if (rwlock->readers)
- error("RW_LOCK: internal error - empty rwlock with %zu readers in it", rwlock->readers);
- if (rwlock->writers)
- error("RW_LOCK: internal error - empty rwlock with %zu writers in it", rwlock->writers);
- }
- debug(D_LOCKS, "RW_LOCK: netdata_rwlock_destroy(%p) = %d, from %lu@%s, %s()", rwlock, ret, line, file, function);
- return ret;
- }
- int netdata_rwlock_init_debug(const char *file __maybe_unused, const char *function __maybe_unused,
- const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
- debug(D_LOCKS, "RW_LOCK: netdata_rwlock_init(%p) from %lu@%s, %s()", rwlock, line, file, function);
- int ret = __netdata_rwlock_init(rwlock);
- if(!ret) {
- __netdata_mutex_init(&rwlock->lockers_mutex);
- rwlock->lockers = NULL;
- rwlock->readers = 0;
- rwlock->writers = 0;
- }
- debug(D_LOCKS, "RW_LOCK: netdata_rwlock_init(%p) = %d, from %lu@%s, %s()", rwlock, ret, line, file, function);
- return ret;
- }
- int netdata_rwlock_rdlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
- const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
- debug(D_LOCKS, "RW_LOCK: netdata_rwlock_rdlock(%p) from %lu@%s, %s()", rwlock, line, file, function);
- netdata_rwlock_locker *locker = find_rwlock_locker(file, function, line, rwlock);
- #ifdef NETDATA_TRACE_RWLOCKS_LOG_NESTED
- if(locker && locker->lock == 'R') {
- log_rwlock_lockers(file, function, line, rwlock, "NESTED READ LOCK REQUEST", 'R');
- }
- #endif // NETDATA_TRACE_RWLOCKS_LOG_NESTED
- int log = 0;
- if(rwlock->writers) {
- log_rwlock_lockers(file, function, line, rwlock, "WANTS", 'R');
- log = 1;
- }
- usec_t start_s = now_monotonic_high_precision_usec();
- int ret = __netdata_rwlock_rdlock(rwlock);
- usec_t end_s = now_monotonic_high_precision_usec();
- if(!ret) {
- locker = update_or_add_rwlock_locker(file, function, line, rwlock, locker, 'R');
- if(log) log_rwlock_lockers(file, function, line, rwlock, "GOT", 'R');
- }
- if(end_s - start_s >= NETDATA_TRACE_RWLOCKS_WAIT_TIME_TO_IGNORE_USEC)
- fprintf(stderr,
- "RW_LOCK ON LOCK %p: %d, '%s' (function %s() %lu@%s) WAITED for a READ lock for %llu usec.\n",
- rwlock,
- gettid(), netdata_thread_tag(),
- function, line, file,
- end_s - start_s);
- debug(D_LOCKS, "RW_LOCK: netdata_rwlock_rdlock(%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, end_s - start_s, line, file, function);
- return ret;
- }
- int netdata_rwlock_wrlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
- const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
- debug(D_LOCKS, "RW_LOCK: netdata_rwlock_wrlock(%p) from %lu@%s, %s()", rwlock, line, file, function);
- netdata_rwlock_locker *locker = find_rwlock_locker(file, function, line, rwlock);
- if(locker)
- not_supported_by_posix_rwlocks(file, function, line, rwlock, 'W', "DEADLOCK - WANTS A WRITE LOCK BUT ALREADY HAVE THIS LOCKED");
- int log = 0;
- if(rwlock->readers) {
- log_rwlock_lockers(file, function, line, rwlock, "WANTS", 'W');
- log = 1;
- }
- usec_t start_s = now_monotonic_high_precision_usec();
- int ret = __netdata_rwlock_wrlock(rwlock);
- usec_t end_s = now_monotonic_high_precision_usec();
- if(!ret){
- locker = update_or_add_rwlock_locker(file, function, line, rwlock, locker, 'W');
- if(log) log_rwlock_lockers(file, function, line, rwlock, "GOT", 'W');
- }
- if(end_s - start_s >= NETDATA_TRACE_RWLOCKS_WAIT_TIME_TO_IGNORE_USEC)
- fprintf(stderr,
- "RW_LOCK ON LOCK %p: %d, '%s' (function %s() %lu@%s) WAITED for a WRITE lock for %llu usec.\n",
- rwlock,
- gettid(), netdata_thread_tag(),
- function, line, file,
- end_s - start_s);
- debug(D_LOCKS, "RW_LOCK: netdata_rwlock_wrlock(%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, end_s - start_s, line, file, function);
- return ret;
- }
- int netdata_rwlock_unlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
- const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
- debug(D_LOCKS, "RW_LOCK: netdata_rwlock_unlock(%p) from %lu@%s, %s()", rwlock, line, file, function);
- netdata_rwlock_locker *locker = find_rwlock_locker(file, function, line, rwlock);
- if(unlikely(!locker))
- not_supported_by_posix_rwlocks(file, function, line, rwlock, 'U', "UNLOCK WITHOUT LOCK");
- usec_t start_s = now_monotonic_high_precision_usec();
- int ret = __netdata_rwlock_unlock(rwlock);
- usec_t end_s = now_monotonic_high_precision_usec();
- if(end_s - start_s >= NETDATA_TRACE_RWLOCKS_WAIT_TIME_TO_IGNORE_USEC)
- fprintf(stderr,
- "RW_LOCK ON LOCK %p: %d, '%s' (function %s() %lu@%s) WAITED to UNLOCK for %llu usec.\n",
- rwlock,
- gettid(), netdata_thread_tag(),
- function, line, file,
- end_s - start_s);
- if(likely(!ret && locker)) remove_rwlock_locker(file, function, line, rwlock, locker);
- debug(D_LOCKS, "RW_LOCK: netdata_rwlock_unlock(%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, end_s - start_s, line, file, function);
- return ret;
- }
- int netdata_rwlock_tryrdlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
- const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
- debug(D_LOCKS, "RW_LOCK: netdata_rwlock_tryrdlock(%p) from %lu@%s, %s()", rwlock, line, file, function);
- netdata_rwlock_locker *locker = find_rwlock_locker(file, function, line, rwlock);
- if(locker && locker->lock == 'W')
- not_supported_by_posix_rwlocks(file, function, line, rwlock, 'R', "DEADLOCK - WANTS A READ LOCK BUT IT HAS A WRITE LOCK ALREADY");
- usec_t start_s = now_monotonic_high_precision_usec();
- int ret = __netdata_rwlock_tryrdlock(rwlock);
- usec_t end_s = now_monotonic_high_precision_usec();
- if(!ret)
- locker = update_or_add_rwlock_locker(file, function, line, rwlock, locker, 'R');
- if(end_s - start_s >= NETDATA_TRACE_RWLOCKS_WAIT_TIME_TO_IGNORE_USEC)
- fprintf(stderr,
- "RW_LOCK ON LOCK %p: %d, '%s' (function %s() %lu@%s) WAITED to TRYREAD for %llu usec.\n",
- rwlock,
- gettid(), netdata_thread_tag(),
- function, line, file,
- end_s - start_s);
- debug(D_LOCKS, "RW_LOCK: netdata_rwlock_tryrdlock(%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, end_s - start_s, line, file, function);
- return ret;
- }
- int netdata_rwlock_trywrlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
- const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
- debug(D_LOCKS, "RW_LOCK: netdata_rwlock_trywrlock(%p) from %lu@%s, %s()", rwlock, line, file, function);
- netdata_rwlock_locker *locker = find_rwlock_locker(file, function, line, rwlock);
- if(locker)
- not_supported_by_posix_rwlocks(file, function, line, rwlock, 'W', "ALREADY HAS THIS LOCK");
- usec_t start_s = now_monotonic_high_precision_usec();
- int ret = __netdata_rwlock_trywrlock(rwlock);
- usec_t end_s = now_monotonic_high_precision_usec();
- if(!ret)
- locker = update_or_add_rwlock_locker(file, function, line, rwlock, locker, 'W');
- if(end_s - start_s >= NETDATA_TRACE_RWLOCKS_WAIT_TIME_TO_IGNORE_USEC)
- fprintf(stderr,
- "RW_LOCK ON LOCK %p: %d, '%s' (function %s() %lu@%s) WAITED to TRYWRITE for %llu usec.\n",
- rwlock,
- gettid(), netdata_thread_tag(),
- function, line, file,
- end_s - start_s);
- debug(D_LOCKS, "RW_LOCK: netdata_rwlock_trywrlock(%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, end_s - start_s, line, file, function);
- return ret;
- }
- #endif // NETDATA_TRACE_RWLOCKS
|