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