Asterisk - The Open Source Telephony Project  GIT-master-44aef04
Functions
lock.c File Reference

General Asterisk locking. More...

#include "asterisk.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"

Go to the source code of this file.

Functions

int __ast_cond_broadcast (const char *filename, int lineno, const char *func, const char *cond_name, ast_cond_t *cond)
 
int __ast_cond_destroy (const char *filename, int lineno, const char *func, const char *cond_name, ast_cond_t *cond)
 
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)
 
int __ast_cond_signal (const char *filename, int lineno, const char *func, const char *cond_name, ast_cond_t *cond)
 
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)
 
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)
 
int __ast_pthread_mutex_destroy (const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
 
int __ast_pthread_mutex_init (int tracking, const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
 
int __ast_pthread_mutex_lock (const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
 
int __ast_pthread_mutex_trylock (const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
 
int __ast_pthread_mutex_unlock (const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
 
int __ast_rwlock_destroy (const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
 
int __ast_rwlock_init (int tracking, const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
 
int __ast_rwlock_rdlock (const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
 
int __ast_rwlock_timedrdlock (const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name, const struct timespec *abs_timeout)
 
int __ast_rwlock_timedwrlock (const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name, const struct timespec *abs_timeout)
 
int __ast_rwlock_tryrdlock (const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
 
int __ast_rwlock_trywrlock (const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
 
int __ast_rwlock_unlock (const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
 
int __ast_rwlock_wrlock (const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
 

Detailed Description

General Asterisk locking.

Definition in file lock.c.

Function Documentation

◆ __ast_cond_broadcast()

int __ast_cond_broadcast ( const char *  filename,
int  lineno,
const char *  func,
const char *  cond_name,
ast_cond_t cond 
)

Definition at line 504 of file lock.c.

References pthread_cond_broadcast.

506 {
508 }
#define pthread_cond_broadcast
Definition: lock.h:631
ast_cond_t cond
Definition: app_meetme.c:1090

◆ __ast_cond_destroy()

int __ast_cond_destroy ( const char *  filename,
int  lineno,
const char *  func,
const char *  cond_name,
ast_cond_t cond 
)

◆ __ast_cond_init()

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 at line 492 of file lock.c.

References pthread_cond_init.

494 {
495  return pthread_cond_init(cond, cond_attr);
496 }
#define pthread_cond_init
Definition: lock.h:628
ast_cond_t cond
Definition: app_meetme.c:1090

◆ __ast_cond_signal()

int __ast_cond_signal ( const char *  filename,
int  lineno,
const char *  func,
const char *  cond_name,
ast_cond_t cond 
)

Definition at line 498 of file lock.c.

References pthread_cond_signal.

500 {
501  return pthread_cond_signal(cond);
502 }
ast_cond_t cond
Definition: app_meetme.c:1090
#define pthread_cond_signal
Definition: lock.h:630

◆ __ast_cond_timedwait()

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 at line 604 of file lock.c.

References ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_mutex_info::mutex, NULL, pthread_cond_timedwait, pthread_mutex_t, ast_lock_track::reentrancy, ROFFSET, and ast_lock_track::thread_id.

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 }
const char * file[AST_MAX_REENTRANCY]
Definition: lock.h:112
int reentrancy
Definition: lock.h:114
#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
Lock tracking information.
Definition: lock.h:111
ast_cond_t cond
Definition: app_meetme.c:1090
#define ROFFSET
Definition: lock.h:240
const char * func[AST_MAX_REENTRANCY]
Definition: lock.h:115
pthread_t thread_id[AST_MAX_REENTRANCY]
Definition: lock.h:116
pthread_mutex_t mutex
Definition: lock.h:136
#define pthread_cond_timedwait
Definition: lock.h:633

◆ __ast_cond_wait()

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 at line 539 of file lock.c.

References ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_mutex_info::mutex, NULL, pthread_cond_wait, pthread_mutex_t, ast_lock_track::reentrancy, ROFFSET, and ast_lock_track::thread_id.

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 }
const char * file[AST_MAX_REENTRANCY]
Definition: lock.h:112
int reentrancy
Definition: lock.h:114
#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
Lock tracking information.
Definition: lock.h:111
#define pthread_cond_wait
Definition: lock.h:632
ast_cond_t cond
Definition: app_meetme.c:1090
#define ROFFSET
Definition: lock.h:240
const char * func[AST_MAX_REENTRANCY]
Definition: lock.h:115
pthread_t thread_id[AST_MAX_REENTRANCY]
Definition: lock.h:116
pthread_mutex_t mutex
Definition: lock.h:136

◆ __ast_pthread_mutex_destroy()

int __ast_pthread_mutex_destroy ( const char *  filename,
int  lineno,
const char *  func,
const char *  mutex_name,
ast_mutex_t t 
)

Definition at line 175 of file lock.c.

References ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_mutex_info::mutex, pthread_mutex_destroy, pthread_mutex_t, pthread_mutex_trylock, pthread_mutex_unlock, ast_lock_track::reentrancy, ROFFSET, and ast_lock_track::thread_id.

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 }
const char * file[AST_MAX_REENTRANCY]
Definition: lock.h:112
int reentrancy
Definition: lock.h:114
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
#define pthread_mutex_destroy
Definition: lock.h:627
Lock tracking information.
Definition: lock.h:111
#define ROFFSET
Definition: lock.h:240
const char * func[AST_MAX_REENTRANCY]
Definition: lock.h:115
pthread_t thread_id[AST_MAX_REENTRANCY]
Definition: lock.h:116
pthread_mutex_t mutex
Definition: lock.h:136
#define pthread_mutex_unlock
Definition: lock.h:624
#define pthread_mutex_trylock
Definition: lock.h:625

◆ __ast_pthread_mutex_init()

int __ast_pthread_mutex_init ( int  tracking,
const char *  filename,
int  lineno,
const char *  func,
const char *  mutex_name,
ast_mutex_t t 
)

Definition at line 144 of file lock.c.

References AST_MUTEX_KIND, ast_mutex_info::mutex, NULL, pthread_mutex_init, and pthread_mutex_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 }
#define pthread_mutex_init
Definition: lock.h:626
#define NULL
Definition: resample.c:96
int lineno[AST_MAX_REENTRANCY]
Definition: lock.h:113
#define pthread_mutex_t
Definition: lock.h:620
const char * func[AST_MAX_REENTRANCY]
Definition: lock.h:115
pthread_mutex_t mutex
Definition: lock.h:136
#define AST_MUTEX_KIND
Definition: lock.h:77

◆ __ast_pthread_mutex_lock()

int __ast_pthread_mutex_lock ( const char *  filename,
int  lineno,
const char *  func,
const char *  mutex_name,
ast_mutex_t t 
)

Definition at line 253 of file lock.c.

References ast_bt_get_addresses, ast_mark(), AST_MAX_REENTRANCY, AST_MUTEX, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_mutex_info::mutex, NULL, pthread_mutex_lock, pthread_mutex_trylock, ast_lock_track::reentrancy, ROFFSET, ast_lock_track::thread_id, and tmp().

Referenced by __ao2_lock().

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. */
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 }
int64_t ast_mark(int, int start1_stop0)
Definition: astman.c:103
const char * file[AST_MAX_REENTRANCY]
Definition: lock.h:112
static int tmp()
Definition: bt_open.c:389
int reentrancy
Definition: lock.h:114
#define NULL
Definition: resample.c:96
int lineno[AST_MAX_REENTRANCY]
Definition: lock.h:113
struct ast_bt backtrace[AST_MAX_REENTRANCY]
Definition: lock.h:118
Lock tracking information.
Definition: lock.h:111
#define pthread_mutex_lock
Definition: lock.h:623
#define ROFFSET
Definition: lock.h:240
const char * func[AST_MAX_REENTRANCY]
Definition: lock.h:115
#define AST_MAX_REENTRANCY
Definition: lock.h:101
pthread_t thread_id[AST_MAX_REENTRANCY]
Definition: lock.h:116
pthread_mutex_t mutex
Definition: lock.h:136
#define pthread_mutex_trylock
Definition: lock.h:625
#define ast_bt_get_addresses(bt)
Definition: backtrace.h:38

◆ __ast_pthread_mutex_trylock()

int __ast_pthread_mutex_trylock ( const char *  filename,
int  lineno,
const char *  func,
const char *  mutex_name,
ast_mutex_t t 
)

Definition at line 366 of file lock.c.

References ast_bt_get_addresses, ast_mark_lock_failed(), AST_MAX_REENTRANCY, AST_MUTEX, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_mutex_info::mutex, NULL, pthread_mutex_trylock, ast_lock_track::reentrancy, ast_lock_track::thread_id, and tmp().

Referenced by __ao2_trylock().

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. */
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 }
const char * file[AST_MAX_REENTRANCY]
Definition: lock.h:112
static int tmp()
Definition: bt_open.c:389
int reentrancy
Definition: lock.h:114
#define NULL
Definition: resample.c:96
int lineno[AST_MAX_REENTRANCY]
Definition: lock.h:113
struct ast_bt backtrace[AST_MAX_REENTRANCY]
Definition: lock.h:118
Lock tracking information.
Definition: lock.h:111
const char * func[AST_MAX_REENTRANCY]
Definition: lock.h:115
#define AST_MAX_REENTRANCY
Definition: lock.h:101
pthread_t thread_id[AST_MAX_REENTRANCY]
Definition: lock.h:116
pthread_mutex_t mutex
Definition: lock.h:136
void ast_mark_lock_failed(void *lock_addr)
Definition: extconf.c:2314
#define pthread_mutex_trylock
Definition: lock.h:625
#define ast_bt_get_addresses(bt)
Definition: backtrace.h:38

◆ __ast_pthread_mutex_unlock()

int __ast_pthread_mutex_unlock ( const char *  filename,
int  lineno,
const char *  func,
const char *  mutex_name,
ast_mutex_t t 
)

Definition at line 421 of file lock.c.

References AST_MAX_REENTRANCY, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_mutex_info::mutex, NULL, pthread_mutex_t, pthread_mutex_unlock, ast_lock_track::reentrancy, ROFFSET, and ast_lock_track::thread_id.

Referenced by __ao2_unlock().

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 }
const char * file[AST_MAX_REENTRANCY]
Definition: lock.h:112
int reentrancy
Definition: lock.h:114
#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
Lock tracking information.
Definition: lock.h:111
#define ROFFSET
Definition: lock.h:240
const char * func[AST_MAX_REENTRANCY]
Definition: lock.h:115
#define AST_MAX_REENTRANCY
Definition: lock.h:101
pthread_t thread_id[AST_MAX_REENTRANCY]
Definition: lock.h:116
pthread_mutex_t mutex
Definition: lock.h:136
#define pthread_mutex_unlock
Definition: lock.h:624

◆ __ast_rwlock_destroy()

int __ast_rwlock_destroy ( const char *  filename,
int  lineno,
const char *  func,
const char *  rwlock_name,
ast_rwlock_t t 
)

Definition at line 701 of file lock.c.

References __AST_RWLOCK_INIT_VALUE, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, ast_lock_track::reentrancy, and ast_lock_track::thread_id.

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 }
const char * file[AST_MAX_REENTRANCY]
Definition: lock.h:112
#define __AST_RWLOCK_INIT_VALUE
Definition: lock.h:84
int reentrancy
Definition: lock.h:114
int lineno[AST_MAX_REENTRANCY]
Definition: lock.h:113
struct ast_bt backtrace[AST_MAX_REENTRANCY]
Definition: lock.h:118
Lock tracking information.
Definition: lock.h:111
const char * func[AST_MAX_REENTRANCY]
Definition: lock.h:115
pthread_t thread_id[AST_MAX_REENTRANCY]
Definition: lock.h:116
pthread_rwlock_t lock
Definition: lock.h:157

◆ __ast_rwlock_init()

int __ast_rwlock_init ( int  tracking,
const char *  filename,
int  lineno,
const char *  func,
const char *  rwlock_name,
ast_rwlock_t t 
)

Definition at line 669 of file lock.c.

References __AST_RWLOCK_INIT_VALUE, ast_rwlock_info::lock, and NULL.

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 }
#define __AST_RWLOCK_INIT_VALUE
Definition: lock.h:84
#define NULL
Definition: resample.c:96
int lineno[AST_MAX_REENTRANCY]
Definition: lock.h:113
const char * func[AST_MAX_REENTRANCY]
Definition: lock.h:115
pthread_rwlock_t lock
Definition: lock.h:157

◆ __ast_rwlock_rdlock()

int __ast_rwlock_rdlock ( const char *  filename,
int  line,
const char *  func,
ast_rwlock_t t,
const char *  name 
)

Definition at line 819 of file lock.c.

References ast_bt_get_addresses, AST_MAX_REENTRANCY, AST_RDLOCK, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, NULL, ast_lock_track::reentrancy, ast_lock_track::thread_id, and tmp().

Referenced by __ao2_global_obj_ref(), __ao2_lock(), and __ast_heap_rdlock().

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. */
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 }
const char * file[AST_MAX_REENTRANCY]
Definition: lock.h:112
static int tmp()
Definition: bt_open.c:389
int reentrancy
Definition: lock.h:114
#define NULL
Definition: resample.c:96
int lineno[AST_MAX_REENTRANCY]
Definition: lock.h:113
struct ast_bt backtrace[AST_MAX_REENTRANCY]
Definition: lock.h:118
Lock tracking information.
Definition: lock.h:111
const char * func[AST_MAX_REENTRANCY]
Definition: lock.h:115
static const char name[]
Definition: cdr_mysql.c:74
#define AST_MAX_REENTRANCY
Definition: lock.h:101
pthread_t thread_id[AST_MAX_REENTRANCY]
Definition: lock.h:116
pthread_rwlock_t lock
Definition: lock.h:157
#define ast_bt_get_addresses(bt)
Definition: backtrace.h:38

◆ __ast_rwlock_timedrdlock()

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 at line 1014 of file lock.c.

References ast_bt_get_addresses, AST_MAX_REENTRANCY, ast_tvnow(), AST_WRLOCK, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, NULL, ast_lock_track::reentrancy, ast_lock_track::thread_id, and tmp().

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. */
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 }
const char * file[AST_MAX_REENTRANCY]
Definition: lock.h:112
static int tmp()
Definition: bt_open.c:389
int reentrancy
Definition: lock.h:114
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#define NULL
Definition: resample.c:96
int lineno[AST_MAX_REENTRANCY]
Definition: lock.h:113
struct ast_bt backtrace[AST_MAX_REENTRANCY]
Definition: lock.h:118
Lock tracking information.
Definition: lock.h:111
const char * func[AST_MAX_REENTRANCY]
Definition: lock.h:115
static const char name[]
Definition: cdr_mysql.c:74
#define AST_MAX_REENTRANCY
Definition: lock.h:101
pthread_t thread_id[AST_MAX_REENTRANCY]
Definition: lock.h:116
pthread_rwlock_t lock
Definition: lock.h:157
#define ast_bt_get_addresses(bt)
Definition: backtrace.h:38

◆ __ast_rwlock_timedwrlock()

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 at line 1096 of file lock.c.

References ast_bt_get_addresses, AST_MAX_REENTRANCY, ast_tvnow(), AST_WRLOCK, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, NULL, ast_lock_track::reentrancy, ast_lock_track::thread_id, and tmp().

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. */
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 }
const char * file[AST_MAX_REENTRANCY]
Definition: lock.h:112
static int tmp()
Definition: bt_open.c:389
int reentrancy
Definition: lock.h:114
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#define NULL
Definition: resample.c:96
int lineno[AST_MAX_REENTRANCY]
Definition: lock.h:113
struct ast_bt backtrace[AST_MAX_REENTRANCY]
Definition: lock.h:118
Lock tracking information.
Definition: lock.h:111
const char * func[AST_MAX_REENTRANCY]
Definition: lock.h:115
static const char name[]
Definition: cdr_mysql.c:74
#define AST_MAX_REENTRANCY
Definition: lock.h:101
pthread_t thread_id[AST_MAX_REENTRANCY]
Definition: lock.h:116
pthread_rwlock_t lock
Definition: lock.h:157
#define ast_bt_get_addresses(bt)
Definition: backtrace.h:38

