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