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