◆ __ast_rwlock_tryrdlock()

int __ast_rwlock_tryrdlock ( const char *  filename,
int  line,
const char *  func,
ast_rwlock_t t,
const char *  name 
)

Definition at line 1178 of file lock.c.

References ast_bt_get_addresses, ast_mark_lock_failed(), AST_MAX_REENTRANCY, AST_RDLOCK, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, NULL, ast_lock_track::reentrancy, ast_lock_track::thread_id, and tmp().

Referenced by __ao2_trylock().

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. */
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 }
const char * file[AST_MAX_REENTRANCY]
Definition: lock.h:112
static int tmp()
Definition: bt_open.c:389
int reentrancy
Definition: lock.h:114
#define NULL
Definition: resample.c:96
int lineno[AST_MAX_REENTRANCY]
Definition: lock.h:113
struct ast_bt backtrace[AST_MAX_REENTRANCY]
Definition: lock.h:118
Lock tracking information.
Definition: lock.h:111
const char * func[AST_MAX_REENTRANCY]
Definition: lock.h:115
static const char name[]
Definition: cdr_mysql.c:74
#define AST_MAX_REENTRANCY
Definition: lock.h:101
pthread_t thread_id[AST_MAX_REENTRANCY]
Definition: lock.h:116
void ast_mark_lock_failed(void *lock_addr)
Definition: extconf.c:2314
pthread_rwlock_t lock
Definition: lock.h:157
#define ast_bt_get_addresses(bt)
Definition: backtrace.h:38

