locks.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "../libnetdata.h"
  3. #ifdef NETDATA_TRACE_RWLOCKS
  4. #ifndef NETDATA_TRACE_RWLOCKS_WAIT_TIME_TO_IGNORE_USEC
  5. #define NETDATA_TRACE_RWLOCKS_WAIT_TIME_TO_IGNORE_USEC 10
  6. #endif
  7. #ifndef NETDATA_TRACE_RWLOCKS_HOLD_TIME_TO_IGNORE_USEC
  8. #define NETDATA_TRACE_RWLOCKS_HOLD_TIME_TO_IGNORE_USEC 10000
  9. #endif
  10. #ifndef NETDATA_THREAD_LOCKS_ARRAY_SIZE
  11. #define NETDATA_THREAD_LOCKS_ARRAY_SIZE 10
  12. #endif
  13. static __thread netdata_rwlock_t *netdata_thread_locks[NETDATA_THREAD_LOCKS_ARRAY_SIZE];
  14. #endif // NETDATA_TRACE_RWLOCKS
  15. // ----------------------------------------------------------------------------
  16. // automatic thread cancelability management, based on locks
  17. static __thread int netdata_thread_first_cancelability = 0;
  18. static __thread int netdata_thread_nested_disables = 0;
  19. static __thread size_t netdata_locks_acquired_rwlocks = 0;
  20. static __thread size_t netdata_locks_acquired_mutexes = 0;
  21. inline void netdata_thread_disable_cancelability(void) {
  22. int old;
  23. int ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old);
  24. if(ret != 0)
  25. error("THREAD_CANCELABILITY: pthread_setcancelstate() on thread %s returned error %d", netdata_thread_tag(), ret);
  26. else {
  27. if(!netdata_thread_nested_disables)
  28. netdata_thread_first_cancelability = old;
  29. netdata_thread_nested_disables++;
  30. }
  31. }
  32. inline void netdata_thread_enable_cancelability(void) {
  33. if(netdata_thread_nested_disables < 1) {
  34. error("THREAD_CANCELABILITY: netdata_thread_enable_cancelability(): invalid thread cancelability count %d on thread %s - results will be undefined - please report this!",
  35. netdata_thread_nested_disables, netdata_thread_tag());
  36. }
  37. else if(netdata_thread_nested_disables == 1) {
  38. int old = 1;
  39. int ret = pthread_setcancelstate(netdata_thread_first_cancelability, &old);
  40. if(ret != 0)
  41. error("THREAD_CANCELABILITY: pthread_setcancelstate() on thread %s returned error %d", netdata_thread_tag(), ret);
  42. else {
  43. if(old != PTHREAD_CANCEL_DISABLE)
  44. 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);
  45. }
  46. netdata_thread_nested_disables = 0;
  47. }
  48. else
  49. netdata_thread_nested_disables--;
  50. }
  51. // ----------------------------------------------------------------------------
  52. // mutex
  53. int __netdata_mutex_init(netdata_mutex_t *mutex) {
  54. int ret = pthread_mutex_init(mutex, NULL);
  55. if(unlikely(ret != 0))
  56. error("MUTEX_LOCK: failed to initialize (code %d).", ret);
  57. return ret;
  58. }
  59. int __netdata_mutex_destroy(netdata_mutex_t *mutex) {
  60. int ret = pthread_mutex_destroy(mutex);
  61. if(unlikely(ret != 0))
  62. error("MUTEX_LOCK: failed to destroy (code %d).", ret);
  63. return ret;
  64. }
  65. int __netdata_mutex_lock(netdata_mutex_t *mutex) {
  66. netdata_thread_disable_cancelability();
  67. int ret = pthread_mutex_lock(mutex);
  68. if(unlikely(ret != 0)) {
  69. netdata_thread_enable_cancelability();
  70. error("MUTEX_LOCK: failed to get lock (code %d)", ret);
  71. }
  72. else
  73. netdata_locks_acquired_mutexes++;
  74. return ret;
  75. }
  76. int __netdata_mutex_trylock(netdata_mutex_t *mutex) {
  77. netdata_thread_disable_cancelability();
  78. int ret = pthread_mutex_trylock(mutex);
  79. if(ret != 0)
  80. netdata_thread_enable_cancelability();
  81. else
  82. netdata_locks_acquired_mutexes++;
  83. return ret;
  84. }
  85. int __netdata_mutex_unlock(netdata_mutex_t *mutex) {
  86. int ret = pthread_mutex_unlock(mutex);
  87. if(unlikely(ret != 0))
  88. error("MUTEX_LOCK: failed to unlock (code %d).", ret);
  89. else {
  90. netdata_locks_acquired_mutexes--;
  91. netdata_thread_enable_cancelability();
  92. }
  93. return ret;
  94. }
  95. #ifdef NETDATA_TRACE_RWLOCKS
  96. #warning NETDATA_TRACE_RWLOCKS ENABLED - EXPECT A LOT OF OUTPUT
  97. int netdata_mutex_init_debug(const char *file __maybe_unused, const char *function __maybe_unused,
  98. const unsigned long line __maybe_unused, netdata_mutex_t *mutex) {
  99. debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_init(%p) from %lu@%s, %s()", mutex, line, file, function);
  100. int ret = __netdata_mutex_init(mutex);
  101. debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_init(%p) = %d, from %lu@%s, %s()", mutex, ret, line, file, function);
  102. return ret;
  103. }
  104. int netdata_mutex_destroy_debug(const char *file __maybe_unused, const char *function __maybe_unused,
  105. const unsigned long line __maybe_unused, netdata_mutex_t *mutex) {
  106. debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_destroy(%p) from %lu@%s, %s()", mutex, line, file, function);
  107. int ret = __netdata_mutex_destroy(mutex);
  108. debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_destroy(%p) = %d, from %lu@%s, %s()", mutex, ret, line, file, function);
  109. return ret;
  110. }
  111. int netdata_mutex_lock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
  112. const unsigned long line __maybe_unused, netdata_mutex_t *mutex) {
  113. debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_lock(%p) from %lu@%s, %s()", mutex, line, file, function);
  114. usec_t start_s = now_monotonic_high_precision_usec();
  115. int ret = __netdata_mutex_lock(mutex);
  116. usec_t end_s = now_monotonic_high_precision_usec();
  117. // remove compiler unused variables warning
  118. (void)start_s;
  119. (void)end_s;
  120. 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);
  121. return ret;
  122. }
  123. int netdata_mutex_trylock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
  124. const unsigned long line __maybe_unused, netdata_mutex_t *mutex) {
  125. debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_trylock(%p) from %lu@%s, %s()", mutex, line, file, function);
  126. usec_t start_s = now_monotonic_high_precision_usec();
  127. int ret = __netdata_mutex_trylock(mutex);
  128. usec_t end_s = now_monotonic_high_precision_usec();
  129. // remove compiler unused variables warning
  130. (void)start_s;
  131. (void)end_s;
  132. 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);
  133. return ret;
  134. }
  135. int netdata_mutex_unlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
  136. const unsigned long line __maybe_unused, netdata_mutex_t *mutex) {
  137. debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_unlock(%p) from %lu@%s, %s()", mutex, line, file, function);
  138. usec_t start_s = now_monotonic_high_precision_usec();
  139. int ret = __netdata_mutex_unlock(mutex);
  140. usec_t end_s = now_monotonic_high_precision_usec();
  141. // remove compiler unused variables warning
  142. (void)start_s;
  143. (void)end_s;
  144. 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);
  145. return ret;
  146. }
  147. #endif // NETDATA_TRACE_RWLOCKS
  148. // ----------------------------------------------------------------------------
  149. // rwlock
  150. int __netdata_rwlock_destroy(netdata_rwlock_t *rwlock) {
  151. int ret = pthread_rwlock_destroy(&rwlock->rwlock_t);
  152. if(unlikely(ret != 0))
  153. error("RW_LOCK: failed to destroy lock (code %d)", ret);
  154. return ret;
  155. }
  156. int __netdata_rwlock_init(netdata_rwlock_t *rwlock) {
  157. int ret = pthread_rwlock_init(&rwlock->rwlock_t, NULL);
  158. if(unlikely(ret != 0))
  159. error("RW_LOCK: failed to initialize lock (code %d)", ret);
  160. return ret;
  161. }
  162. int __netdata_rwlock_rdlock(netdata_rwlock_t *rwlock) {
  163. netdata_thread_disable_cancelability();
  164. int ret = pthread_rwlock_rdlock(&rwlock->rwlock_t);
  165. if(unlikely(ret != 0)) {
  166. netdata_thread_enable_cancelability();
  167. error("RW_LOCK: failed to obtain read lock (code %d)", ret);
  168. }
  169. else
  170. netdata_locks_acquired_rwlocks++;
  171. return ret;
  172. }
  173. int __netdata_rwlock_wrlock(netdata_rwlock_t *rwlock) {
  174. netdata_thread_disable_cancelability();
  175. int ret = pthread_rwlock_wrlock(&rwlock->rwlock_t);
  176. if(unlikely(ret != 0)) {
  177. error("RW_LOCK: failed to obtain write lock (code %d)", ret);
  178. netdata_thread_enable_cancelability();
  179. }
  180. else
  181. netdata_locks_acquired_rwlocks++;
  182. return ret;
  183. }
  184. int __netdata_rwlock_unlock(netdata_rwlock_t *rwlock) {
  185. int ret = pthread_rwlock_unlock(&rwlock->rwlock_t);
  186. if(unlikely(ret != 0))
  187. error("RW_LOCK: failed to release lock (code %d)", ret);
  188. else {
  189. netdata_thread_enable_cancelability();
  190. netdata_locks_acquired_rwlocks--;
  191. }
  192. return ret;
  193. }
  194. int __netdata_rwlock_tryrdlock(netdata_rwlock_t *rwlock) {
  195. netdata_thread_disable_cancelability();
  196. int ret = pthread_rwlock_tryrdlock(&rwlock->rwlock_t);
  197. if(ret != 0)
  198. netdata_thread_enable_cancelability();
  199. else
  200. netdata_locks_acquired_rwlocks++;
  201. return ret;
  202. }
  203. int __netdata_rwlock_trywrlock(netdata_rwlock_t *rwlock) {
  204. netdata_thread_disable_cancelability();
  205. int ret = pthread_rwlock_trywrlock(&rwlock->rwlock_t);
  206. if(ret != 0)
  207. netdata_thread_enable_cancelability();
  208. else
  209. netdata_locks_acquired_rwlocks++;
  210. return ret;
  211. }
  212. #ifdef NETDATA_TRACE_RWLOCKS
  213. // ----------------------------------------------------------------------------
  214. // lockers list
  215. 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) {
  216. __netdata_mutex_lock(&rwlock->lockers_mutex);
  217. fprintf(stderr,
  218. "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",
  219. rwlock,
  220. gettid(), netdata_thread_tag(),
  221. function, line, file,
  222. locktype,
  223. reason,
  224. netdata_locks_acquired_rwlocks, netdata_locks_acquired_mutexes,
  225. rwlock->readers, rwlock->writers);
  226. int i;
  227. usec_t now = now_monotonic_high_precision_usec();
  228. netdata_rwlock_locker *p;
  229. for(i = 1, p = rwlock->lockers; p ;p = p->next, i++) {
  230. fprintf(stderr,
  231. " => %i: RW_LOCK %p: process %d '%s' (function %s() %lu@%s) is having %zu '%c' lock for %llu usec.\n",
  232. i, rwlock,
  233. p->pid, p->tag,
  234. p->function, p->line, p->file,
  235. p->callers, p->lock,
  236. (now - p->start_s));
  237. }
  238. __netdata_mutex_unlock(&rwlock->lockers_mutex);
  239. }
  240. static void log_rwlock_lockers(const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock, const char *reason, char locktype) {
  241. // this function can only be used by one thread at a time
  242. // because otherwise, the threads may deadlock waiting for each other
  243. static netdata_mutex_t log_lockers_mutex = NETDATA_MUTEX_INITIALIZER;
  244. __netdata_mutex_lock(&log_lockers_mutex);
  245. // now work on this locker
  246. __netdata_mutex_lock(&rwlock->lockers_mutex);
  247. fprintf(stderr,
  248. "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",
  249. rwlock,
  250. gettid(), netdata_thread_tag(),
  251. function, line, file,
  252. reason, locktype,
  253. netdata_locks_acquired_rwlocks, netdata_locks_acquired_mutexes,
  254. rwlock->readers, rwlock->writers);
  255. int i;
  256. usec_t now = now_monotonic_high_precision_usec();
  257. netdata_rwlock_locker *p;
  258. for(i = 1, p = rwlock->lockers; p ;p = p->next, i++) {
  259. fprintf(stderr,
  260. " => %i: RW_LOCK %p: process %d '%s' (function %s() %lu@%s) is having %zu '%c' lock for %llu usec.\n",
  261. i, rwlock,
  262. p->pid, p->tag,
  263. p->function, p->line, p->file,
  264. p->callers, p->lock,
  265. (now - p->start_s));
  266. if(p->all_caller_locks) {
  267. // find the lock in the netdata_thread_locks[]
  268. // and remove it
  269. int k;
  270. for(k = 0; k < NETDATA_THREAD_LOCKS_ARRAY_SIZE ;k++) {
  271. if (p->all_caller_locks[k] && p->all_caller_locks[k] != rwlock) {
  272. // lock the other lock lockers list
  273. __netdata_mutex_lock(&p->all_caller_locks[k]->lockers_mutex);
  274. // print the list of lockers of the other lock
  275. netdata_rwlock_locker *r;
  276. int j;
  277. for(j = 1, r = p->all_caller_locks[k]->lockers; r ;r = r->next, j++) {
  278. fprintf(
  279. stderr,
  280. " ~~~> %i: RW_LOCK %p: process %d '%s' (function %s() %lu@%s) is having %zu '%c' lock for %llu usec.\n",
  281. j,
  282. p->all_caller_locks[k],
  283. r->pid,
  284. r->tag,
  285. r->function,
  286. r->line,
  287. r->file,
  288. r->callers,
  289. r->lock,
  290. (now - r->start_s));
  291. }
  292. // unlock the other lock lockers list
  293. __netdata_mutex_unlock(&p->all_caller_locks[k]->lockers_mutex);
  294. }
  295. }
  296. }
  297. }
  298. __netdata_mutex_unlock(&rwlock->lockers_mutex);
  299. // unlock this function for other threads
  300. __netdata_mutex_unlock(&log_lockers_mutex);
  301. }
  302. static netdata_rwlock_locker *add_rwlock_locker(const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock, char lock_type) {
  303. netdata_rwlock_locker *p = mallocz(sizeof(netdata_rwlock_locker));
  304. p->pid = gettid();
  305. p->tag = netdata_thread_tag();
  306. p->lock = lock_type;
  307. p->file = file;
  308. p->function = function;
  309. p->line = line;
  310. p->callers = 1;
  311. p->all_caller_locks = netdata_thread_locks;
  312. p->start_s = now_monotonic_high_precision_usec();
  313. // find a slot in the netdata_thread_locks[]
  314. int i;
  315. for(i = 0; i < NETDATA_THREAD_LOCKS_ARRAY_SIZE ;i++) {
  316. if (!netdata_thread_locks[i]) {
  317. netdata_thread_locks[i] = rwlock;
  318. break;
  319. }
  320. }
  321. __netdata_mutex_lock(&rwlock->lockers_mutex);
  322. p->next = rwlock->lockers;
  323. rwlock->lockers = p;
  324. if(lock_type == 'R') rwlock->readers++;
  325. if(lock_type == 'W') rwlock->writers++;
  326. __netdata_mutex_unlock(&rwlock->lockers_mutex);
  327. return p;
  328. }
  329. 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) {
  330. usec_t end_s = now_monotonic_high_precision_usec();
  331. if(locker->callers == 0)
  332. fprintf(stderr,
  333. "RW_LOCK ON LOCK %p: %d, '%s' (function %s() %lu@%s) callers should be positive but it is zero\n",
  334. rwlock,
  335. locker->pid, locker->tag,
  336. locker->function, locker->line, locker->file);
  337. if(locker->callers > 1 && locker->lock != 'R')
  338. fprintf(stderr,
  339. "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",
  340. rwlock,
  341. locker->pid, locker->tag,
  342. locker->function, locker->line, locker->file,
  343. locker->callers, locker->lock);
  344. __netdata_mutex_lock(&rwlock->lockers_mutex);
  345. locker->callers--;
  346. if(!locker->callers) {
  347. int doit = 0;
  348. if (rwlock->lockers == locker) {
  349. rwlock->lockers = locker->next;
  350. doit = 1;
  351. } else {
  352. netdata_rwlock_locker *p;
  353. for (p = rwlock->lockers; p && p->next != locker; p = p->next)
  354. ;
  355. if (p && p->next == locker) {
  356. p->next = locker->next;
  357. doit = 1;
  358. }
  359. }
  360. if(doit) {
  361. if(locker->lock == 'R') rwlock->readers--;
  362. if(locker->lock == 'W') rwlock->writers--;
  363. }
  364. if(!doit) {
  365. fprintf(stderr,
  366. "RW_LOCK ON LOCK %p: %d, '%s' (function %s() %lu@%s) with %zu x '%c' lock is not found.\n",
  367. rwlock,
  368. locker->pid, locker->tag,
  369. locker->function, locker->line, locker->file,
  370. locker->callers, locker->lock);
  371. }
  372. else {
  373. // find the lock in the netdata_thread_locks[]
  374. // and remove it
  375. int i;
  376. for(i = 0; i < NETDATA_THREAD_LOCKS_ARRAY_SIZE ;i++) {
  377. if (netdata_thread_locks[i] == rwlock)
  378. netdata_thread_locks[i] = NULL;
  379. }
  380. if(end_s - locker->start_s >= NETDATA_TRACE_RWLOCKS_HOLD_TIME_TO_IGNORE_USEC)
  381. fprintf(stderr,
  382. "RW_LOCK ON LOCK %p: %d, '%s' (function %s() %lu@%s) holded a '%c' for %llu usec.\n",
  383. rwlock,
  384. locker->pid, locker->tag,
  385. locker->function, locker->line, locker->file,
  386. locker->lock, end_s - locker->start_s);
  387. freez(locker);
  388. }
  389. }
  390. __netdata_mutex_unlock(&rwlock->lockers_mutex);
  391. }
  392. 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) {
  393. pid_t pid = gettid();
  394. netdata_rwlock_locker *p;
  395. __netdata_mutex_lock(&rwlock->lockers_mutex);
  396. for(p = rwlock->lockers; p ;p = p->next) {
  397. if(p->pid == pid) break;
  398. }
  399. __netdata_mutex_unlock(&rwlock->lockers_mutex);
  400. return p;
  401. }
  402. 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) {
  403. if(!locker) {
  404. return add_rwlock_locker(file, function, line, rwlock, locktype);
  405. }
  406. else if(locker->lock == 'R' && locktype == 'R') {
  407. __netdata_mutex_lock(&rwlock->lockers_mutex);
  408. locker->callers++;
  409. __netdata_mutex_unlock(&rwlock->lockers_mutex);
  410. return locker;
  411. }
  412. else {
  413. not_supported_by_posix_rwlocks(file, function, line, rwlock, locktype, "DEADLOCK - WANTS TO CHANGE LOCK TYPE BUT ALREADY HAS THIS LOCKED");
  414. return locker;
  415. }
  416. }
  417. // ----------------------------------------------------------------------------
  418. // debug versions of rwlock
  419. int netdata_rwlock_destroy_debug(const char *file __maybe_unused, const char *function __maybe_unused,
  420. const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
  421. debug(D_LOCKS, "RW_LOCK: netdata_rwlock_destroy(%p) from %lu@%s, %s()", rwlock, line, file, function);
  422. if(rwlock->readers)
  423. error("RW_LOCK: destroying a rwlock with %zu readers in it", rwlock->readers);
  424. if(rwlock->writers)
  425. error("RW_LOCK: destroying a rwlock with %zu writers in it", rwlock->writers);
  426. int ret = __netdata_rwlock_destroy(rwlock);
  427. if(!ret) {
  428. while (rwlock->lockers)
  429. remove_rwlock_locker(file, function, line, rwlock, rwlock->lockers);
  430. if (rwlock->readers)
  431. error("RW_LOCK: internal error - empty rwlock with %zu readers in it", rwlock->readers);
  432. if (rwlock->writers)
  433. error("RW_LOCK: internal error - empty rwlock with %zu writers in it", rwlock->writers);
  434. }
  435. debug(D_LOCKS, "RW_LOCK: netdata_rwlock_destroy(%p) = %d, from %lu@%s, %s()", rwlock, ret, line, file, function);
  436. return ret;
  437. }
  438. int netdata_rwlock_init_debug(const char *file __maybe_unused, const char *function __maybe_unused,
  439. const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
  440. debug(D_LOCKS, "RW_LOCK: netdata_rwlock_init(%p) from %lu@%s, %s()", rwlock, line, file, function);
  441. int ret = __netdata_rwlock_init(rwlock);
  442. if(!ret) {
  443. __netdata_mutex_init(&rwlock->lockers_mutex);
  444. rwlock->lockers = NULL;
  445. rwlock->readers = 0;
  446. rwlock->writers = 0;
  447. }
  448. debug(D_LOCKS, "RW_LOCK: netdata_rwlock_init(%p) = %d, from %lu@%s, %s()", rwlock, ret, line, file, function);
  449. return ret;
  450. }
  451. int netdata_rwlock_rdlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
  452. const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
  453. debug(D_LOCKS, "RW_LOCK: netdata_rwlock_rdlock(%p) from %lu@%s, %s()", rwlock, line, file, function);
  454. netdata_rwlock_locker *locker = find_rwlock_locker(file, function, line, rwlock);
  455. #ifdef NETDATA_TRACE_RWLOCKS_LOG_NESTED
  456. if(locker && locker->lock == 'R') {
  457. log_rwlock_lockers(file, function, line, rwlock, "NESTED READ LOCK REQUEST", 'R');
  458. }
  459. #endif // NETDATA_TRACE_RWLOCKS_LOG_NESTED
  460. int log = 0;
  461. if(rwlock->writers) {
  462. log_rwlock_lockers(file, function, line, rwlock, "WANTS", 'R');
  463. log = 1;
  464. }
  465. usec_t start_s = now_monotonic_high_precision_usec();
  466. int ret = __netdata_rwlock_rdlock(rwlock);
  467. usec_t end_s = now_monotonic_high_precision_usec();
  468. if(!ret) {
  469. locker = update_or_add_rwlock_locker(file, function, line, rwlock, locker, 'R');
  470. if(log) log_rwlock_lockers(file, function, line, rwlock, "GOT", 'R');
  471. }
  472. if(end_s - start_s >= NETDATA_TRACE_RWLOCKS_WAIT_TIME_TO_IGNORE_USEC)
  473. fprintf(stderr,
  474. "RW_LOCK ON LOCK %p: %d, '%s' (function %s() %lu@%s) WAITED for a READ lock for %llu usec.\n",
  475. rwlock,
  476. gettid(), netdata_thread_tag(),
  477. function, line, file,
  478. end_s - start_s);
  479. 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);
  480. return ret;
  481. }
  482. int netdata_rwlock_wrlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
  483. const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
  484. debug(D_LOCKS, "RW_LOCK: netdata_rwlock_wrlock(%p) from %lu@%s, %s()", rwlock, line, file, function);
  485. netdata_rwlock_locker *locker = find_rwlock_locker(file, function, line, rwlock);
  486. if(locker)
  487. not_supported_by_posix_rwlocks(file, function, line, rwlock, 'W', "DEADLOCK - WANTS A WRITE LOCK BUT ALREADY HAVE THIS LOCKED");
  488. int log = 0;
  489. if(rwlock->readers) {
  490. log_rwlock_lockers(file, function, line, rwlock, "WANTS", 'W');
  491. log = 1;
  492. }
  493. usec_t start_s = now_monotonic_high_precision_usec();
  494. int ret = __netdata_rwlock_wrlock(rwlock);
  495. usec_t end_s = now_monotonic_high_precision_usec();
  496. if(!ret){
  497. locker = update_or_add_rwlock_locker(file, function, line, rwlock, locker, 'W');
  498. if(log) log_rwlock_lockers(file, function, line, rwlock, "GOT", 'W');
  499. }
  500. if(end_s - start_s >= NETDATA_TRACE_RWLOCKS_WAIT_TIME_TO_IGNORE_USEC)
  501. fprintf(stderr,
  502. "RW_LOCK ON LOCK %p: %d, '%s' (function %s() %lu@%s) WAITED for a WRITE lock for %llu usec.\n",
  503. rwlock,
  504. gettid(), netdata_thread_tag(),
  505. function, line, file,
  506. end_s - start_s);
  507. 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);
  508. return ret;
  509. }
  510. int netdata_rwlock_unlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
  511. const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
  512. debug(D_LOCKS, "RW_LOCK: netdata_rwlock_unlock(%p) from %lu@%s, %s()", rwlock, line, file, function);
  513. netdata_rwlock_locker *locker = find_rwlock_locker(file, function, line, rwlock);
  514. if(unlikely(!locker))
  515. not_supported_by_posix_rwlocks(file, function, line, rwlock, 'U', "UNLOCK WITHOUT LOCK");
  516. usec_t start_s = now_monotonic_high_precision_usec();
  517. int ret = __netdata_rwlock_unlock(rwlock);
  518. usec_t end_s = now_monotonic_high_precision_usec();
  519. if(end_s - start_s >= NETDATA_TRACE_RWLOCKS_WAIT_TIME_TO_IGNORE_USEC)
  520. fprintf(stderr,
  521. "RW_LOCK ON LOCK %p: %d, '%s' (function %s() %lu@%s) WAITED to UNLOCK for %llu usec.\n",
  522. rwlock,
  523. gettid(), netdata_thread_tag(),
  524. function, line, file,
  525. end_s - start_s);
  526. if(likely(!ret && locker)) remove_rwlock_locker(file, function, line, rwlock, locker);
  527. 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);
  528. return ret;
  529. }
  530. int netdata_rwlock_tryrdlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
  531. const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
  532. debug(D_LOCKS, "RW_LOCK: netdata_rwlock_tryrdlock(%p) from %lu@%s, %s()", rwlock, line, file, function);
  533. netdata_rwlock_locker *locker = find_rwlock_locker(file, function, line, rwlock);
  534. if(locker && locker->lock == 'W')
  535. not_supported_by_posix_rwlocks(file, function, line, rwlock, 'R', "DEADLOCK - WANTS A READ LOCK BUT IT HAS A WRITE LOCK ALREADY");
  536. usec_t start_s = now_monotonic_high_precision_usec();
  537. int ret = __netdata_rwlock_tryrdlock(rwlock);
  538. usec_t end_s = now_monotonic_high_precision_usec();
  539. if(!ret)
  540. locker = update_or_add_rwlock_locker(file, function, line, rwlock, locker, 'R');
  541. if(end_s - start_s >= NETDATA_TRACE_RWLOCKS_WAIT_TIME_TO_IGNORE_USEC)
  542. fprintf(stderr,
  543. "RW_LOCK ON LOCK %p: %d, '%s' (function %s() %lu@%s) WAITED to TRYREAD for %llu usec.\n",
  544. rwlock,
  545. gettid(), netdata_thread_tag(),
  546. function, line, file,
  547. end_s - start_s);
  548. 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);
  549. return ret;
  550. }
  551. int netdata_rwlock_trywrlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
  552. const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
  553. debug(D_LOCKS, "RW_LOCK: netdata_rwlock_trywrlock(%p) from %lu@%s, %s()", rwlock, line, file, function);
  554. netdata_rwlock_locker *locker = find_rwlock_locker(file, function, line, rwlock);
  555. if(locker)
  556. not_supported_by_posix_rwlocks(file, function, line, rwlock, 'W', "ALREADY HAS THIS LOCK");
  557. usec_t start_s = now_monotonic_high_precision_usec();
  558. int ret = __netdata_rwlock_trywrlock(rwlock);
  559. usec_t end_s = now_monotonic_high_precision_usec();
  560. if(!ret)
  561. locker = update_or_add_rwlock_locker(file, function, line, rwlock, locker, 'W');
  562. if(end_s - start_s >= NETDATA_TRACE_RWLOCKS_WAIT_TIME_TO_IGNORE_USEC)
  563. fprintf(stderr,
  564. "RW_LOCK ON LOCK %p: %d, '%s' (function %s() %lu@%s) WAITED to TRYWRITE for %llu usec.\n",
  565. rwlock,
  566. gettid(), netdata_thread_tag(),
  567. function, line, file,
  568. end_s - start_s);
  569. 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);
  570. return ret;
  571. }
  572. #endif // NETDATA_TRACE_RWLOCKS