Wed Jan 8 2020 09:49:48

Asterisk developer's documentation


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