◆ __ast_rwlock_trywrlock()

int __ast_rwlock_trywrlock ( const char *  filename,
int  line,
const char *  func,
ast_rwlock_t t,
const char *  name 
)

Definition at line 1228 of file lock.c.

References ast_bt_get_addresses, ast_mark_lock_failed(), AST_MAX_REENTRANCY, AST_WRLOCK, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, NULL, ast_lock_track::reentrancy, ast_lock_track::thread_id, and tmp().

Referenced by __ao2_trylock().

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. */
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 }
const char * file[AST_MAX_REENTRANCY]
Definition: lock.h:112
static int tmp()
Definition: bt_open.c:389
int reentrancy
Definition: lock.h:114
#define NULL
Definition: resample.c:96
int lineno[AST_MAX_REENTRANCY]
Definition: lock.h:113
struct ast_bt backtrace[AST_MAX_REENTRANCY]
Definition: lock.h:118
Lock tracking information.
Definition: lock.h:111
const char * func[AST_MAX_REENTRANCY]
Definition: lock.h:115
static const char name[]
Definition: cdr_mysql.c:74
#define AST_MAX_REENTRANCY
Definition: lock.h:101
pthread_t thread_id[AST_MAX_REENTRANCY]
Definition: lock.h:116
void ast_mark_lock_failed(void *lock_addr)
Definition: extconf.c:2314
pthread_rwlock_t lock
Definition: lock.h:157
#define ast_bt_get_addresses(bt)
Definition: backtrace.h:38

