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