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