◆ __ast_rwlock_unlock()

int __ast_rwlock_unlock ( const char *  filename,
int  line,
const char *  func,
ast_rwlock_t t,
const char *  name 
)

Definition at line 748 of file lock.c.

References __AST_RWLOCK_INIT_VALUE, AST_PTHREADT_NULL, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, NULL, ast_lock_track::reentrancy, and ast_lock_track::thread_id.

Referenced by __ao2_global_obj_ref(), __ao2_global_obj_replace(), __ao2_unlock(), and __ast_heap_unlock().

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 }
const char * file[AST_MAX_REENTRANCY]
Definition: lock.h:112
#define __AST_RWLOCK_INIT_VALUE
Definition: lock.h:84
int reentrancy
Definition: lock.h:114
#define NULL
Definition: resample.c:96
int lineno[AST_MAX_REENTRANCY]
Definition: lock.h:113
struct ast_bt backtrace[AST_MAX_REENTRANCY]
Definition: lock.h:118
Lock tracking information.
Definition: lock.h:111
#define AST_PTHREADT_NULL
Definition: lock.h:66
const char * func[AST_MAX_REENTRANCY]
Definition: lock.h:115
static const char name[]
Definition: cdr_mysql.c:74
pthread_t thread_id[AST_MAX_REENTRANCY]
Definition: lock.h:116
pthread_rwlock_t lock
Definition: lock.h:157

