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