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