◆ __ast_rwlock_wrlock()

int __ast_rwlock_wrlock ( const char *  filename,
int  line,
const char *  func,
ast_rwlock_t t,
const char *  name 
)

Definition at line 917 of file lock.c.

References ast_bt_get_addresses, AST_MAX_REENTRANCY, AST_WRLOCK, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, NULL, ast_lock_track::reentrancy, ast_lock_track::thread_id, and tmp().

Referenced by __ao2_global_obj_replace(), __ao2_lock(), and __ast_heap_wrlock().

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. */
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 }
const char * file[AST_MAX_REENTRANCY]
Definition: lock.h:112
static int tmp()
Definition: bt_open.c:389
int reentrancy
Definition: lock.h:114
#define NULL
Definition: resample.c:96
int lineno[AST_MAX_REENTRANCY]
Definition: lock.h:113
struct ast_bt backtrace[AST_MAX_REENTRANCY]
Definition: lock.h:118
Lock tracking information.
Definition: lock.h:111
const char * func[AST_MAX_REENTRANCY]
Definition: lock.h:115
static const char name[]
Definition: cdr_mysql.c:74
#define AST_MAX_REENTRANCY
Definition: lock.h:101
pthread_t thread_id[AST_MAX_REENTRANCY]
Definition: lock.h:116
pthread_rwlock_t lock
Definition: lock.h:157
#define ast_bt_get_addresses(bt)
Definition: backtrace.h:38