Asterisk - The Open Source Telephony Project  GIT-master-1b41629
lock.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2010, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  *
21  * \brief General Asterisk locking.
22  */
23 
24 /*** MODULEINFO
25  <support_level>core</support_level>
26  ***/
27 
28 #include "asterisk.h"
29 
30 #ifdef HAVE_MTX_PROFILE
31 /* profile mutex */
32 static int mtx_prof = -1;
33 static void __attribute__((constructor)) __mtx_init(void)
34 {
35  mtx_prof = ast_add_profile("mtx_lock_" __FILE__, 0);
36 }
37 #endif
38 
39 #include "asterisk/utils.h"
40 #include "asterisk/lock.h"
41 
42 /* Allow direct use of pthread_mutex_* / pthread_cond_* */
43 #undef pthread_mutex_init
44 #undef pthread_mutex_destroy
45 #undef pthread_mutex_lock
46 #undef pthread_mutex_trylock
47 #undef pthread_mutex_t
48 #undef pthread_mutex_unlock
49 #undef pthread_cond_init
50 #undef pthread_cond_signal
51 #undef pthread_cond_broadcast
52 #undef pthread_cond_destroy
53 #undef pthread_cond_wait
54 #undef pthread_cond_timedwait
55 
56 #if defined(DEBUG_THREADS)
57 #define log_mutex_error(canlog, ...) \
58  do { \
59  if (canlog) { \
60  ast_log(LOG_ERROR, __VA_ARGS__); \
61  } else { \
62  fprintf(stderr, __VA_ARGS__); \
63  } \
64  } while (0)
65 #endif
66 
67 #if defined(DEBUG_THREADS) && defined(HAVE_BKTR)
68 static void __dump_backtrace(struct ast_bt *bt, int canlog)
69 {
70  char **strings;
71  ssize_t i;
72 
73  strings = backtrace_symbols(bt->addresses, bt->num_frames);
74 
75  for (i = 0; i < bt->num_frames; i++) {
76  log_mutex_error(canlog, "%s\n", strings[i]);
77  }
78 
79  ast_std_free(strings);
80 }
81 #endif /* defined(DEBUG_THREADS) && defined(HAVE_BKTR) */
82 
83 #ifdef DEBUG_THREADS
84 AST_MUTEX_DEFINE_STATIC(reentrancy_lock);
85 
86 static inline struct ast_lock_track *ast_get_reentrancy(struct ast_lock_track **plt,
87  struct ast_lock_track_flags *flags, int no_setup)
88 {
89  pthread_mutexattr_t reentr_attr;
90  struct ast_lock_track *lt;
91 
92  if (!flags->tracking || flags->setup) {
93  return *plt;
94  }
95 
96  pthread_mutex_lock(&reentrancy_lock.mutex);
97 
98  if (*plt) {
99  pthread_mutex_unlock(&reentrancy_lock.mutex);
100  return *plt;
101  }
102 
103  if (no_setup) {
104  pthread_mutex_unlock(&reentrancy_lock.mutex);
105  return NULL;
106  }
107 
108  lt = *plt = ast_std_calloc(1, sizeof(*lt));
109  if (!lt) {
110  fprintf(stderr, "%s: Failed to allocate lock tracking\n", __func__);
111 #if defined(DO_CRASH) || defined(THREAD_CRASH)
112  abort();
113 #else
114  pthread_mutex_unlock(&reentrancy_lock.mutex);
115  return NULL;
116 #endif
117  }
118 
119  pthread_mutexattr_init(&reentr_attr);
120  pthread_mutexattr_settype(&reentr_attr, AST_MUTEX_KIND);
121  pthread_mutex_init(&lt->reentr_mutex, &reentr_attr);
122  pthread_mutexattr_destroy(&reentr_attr);
123 
124  flags->setup = 1;
125  pthread_mutex_unlock(&reentrancy_lock.mutex);
126  return lt;
127 }
128 
129 static inline void delete_reentrancy_cs(struct ast_lock_track **plt)
130 {
131  struct ast_lock_track *lt;
132 
133  if (*plt) {
134  lt = *plt;
135  *plt = NULL;
136 
138  ast_std_free(lt);
139  }
140 }
141 
142 #endif /* DEBUG_THREADS */
143 
144 int __ast_pthread_mutex_init(int tracking, const char *filename, int lineno, const char *func,
145  const char *mutex_name, ast_mutex_t *t)
146 {
147  int res;
148  pthread_mutexattr_t attr;
149 
150 #ifdef DEBUG_THREADS
151 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
152  if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
153  int canlog = tracking && strcmp(filename, "logger.c");
154 
155  log_mutex_error(canlog, "%s line %d (%s): NOTICE: mutex '%s' is already initialized.\n",
156  filename, lineno, func, mutex_name);
157  DO_THREAD_CRASH;
158  return EBUSY;
159  }
160 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
161 
162  t->track = NULL;
163  t->flags.tracking = tracking;
164  t->flags.setup = 0;
165 #endif /* DEBUG_THREADS */
166 
167  pthread_mutexattr_init(&attr);
168  pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
169  res = pthread_mutex_init(&t->mutex, &attr);
170  pthread_mutexattr_destroy(&attr);
171 
172  return res;
173 }
174 
175 int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
176  const char *mutex_name, ast_mutex_t *t)
177 {
178  int res;
179 
180 #ifdef DEBUG_THREADS
181  struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 1);
182  int canlog = t->flags.tracking && strcmp(filename, "logger.c");
183 
184 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
185  if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
186  /* Don't try to uninitialize an uninitialized mutex
187  * This may have no effect on linux
188  * but it always generates a core on *BSD when
189  * linked with libpthread.
190  * This is not an error condition if the mutex is created on the fly.
191  */
192  log_mutex_error(canlog, "%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
193  filename, lineno, func, mutex_name);
194  DO_THREAD_CRASH;
195  res = EINVAL;
196  goto lt_cleanup;
197  }
198 #endif
199 
200  res = pthread_mutex_trylock(&t->mutex);
201  switch (res) {
202  case 0:
204  break;
205  case EINVAL:
206  log_mutex_error(canlog, "%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
207  filename, lineno, func, mutex_name);
208  break;
209  case EBUSY:
210  log_mutex_error(canlog, "%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
211  filename, lineno, func, mutex_name);
212  if (lt) {
213  ast_reentrancy_lock(lt);
214  log_mutex_error(canlog, "%s line %d (%s): Error: '%s' was locked here.\n",
215  lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
216 #ifdef HAVE_BKTR
217  __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
218 #endif
219  ast_reentrancy_unlock(lt);
220  }
221  break;
222  }
223 #endif /* DEBUG_THREADS */
224 
225  res = pthread_mutex_destroy(&t->mutex);
226 
227 #ifdef DEBUG_THREADS
228  if (res) {
229  log_mutex_error(canlog, "%s line %d (%s): Error destroying mutex %s: %s\n",
230  filename, lineno, func, mutex_name, strerror(res));
231  }
232 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
233 lt_cleanup:
234 #endif
235  if (lt) {
236  ast_reentrancy_lock(lt);
237  lt->file[0] = filename;
238  lt->lineno[0] = lineno;
239  lt->func[0] = func;
240  lt->reentrancy = 0;
241  lt->thread_id[0] = 0;
242 #ifdef HAVE_BKTR
243  memset(&lt->backtrace[0], 0, sizeof(lt->backtrace[0]));
244 #endif
245  ast_reentrancy_unlock(lt);
246  delete_reentrancy_cs(&t->track);
247  }
248 #endif /* DEBUG_THREADS */
249 
250  return res;
251 }
252 
253 int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
254  const char* mutex_name, ast_mutex_t *t)
255 {
256  int res;
257 
258 #ifdef DEBUG_THREADS
259  struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
260  int canlog = t->flags.tracking && strcmp(filename, "logger.c");
261  struct ast_bt *bt = NULL;
262 
263  if (lt) {
264 #ifdef HAVE_BKTR
265  struct ast_bt tmp;
266 
267  /* The implementation of backtrace() may have its own locks.
268  * Capture the backtrace outside of the reentrancy lock to
269  * avoid deadlocks. See ASTERISK-22455. */
270  ast_bt_get_addresses(&tmp);
271 
272  ast_reentrancy_lock(lt);
273  if (lt->reentrancy < AST_MAX_REENTRANCY) {
274  lt->backtrace[lt->reentrancy] = tmp;
275  bt = &lt->backtrace[lt->reentrancy];
276  }
277  ast_reentrancy_unlock(lt);
278 #endif
279  ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
280  }
281 #endif /* DEBUG_THREADS */
282 
283 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
284  {
285  time_t seconds = time(NULL);
286  time_t wait_time, reported_wait = 0;
287  do {
288 #ifdef HAVE_MTX_PROFILE
289  ast_mark(mtx_prof, 1);
290 #endif
291  res = pthread_mutex_trylock(&t->mutex);
292 #ifdef HAVE_MTX_PROFILE
293  ast_mark(mtx_prof, 0);
294 #endif
295  if (res == EBUSY) {
296  wait_time = time(NULL) - seconds;
297  if (wait_time > reported_wait && (wait_time % 5) == 0) {
298  log_mutex_error(canlog, "%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
299  filename, lineno, func, (int) wait_time, mutex_name);
300  if (lt) {
301  ast_reentrancy_lock(lt);
302 #ifdef HAVE_BKTR
303  __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
304 #endif
305  log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
306  lt->file[ROFFSET], lt->lineno[ROFFSET],
307  lt->func[ROFFSET], mutex_name);
308 #ifdef HAVE_BKTR
309  __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
310 #endif
311  ast_reentrancy_unlock(lt);
312  }
313  reported_wait = wait_time;
314  }
315  usleep(200);
316  }
317  } while (res == EBUSY);
318  }
319 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
320 #ifdef HAVE_MTX_PROFILE
321  ast_mark(mtx_prof, 1);
322  res = pthread_mutex_trylock(&t->mutex);
323  ast_mark(mtx_prof, 0);
324  if (res)
325 #endif
326  res = pthread_mutex_lock(&t->mutex);
327 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
328 
329 #ifdef DEBUG_THREADS
330  if (lt && !res) {
331  ast_reentrancy_lock(lt);
332  if (lt->reentrancy < AST_MAX_REENTRANCY) {
333  lt->file[lt->reentrancy] = filename;
334  lt->lineno[lt->reentrancy] = lineno;
335  lt->func[lt->reentrancy] = func;
336  lt->thread_id[lt->reentrancy] = pthread_self();
337  lt->reentrancy++;
338  } else {
339  log_mutex_error(canlog, "%s line %d (%s): '%s' really deep reentrancy!\n",
340  filename, lineno, func, mutex_name);
341  }
342  ast_reentrancy_unlock(lt);
343  ast_mark_lock_acquired(t);
344  } else if (lt) {
345 #ifdef HAVE_BKTR
346  if (lt->reentrancy) {
347  ast_reentrancy_lock(lt);
348  bt = &lt->backtrace[lt->reentrancy-1];
349  ast_reentrancy_unlock(lt);
350  } else {
351  bt = NULL;
352  }
353 #endif
354  ast_remove_lock_info(t, bt);
355  }
356  if (res) {
357  log_mutex_error(canlog, "%s line %d (%s): Error obtaining mutex: %s\n",
358  filename, lineno, func, strerror(res));
359  DO_THREAD_CRASH;
360  }
361 #endif /* DEBUG_THREADS */
362 
363  return res;
364 }
365 
366 int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
367  const char* mutex_name, ast_mutex_t *t)
368 {
369  int res;
370 
371 #ifdef DEBUG_THREADS
372  struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
373  int canlog = t->flags.tracking && strcmp(filename, "logger.c");
374  struct ast_bt *bt = NULL;
375 
376  if (lt) {
377 #ifdef HAVE_BKTR
378  struct ast_bt tmp;
379 
380  /* The implementation of backtrace() may have its own locks.
381  * Capture the backtrace outside of the reentrancy lock to
382  * avoid deadlocks. See ASTERISK-22455. */
383  ast_bt_get_addresses(&tmp);
384 
385  ast_reentrancy_lock(lt);
386  if (lt->reentrancy < AST_MAX_REENTRANCY) {
387  lt->backtrace[lt->reentrancy] = tmp;
388  bt = &lt->backtrace[lt->reentrancy];
389  }
390  ast_reentrancy_unlock(lt);
391 #endif
392  ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
393  }
394 #endif /* DEBUG_THREADS */
395 
396  res = pthread_mutex_trylock(&t->mutex);
397 
398 #ifdef DEBUG_THREADS
399  if (lt && !res) {
400  ast_reentrancy_lock(lt);
401  if (lt->reentrancy < AST_MAX_REENTRANCY) {
402  lt->file[lt->reentrancy] = filename;
403  lt->lineno[lt->reentrancy] = lineno;
404  lt->func[lt->reentrancy] = func;
405  lt->thread_id[lt->reentrancy] = pthread_self();
406  lt->reentrancy++;
407  } else {
408  log_mutex_error(canlog, "%s line %d (%s): '%s' really deep reentrancy!\n",
409  filename, lineno, func, mutex_name);
410  }
411  ast_reentrancy_unlock(lt);
412  ast_mark_lock_acquired(t);
413  } else if (lt) {
415  }
416 #endif /* DEBUG_THREADS */
417 
418  return res;
419 }
420 
421 int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
422  const char *mutex_name, ast_mutex_t *t)
423 {
424  int res;
425 
426 #ifdef DEBUG_THREADS
427  struct ast_lock_track *lt = NULL;
428  int canlog = t->flags.tracking && strcmp(filename, "logger.c");
429  struct ast_bt *bt = NULL;
430 
431 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
432  if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
433  log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
434  filename, lineno, func, mutex_name);
435  DO_THREAD_CRASH;
436  return EINVAL;
437  }
438 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
439 
440  lt = ast_get_reentrancy(&t->track, &t->flags, 0);
441  if (lt) {
442  ast_reentrancy_lock(lt);
443  if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
444  log_mutex_error(canlog, "%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
445  filename, lineno, func, mutex_name);
446  log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
447  lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
448 #ifdef HAVE_BKTR
449  __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
450 #endif
451  DO_THREAD_CRASH;
452  }
453 
454  if (--lt->reentrancy < 0) {
455  log_mutex_error(canlog, "%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
456  filename, lineno, func, mutex_name);
457  lt->reentrancy = 0;
458  }
459 
460  if (lt->reentrancy < AST_MAX_REENTRANCY) {
461  lt->file[lt->reentrancy] = NULL;
462  lt->lineno[lt->reentrancy] = 0;
463  lt->func[lt->reentrancy] = NULL;
464  lt->thread_id[lt->reentrancy] = 0;
465  }
466 
467 #ifdef HAVE_BKTR
468  if (lt->reentrancy) {
469  bt = &lt->backtrace[lt->reentrancy - 1];
470  }
471 #endif
472  ast_reentrancy_unlock(lt);
473 
474  ast_remove_lock_info(t, bt);
475  }
476 #endif /* DEBUG_THREADS */
477 
478  res = pthread_mutex_unlock(&t->mutex);
479 
480 #ifdef DEBUG_THREADS
481  if (res) {
482  log_mutex_error(canlog, "%s line %d (%s): Error releasing mutex: %s\n",
483  filename, lineno, func, strerror(res));
484  DO_THREAD_CRASH;
485  }
486 #endif /* DEBUG_THREADS */
487 
488  return res;
489 }
490 
491 
492 int __ast_cond_init(const char *filename, int lineno, const char *func,
493  const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
494 {
495  return pthread_cond_init(cond, cond_attr);
496 }
497 
498 int __ast_cond_signal(const char *filename, int lineno, const char *func,
499  const char *cond_name, ast_cond_t *cond)
500 {
501  return pthread_cond_signal(cond);
502 }
503 
504 int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
505  const char *cond_name, ast_cond_t *cond)
506 {
507  return pthread_cond_broadcast(cond);
508 }
509 
510 int __ast_cond_destroy(const char *filename, int lineno, const char *func,
511  const char *cond_name, ast_cond_t *cond)
512 {
513  return pthread_cond_destroy(cond);
514 }
515 
516 #ifdef DEBUG_THREADS
517 static void restore_lock_tracking(struct ast_lock_track *lt, struct ast_lock_track *lt_saved)
518 {
519  ast_reentrancy_lock(lt);
520 
521  /*
522  * The following code must match the struct ast_lock_track
523  * definition with the explicit exception of the reentr_mutex
524  * member.
525  */
526  memcpy(lt->file, lt_saved->file, sizeof(lt->file));
527  memcpy(lt->lineno, lt_saved->lineno, sizeof(lt->lineno));
528  lt->reentrancy = lt_saved->reentrancy;
529  memcpy(lt->func, lt_saved->func, sizeof(lt->func));
530  memcpy(lt->thread_id, lt_saved->thread_id, sizeof(lt->thread_id));
531 #ifdef HAVE_BKTR
532  memcpy(lt->backtrace, lt_saved->backtrace, sizeof(lt->backtrace));
533 #endif
534 
535  ast_reentrancy_unlock(lt);
536 }
537 #endif /* DEBUG_THREADS */
538 
539 int __ast_cond_wait(const char *filename, int lineno, const char *func,
540  const char *cond_name, const char *mutex_name,
542 {
543  int res;
544 
545 #ifdef DEBUG_THREADS
546  struct ast_lock_track *lt = NULL;
547  struct ast_lock_track lt_orig;
548  int canlog = t->flags.tracking && strcmp(filename, "logger.c");
549 
550 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
551  if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
552  log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
553  filename, lineno, func, mutex_name);
554  DO_THREAD_CRASH;
555  return EINVAL;
556  }
557 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
558 
559  lt = ast_get_reentrancy(&t->track, &t->flags, 0);
560  if (lt) {
561  ast_reentrancy_lock(lt);
562  if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
563  log_mutex_error(canlog, "%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
564  filename, lineno, func, mutex_name);
565  log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
566  lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
567 #ifdef HAVE_BKTR
568  __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
569 #endif
570  DO_THREAD_CRASH;
571  } else if (lt->reentrancy <= 0) {
572  log_mutex_error(canlog, "%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
573  filename, lineno, func, mutex_name);
574  DO_THREAD_CRASH;
575  }
576 
577  /* Waiting on a condition completely suspends a recursive mutex,
578  * even if it's been recursively locked multiple times. Make a
579  * copy of the lock tracking, and reset reentrancy to zero */
580  lt_orig = *lt;
581  lt->reentrancy = 0;
582  ast_reentrancy_unlock(lt);
583 
584  ast_suspend_lock_info(t);
585  }
586 #endif /* DEBUG_THREADS */
587 
588  res = pthread_cond_wait(cond, &t->mutex);
589 
590 #ifdef DEBUG_THREADS
591  if (res) {
592  log_mutex_error(canlog, "%s line %d (%s): Error waiting on condition mutex '%s'\n",
593  filename, lineno, func, strerror(res));
594  DO_THREAD_CRASH;
595  } else if (lt) {
596  restore_lock_tracking(lt, &lt_orig);
597  ast_restore_lock_info(t);
598  }
599 #endif /* DEBUG_THREADS */
600 
601  return res;
602 }
603 
604 int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
605  const char *cond_name, const char *mutex_name, ast_cond_t *cond,
606  ast_mutex_t *t, const struct timespec *abstime)
607 {
608  int res;
609 
610 #ifdef DEBUG_THREADS
611  struct ast_lock_track *lt = NULL;
612  struct ast_lock_track lt_orig;
613  int canlog = t->flags.tracking && strcmp(filename, "logger.c");
614 
615 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
616  if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
617  log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
618  filename, lineno, func, mutex_name);
619  DO_THREAD_CRASH;
620  return EINVAL;
621  }
622 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
623 
624  lt = ast_get_reentrancy(&t->track, &t->flags, 0);
625  if (lt) {
626  ast_reentrancy_lock(lt);
627  if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
628  log_mutex_error(canlog, "%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
629  filename, lineno, func, mutex_name);
630  log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
631  lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
632 #ifdef HAVE_BKTR
633  __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
634 #endif
635  DO_THREAD_CRASH;
636  } else if (lt->reentrancy <= 0) {
637  log_mutex_error(canlog, "%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
638  filename, lineno, func, mutex_name);
639  DO_THREAD_CRASH;
640  }
641 
642  /* Waiting on a condition completely suspends a recursive mutex,
643  * even if it's been recursively locked multiple times. Make a
644  * copy of the lock tracking, and reset reentrancy to zero */
645  lt_orig = *lt;
646  lt->reentrancy = 0;
647  ast_reentrancy_unlock(lt);
648 
649  ast_suspend_lock_info(t);
650  }
651 #endif /* DEBUG_THREADS */
652 
653  res = pthread_cond_timedwait(cond, &t->mutex, abstime);
654 
655 #ifdef DEBUG_THREADS
656  if (res && (res != ETIMEDOUT)) {
657  log_mutex_error(canlog, "%s line %d (%s): Error waiting on condition mutex '%s'\n",
658  filename, lineno, func, strerror(res));
659  DO_THREAD_CRASH;
660  } else if (lt) {
661  restore_lock_tracking(lt, &lt_orig);
662  ast_restore_lock_info(t);
663  }
664 #endif /* DEBUG_THREADS */
665 
666  return res;
667 }
668 
669 int __ast_rwlock_init(int tracking, const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
670 {
671  int res;
672  pthread_rwlockattr_t attr;
673 
674 #ifdef DEBUG_THREADS
675 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
676  if (t->lock != ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
677  int canlog = tracking && strcmp(filename, "logger.c");
678 
679  log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
680  filename, lineno, func, rwlock_name);
681  DO_THREAD_CRASH;
682  return EBUSY;
683  }
684 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
685 
686  t->track = NULL;
687  t->flags.tracking = tracking;
688  t->flags.setup = 0;
689 #endif /* DEBUG_THREADS */
690 
691  pthread_rwlockattr_init(&attr);
692 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
693  pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
694 #endif
695  res = pthread_rwlock_init(&t->lock, &attr);
696  pthread_rwlockattr_destroy(&attr);
697 
698  return res;
699 }
700 
701 int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
702 {
703  int res;
704 
705 #ifdef DEBUG_THREADS
706  struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 1);
707  int canlog = t->flags.tracking && strcmp(filename, "logger.c");
708 
709 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
710  if (t->lock == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
711  log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
712  filename, lineno, func, rwlock_name);
713  DO_THREAD_CRASH;
714  res = EINVAL;
715  goto lt_cleanup;
716  }
717 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
718 #endif /* DEBUG_THREADS */
719 
720  res = pthread_rwlock_destroy(&t->lock);
721 
722 #ifdef DEBUG_THREADS
723  if (res) {
724  log_mutex_error(canlog, "%s line %d (%s): Error destroying rwlock %s: %s\n",
725  filename, lineno, func, rwlock_name, strerror(res));
726  }
727 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
728 lt_cleanup:
729 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
730  if (lt) {
731  ast_reentrancy_lock(lt);
732  lt->file[0] = filename;
733  lt->lineno[0] = lineno;
734  lt->func[0] = func;
735  lt->reentrancy = 0;
736  lt->thread_id[0] = 0;
737 #ifdef HAVE_BKTR
738  memset(&lt->backtrace[0], 0, sizeof(lt->backtrace[0]));
739 #endif
740  ast_reentrancy_unlock(lt);
741  delete_reentrancy_cs(&t->track);
742  }
743 #endif /* DEBUG_THREADS */
744 
745  return res;
746 }
747 
748 int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
749 {
750  int res;
751 
752 #ifdef DEBUG_THREADS
753  struct ast_lock_track *lt = NULL;
754  int canlog = t->flags.tracking && strcmp(filename, "logger.c");
755  struct ast_bt *bt = NULL;
756  int lock_found = 0;
757 
758 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
759  if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
760  log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
761  filename, line, func, name);
762  DO_THREAD_CRASH;
763  return EINVAL;
764  }
765 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
766 
767  lt = ast_get_reentrancy(&t->track, &t->flags, 0);
768  if (lt) {
769  ast_reentrancy_lock(lt);
770  if (lt->reentrancy) {
771  int i;
772  pthread_t self = pthread_self();
773  for (i = lt->reentrancy - 1; i >= 0; --i) {
774  if (lt->thread_id[i] == self) {
775  lock_found = 1;
776  if (i != lt->reentrancy - 1) {
777  lt->file[i] = lt->file[lt->reentrancy - 1];
778  lt->lineno[i] = lt->lineno[lt->reentrancy - 1];
779  lt->func[i] = lt->func[lt->reentrancy - 1];
780  lt->thread_id[i] = lt->thread_id[lt->reentrancy - 1];
781  }
782 #ifdef HAVE_BKTR
783  bt = &lt->backtrace[i];
784 #endif
785  lt->file[lt->reentrancy - 1] = NULL;
786  lt->lineno[lt->reentrancy - 1] = 0;
787  lt->func[lt->reentrancy - 1] = NULL;
788  lt->thread_id[lt->reentrancy - 1] = AST_PTHREADT_NULL;
789  break;
790  }
791  }
792  }
793 
794  if (lock_found && --lt->reentrancy < 0) {
795  log_mutex_error(canlog, "%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
796  filename, line, func, name);
797  lt->reentrancy = 0;
798  }
799 
800  ast_reentrancy_unlock(lt);
801 
802  ast_remove_lock_info(t, bt);
803  }
804 #endif /* DEBUG_THREADS */
805 
806  res = pthread_rwlock_unlock(&t->lock);
807 
808 #ifdef DEBUG_THREADS
809  if (res) {
810  log_mutex_error(canlog, "%s line %d (%s): Error releasing rwlock: %s\n",
811  filename, line, func, strerror(res));
812  DO_THREAD_CRASH;
813  }
814 #endif /* DEBUG_THREADS */
815 
816  return res;
817 }
818 
819 int __ast_rwlock_rdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
820 {
821  int res;
822 
823 #ifdef DEBUG_THREADS
824  struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
825  int canlog = t->flags.tracking && strcmp(filename, "logger.c");
826  struct ast_bt *bt = NULL;
827 
828  if (lt) {
829 #ifdef HAVE_BKTR
830  struct ast_bt tmp;
831 
832  /* The implementation of backtrace() may have its own locks.
833  * Capture the backtrace outside of the reentrancy lock to
834  * avoid deadlocks. See ASTERISK-22455. */
835  ast_bt_get_addresses(&tmp);
836 
837  ast_reentrancy_lock(lt);
838  if (lt->reentrancy < AST_MAX_REENTRANCY) {
839  lt->backtrace[lt->reentrancy] = tmp;
840  bt = &lt->backtrace[lt->reentrancy];
841  }
842  ast_reentrancy_unlock(lt);
843 #endif
844  ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
845  }
846 #endif /* DEBUG_THREADS */
847 
848 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
849  {
850  time_t seconds = time(NULL);
851  time_t wait_time, reported_wait = 0;
852  do {
853  res = pthread_rwlock_tryrdlock(&t->lock);
854  if (res == EBUSY) {
855  wait_time = time(NULL) - seconds;
856  if (wait_time > reported_wait && (wait_time % 5) == 0) {
857  log_mutex_error(canlog, "%s line %d (%s): Deadlock? waited %d sec for readlock '%s'?\n",
858  filename, line, func, (int)wait_time, name);
859  if (lt) {
860  ast_reentrancy_lock(lt);
861 #ifdef HAVE_BKTR
862  __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
863 #endif
864  log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
865  lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
866  lt->func[lt->reentrancy-1], name);
867 #ifdef HAVE_BKTR
868  __dump_backtrace(&lt->backtrace[lt->reentrancy-1], canlog);
869 #endif
870  ast_reentrancy_unlock(lt);
871  }
872  reported_wait = wait_time;
873  }
874  usleep(200);
875  }
876  } while (res == EBUSY);
877  }
878 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
879  res = pthread_rwlock_rdlock(&t->lock);
880 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
881 
882 #ifdef DEBUG_THREADS
883  if (!res && lt) {
884  ast_reentrancy_lock(lt);
885  if (lt->reentrancy < AST_MAX_REENTRANCY) {
886  lt->file[lt->reentrancy] = filename;
887  lt->lineno[lt->reentrancy] = line;
888  lt->func[lt->reentrancy] = func;
889  lt->thread_id[lt->reentrancy] = pthread_self();
890  lt->reentrancy++;
891  }
892  ast_reentrancy_unlock(lt);
893  ast_mark_lock_acquired(t);
894  } else if (lt) {
895 #ifdef HAVE_BKTR
896  if (lt->reentrancy) {
897  ast_reentrancy_lock(lt);
898  bt = &lt->backtrace[lt->reentrancy-1];
899  ast_reentrancy_unlock(lt);
900  } else {
901  bt = NULL;
902  }
903 #endif
904  ast_remove_lock_info(t, bt);
905  }
906 
907  if (res) {
908  log_mutex_error(canlog, "%s line %d (%s): Error obtaining read lock: %s\n",
909  filename, line, func, strerror(res));
910  DO_THREAD_CRASH;
911  }
912 #endif /* DEBUG_THREADS */
913 
914  return res;
915 }
916 
917 int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
918 {
919  int res;
920 
921 #ifdef DEBUG_THREADS
922  struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
923  int canlog = t->flags.tracking && strcmp(filename, "logger.c");
924  struct ast_bt *bt = NULL;
925 
926  if (lt) {
927 #ifdef HAVE_BKTR
928  struct ast_bt tmp;
929 
930  /* The implementation of backtrace() may have its own locks.
931  * Capture the backtrace outside of the reentrancy lock to
932  * avoid deadlocks. See ASTERISK-22455. */
933  ast_bt_get_addresses(&tmp);
934 
935  ast_reentrancy_lock(lt);
936  if (lt->reentrancy < AST_MAX_REENTRANCY) {
937  lt->backtrace[lt->reentrancy] = tmp;
938  bt = &lt->backtrace[lt->reentrancy];
939  }
940  ast_reentrancy_unlock(lt);
941 #endif
942  ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
943  }
944 #endif /* DEBUG_THREADS */
945 
946 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
947  {
948  time_t seconds = time(NULL);
949  time_t wait_time, reported_wait = 0;
950  do {
951  res = pthread_rwlock_trywrlock(&t->lock);
952  if (res == EBUSY) {
953  wait_time = time(NULL) - seconds;
954  if (wait_time > reported_wait && (wait_time % 5) == 0) {
955  log_mutex_error(canlog, "%s line %d (%s): Deadlock? waited %d sec for writelock '%s'?\n",
956  filename, line, func, (int)wait_time, name);
957  if (lt) {
958  ast_reentrancy_lock(lt);
959 #ifdef HAVE_BKTR
960  __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
961 #endif
962  log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
963  lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
964  lt->func[lt->reentrancy-1], name);
965 #ifdef HAVE_BKTR
966  __dump_backtrace(&lt->backtrace[lt->reentrancy-1], canlog);
967 #endif
968  ast_reentrancy_unlock(lt);
969  }
970  reported_wait = wait_time;
971  }
972  usleep(200);
973  }
974  } while (res == EBUSY);
975  }
976 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
977  res = pthread_rwlock_wrlock(&t->lock);
978 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
979 
980 #ifdef DEBUG_THREADS
981  if (!res && lt) {
982  ast_reentrancy_lock(lt);
983  if (lt->reentrancy < AST_MAX_REENTRANCY) {
984  lt->file[lt->reentrancy] = filename;
985  lt->lineno[lt->reentrancy] = line;
986  lt->func[lt->reentrancy] = func;
987  lt->thread_id[lt->reentrancy] = pthread_self();
988  lt->reentrancy++;
989  }
990  ast_reentrancy_unlock(lt);
991  ast_mark_lock_acquired(t);
992  } else if (lt) {
993 #ifdef HAVE_BKTR
994  if (lt->reentrancy) {
995  ast_reentrancy_lock(lt);
996  bt = &lt->backtrace[lt->reentrancy-1];
997  ast_reentrancy_unlock(lt);
998  } else {
999  bt = NULL;
1000  }
1001 #endif
1002  ast_remove_lock_info(t, bt);
1003  }
1004  if (res) {
1005  log_mutex_error(canlog, "%s line %d (%s): Error obtaining write lock: %s\n",
1006  filename, line, func, strerror(res));
1007  DO_THREAD_CRASH;
1008  }
1009 #endif /* DEBUG_THREADS */
1010 
1011  return res;
1012 }
1013 
1014 int __ast_rwlock_timedrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1015  const struct timespec *abs_timeout)
1016 {
1017  int res;
1018 
1019 #ifdef DEBUG_THREADS
1020  struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1021  int canlog = t->flags.tracking && strcmp(filename, "logger.c");
1022  struct ast_bt *bt = NULL;
1023 
1024  if (lt) {
1025 #ifdef HAVE_BKTR
1026  struct ast_bt tmp;
1027 
1028  /* The implementation of backtrace() may have its own locks.
1029  * Capture the backtrace outside of the reentrancy lock to
1030  * avoid deadlocks. See ASTERISK-22455. */
1031  ast_bt_get_addresses(&tmp);
1032 
1033  ast_reentrancy_lock(lt);
1034  if (lt->reentrancy < AST_MAX_REENTRANCY) {
1035  lt->backtrace[lt->reentrancy] = tmp;
1036  bt = &lt->backtrace[lt->reentrancy];
1037  }
1038  ast_reentrancy_unlock(lt);
1039 #endif
1040  ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1041  }
1042 #endif /* DEBUG_THREADS */
1043 
1044 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1045  res = pthread_rwlock_timedrdlock(&t->lock, abs_timeout);
1046 #else
1047  do {
1048  struct timeval _now;
1049  for (;;) {
1050  if (!(res = pthread_rwlock_tryrdlock(&t->lock))) {
1051  break;
1052  }
1053  _now = ast_tvnow();
1054  if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1055  break;
1056  }
1057  usleep(1);
1058  }
1059  } while (0);
1060 #endif
1061 
1062 #ifdef DEBUG_THREADS
1063  if (!res && lt) {
1064  ast_reentrancy_lock(lt);
1065  if (lt->reentrancy < AST_MAX_REENTRANCY) {
1066  lt->file[lt->reentrancy] = filename;
1067  lt->lineno[lt->reentrancy] = line;
1068  lt->func[lt->reentrancy] = func;
1069  lt->thread_id[lt->reentrancy] = pthread_self();
1070  lt->reentrancy++;
1071  }
1072  ast_reentrancy_unlock(lt);
1073  ast_mark_lock_acquired(t);
1074  } else if (lt) {
1075 #ifdef HAVE_BKTR
1076  if (lt->reentrancy) {
1077  ast_reentrancy_lock(lt);
1078  bt = &lt->backtrace[lt->reentrancy-1];
1079  ast_reentrancy_unlock(lt);
1080  } else {
1081  bt = NULL;
1082  }
1083 #endif
1084  ast_remove_lock_info(t, bt);
1085  }
1086  if (res) {
1087  log_mutex_error(canlog, "%s line %d (%s): Error obtaining read lock: %s\n",
1088  filename, line, func, strerror(res));
1089  DO_THREAD_CRASH;
1090  }
1091 #endif /* DEBUG_THREADS */
1092 
1093  return res;
1094 }
1095 
1096 int __ast_rwlock_timedwrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1097  const struct timespec *abs_timeout)
1098 {
1099  int res;
1100 
1101 #ifdef DEBUG_THREADS
1102  struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1103  int canlog = t->flags.tracking && strcmp(filename, "logger.c");
1104  struct ast_bt *bt = NULL;
1105 
1106  if (lt) {
1107 #ifdef HAVE_BKTR
1108  struct ast_bt tmp;
1109 
1110  /* The implementation of backtrace() may have its own locks.
1111  * Capture the backtrace outside of the reentrancy lock to
1112  * avoid deadlocks. See ASTERISK-22455. */
1113  ast_bt_get_addresses(&tmp);
1114 
1115  ast_reentrancy_lock(lt);
1116  if (lt->reentrancy < AST_MAX_REENTRANCY) {
1117  lt->backtrace[lt->reentrancy] = tmp;
1118  bt = &lt->backtrace[lt->reentrancy];
1119  }
1120  ast_reentrancy_unlock(lt);
1121 #endif
1122  ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1123  }
1124 #endif /* DEBUG_THREADS */
1125 
1126 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1127  res = pthread_rwlock_timedwrlock(&t->lock, abs_timeout);
1128 #else
1129  do {
1130  struct timeval _now;
1131  for (;;) {
1132  if (!(res = pthread_rwlock_trywrlock(&t->lock))) {
1133  break;
1134  }
1135  _now = ast_tvnow();
1136  if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1137  break;
1138  }
1139  usleep(1);
1140  }
1141  } while (0);
1142 #endif
1143 
1144 #ifdef DEBUG_THREADS
1145  if (!res && lt) {
1146  ast_reentrancy_lock(lt);
1147  if (lt->reentrancy < AST_MAX_REENTRANCY) {
1148  lt->file[lt->reentrancy] = filename;
1149  lt->lineno[lt->reentrancy] = line;
1150  lt->func[lt->reentrancy] = func;
1151  lt->thread_id[lt->reentrancy] = pthread_self();
1152  lt->reentrancy++;
1153  }
1154  ast_reentrancy_unlock(lt);
1155  ast_mark_lock_acquired(t);
1156  } else if (lt) {
1157 #ifdef HAVE_BKTR
1158  if (lt->reentrancy) {
1159  ast_reentrancy_lock(lt);
1160  bt = &lt->backtrace[lt->reentrancy-1];
1161  ast_reentrancy_unlock(lt);
1162  } else {
1163  bt = NULL;
1164  }
1165 #endif
1166  ast_remove_lock_info(t, bt);
1167  }
1168  if (res) {
1169  log_mutex_error(canlog, "%s line %d (%s): Error obtaining read lock: %s\n",
1170  filename, line, func, strerror(res));
1171  DO_THREAD_CRASH;
1172  }
1173 #endif /* DEBUG_THREADS */
1174 
1175  return res;
1176 }
1177 
1178 int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
1179 {
1180  int res;
1181 
1182 #ifdef DEBUG_THREADS
1183  struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1184  struct ast_bt *bt = NULL;
1185 
1186  if (lt) {
1187 #ifdef HAVE_BKTR
1188  struct ast_bt tmp;
1189 
1190  /* The implementation of backtrace() may have its own locks.
1191  * Capture the backtrace outside of the reentrancy lock to
1192  * avoid deadlocks. See ASTERISK-22455. */
1193  ast_bt_get_addresses(&tmp);
1194 
1195  ast_reentrancy_lock(lt);
1196  if (lt->reentrancy < AST_MAX_REENTRANCY) {
1197  lt->backtrace[lt->reentrancy] = tmp;
1198  bt = &lt->backtrace[lt->reentrancy];
1199  }
1200  ast_reentrancy_unlock(lt);
1201 #endif
1202  ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
1203  }
1204 #endif /* DEBUG_THREADS */
1205 
1206  res = pthread_rwlock_tryrdlock(&t->lock);
1207 
1208 #ifdef DEBUG_THREADS
1209  if (!res && lt) {
1210  ast_reentrancy_lock(lt);
1211  if (lt->reentrancy < AST_MAX_REENTRANCY) {
1212  lt->file[lt->reentrancy] = filename;
1213  lt->lineno[lt->reentrancy] = line;
1214  lt->func[lt->reentrancy] = func;
1215  lt->thread_id[lt->reentrancy] = pthread_self();
1216  lt->reentrancy++;
1217  }
1218  ast_reentrancy_unlock(lt);
1219  ast_mark_lock_acquired(t);
1220  } else if (lt) {
1222  }
1223 #endif /* DEBUG_THREADS */
1224 
1225  return res;
1226 }
1227 
1228 int __ast_rwlock_trywrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
1229 {
1230  int res;
1231 
1232 #ifdef DEBUG_THREADS
1233  struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1234  struct ast_bt *bt = NULL;
1235 
1236  if (lt) {
1237 #ifdef HAVE_BKTR
1238  struct ast_bt tmp;
1239 
1240  /* The implementation of backtrace() may have its own locks.
1241  * Capture the backtrace outside of the reentrancy lock to
1242  * avoid deadlocks. See ASTERISK-22455. */
1243  ast_bt_get_addresses(&tmp);
1244 
1245  ast_reentrancy_lock(lt);
1246  if (lt->reentrancy < AST_MAX_REENTRANCY) {
1247  lt->backtrace[lt->reentrancy] = tmp;
1248  bt = &lt->backtrace[lt->reentrancy];
1249  }
1250  ast_reentrancy_unlock(lt);
1251 #endif
1252  ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1253  }
1254 #endif /* DEBUG_THREADS */
1255 
1256  res = pthread_rwlock_trywrlock(&t->lock);
1257 
1258 #ifdef DEBUG_THREADS
1259  if (!res && lt) {
1260  ast_reentrancy_lock(lt);
1261  if (lt->reentrancy < AST_MAX_REENTRANCY) {
1262  lt->file[lt->reentrancy] = filename;
1263  lt->lineno[lt->reentrancy] = line;
1264  lt->func[lt->reentrancy] = func;
1265  lt->thread_id[lt->reentrancy] = pthread_self();
1266  lt->reentrancy++;
1267  }
1268  ast_reentrancy_unlock(lt);
1269  ast_mark_lock_acquired(t);
1270  } else if (lt) {
1272  }
1273 #endif /* DEBUG_THREADS */
1274 
1275  return res;
1276 }
void ast_std_free(void *ptr)
Definition: astmm.c:1766
#define pthread_mutex_init
Definition: lock.h:626
int64_t ast_mark(int, int start1_stop0)
Definition: astman.c:103
int __ast_rwlock_init(int tracking, const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
Definition: lock.c:669
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition: lock.c:366
const char * file[AST_MAX_REENTRANCY]
Definition: lock.h:112
int __ast_rwlock_timedrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name, const struct timespec *abs_timeout)
Definition: lock.c:1014
#define pthread_cond_init
Definition: lock.h:628
#define __AST_RWLOCK_INIT_VALUE
Definition: lock.h:84
static int tmp()
Definition: bt_open.c:389
int __ast_rwlock_timedwrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name, const struct timespec *abs_timeout)
Definition: lock.c:1096
int __ast_rwlock_rdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:819
int __ast_cond_destroy(const char *filename, int lineno, const char *func, const char *cond_name, ast_cond_t *cond)
Definition: lock.c:510
int reentrancy
Definition: lock.h:114
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:917
#define NULL
Definition: resample.c:96
int lineno[AST_MAX_REENTRANCY]
Definition: lock.h:113
#define pthread_mutex_t
Definition: lock.h:620
struct ast_bt backtrace[AST_MAX_REENTRANCY]
Definition: lock.h:118
Utility functions.
int __ast_cond_broadcast(const char *filename, int lineno, const char *func, const char *cond_name, ast_cond_t *cond)
Definition: lock.c:504
pthread_cond_t ast_cond_t
Definition: lock.h:176
int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:1178
#define pthread_mutex_destroy
Definition: lock.h:627
int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition: lock.c:253
int __ast_cond_init(const char *filename, int lineno, const char *func, const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
Definition: lock.c:492
Lock tracking information.
Definition: lock.h:111
#define pthread_cond_wait
Definition: lock.h:632
#define pthread_mutex_lock
Definition: lock.h:623
#define pthread_cond_broadcast
Definition: lock.h:631
volatile unsigned int setup
Definition: lock.h:127
#define AST_PTHREADT_NULL
Definition: lock.h:66
unsigned int tracking
Definition: lock.h:125
ast_cond_t cond
Definition: app_meetme.c:1090
#define ROFFSET
Definition: lock.h:240
int ast_add_profile(const char *, uint64_t scale)
support for event profiling
Definition: astman.c:92
int __ast_rwlock_trywrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:1228
int __ast_cond_signal(const char *filename, int lineno, const char *func, const char *cond_name, ast_cond_t *cond)
Definition: lock.c:498
int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:748
const char * func[AST_MAX_REENTRANCY]
Definition: lock.h:115
static const char name[]
Definition: cdr_mysql.c:74
int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition: lock.c:175
void * ast_std_calloc(size_t nmemb, size_t size) attribute_malloc
Definition: astmm.c:1756
void * addresses[AST_MAX_BT_FRAMES]
Definition: backtrace.h:52
#define AST_MAX_REENTRANCY
Definition: lock.h:101
#define pthread_cond_signal
Definition: lock.h:630
int num_frames
Definition: backtrace.h:54
Structure for rwlock and tracking information.
Definition: lock.h:156
int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition: lock.c:421
pthread_t thread_id[AST_MAX_REENTRANCY]
Definition: lock.h:116
int __ast_cond_timedwait(const char *filename, int lineno, const char *func, const char *cond_name, const char *mutex_name, ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
Definition: lock.c:604
int __ast_cond_wait(const char *filename, int lineno, const char *func, const char *cond_name, const char *mutex_name, ast_cond_t *cond, ast_mutex_t *t)
Definition: lock.c:539
pthread_mutex_t mutex
Definition: lock.h:136
pthread_mutex_t reentr_mutex
Definition: lock.h:120
#define pthread_mutex_unlock
Definition: lock.h:624
void ast_mark_lock_failed(void *lock_addr)
Definition: extconf.c:2314
int __ast_pthread_mutex_init(int tracking, const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition: lock.c:144
pthread_rwlock_t lock
Definition: lock.h:157
#define pthread_cond_timedwait
Definition: lock.h:633
#define pthread_mutex_trylock
Definition: lock.h:625
#define pthread_cond_destroy
Definition: lock.h:629
int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
Definition: lock.c:701
#define AST_MUTEX_KIND
Definition: lock.h:77
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:518
Structure for mutex and tracking information.
Definition: lock.h:135
#define ast_bt_get_addresses(bt)
Definition: backtrace.h:38