Fix potential segfault, add support for MacOS X locks
[asterisk/asterisk.git] / include / asterisk / lock.h
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * General Asterisk channel definitions.
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #ifndef _ASTERISK_LOCK_H
15 #define _ASTERISK_LOCK_H
16
17 #include <pthread.h>
18 #include <netdb.h>
19
20 #define AST_PTHREADT_NULL (pthread_t) -1
21 #define AST_PTHREADT_STOP (pthread_t) -2
22
23 #ifdef __APPLE__
24 /* Provide the Linux initializers for MacOS X */
25 #define PTHREAD_MUTEX_RECURSIVE_NP                                      PTHREAD_MUTEX_RECURSIVE
26 #define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP           { 0x4d555458, \
27                                                                                                            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
28                                                                                                                  0x20 } }
29 #endif
30
31 #ifdef DEBUG_THREADS
32
33 #ifdef THREAD_CRASH
34 #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
35 #endif
36
37 #include <errno.h>
38 #include <string.h>
39 #include <stdio.h>
40 #include <unistd.h>
41
42 /* From now on, Asterisk REQUIRES Recursive (not error checking) mutexes
43    and will not run without them. */
44
45 #define AST_MUTEX_INITIALIZER      { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, NULL, 0, NULL, 0 }
46 #define AST_MUTEX_KIND             PTHREAD_MUTEX_RECURSIVE_NP
47
48 struct ast_mutex_info {
49         pthread_mutex_t mutex;
50         char *file;
51         int lineno;
52         char *func;
53         pthread_t thread;
54 };
55
56 typedef struct ast_mutex_info ast_mutex_t;
57
58 static inline int ast_mutex_init(ast_mutex_t *t) {
59         static pthread_mutexattr_t  attr;
60         static int  init = 1;
61         int res;
62         extern int  pthread_mutexattr_setkind_np(pthread_mutexattr_t *, int);
63
64         if (init) {
65                 pthread_mutexattr_init(&attr);
66                 pthread_mutexattr_setkind_np(&attr, AST_MUTEX_KIND);
67                 init = 0;
68         }
69         res = pthread_mutex_init(&t->mutex, &attr);
70         t->file = NULL;
71         t->lineno = 0;
72         t->func = 0;
73         t->thread  = 0;
74         return res;
75 }
76
77 static inline int ast_pthread_mutex_init(ast_mutex_t *t, pthread_mutexattr_t *attr) 
78 {
79         int res;
80         res = pthread_mutex_init(&t->mutex, attr);
81         t->file = NULL;
82         t->lineno = 0;
83         t->func = 0;
84         t->thread  = 0;
85         return res;
86 }
87
88 static inline int __ast_pthread_mutex_lock(char *filename, int lineno, char *func, ast_mutex_t *t) {
89         int res;
90         res = pthread_mutex_lock(&t->mutex);
91         if (!res) {
92                 t->file = filename;
93                 t->lineno = lineno;
94                 t->func = func;
95                 t->thread = pthread_self();
96         } else {
97                 fprintf(stderr, "%s line %d (%s): Error obtaining mutex: %s\n",
98                         filename, lineno, func, strerror(errno));
99 #ifdef THREAD_CRASH
100                 DO_THREAD_CRASH;
101 #endif
102         }
103         return res;
104 }
105
106 #define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a)
107
108 static inline int __ast_pthread_mutex_trylock(char *filename, int lineno, char *func, ast_mutex_t *t) {
109         int res;
110         res = pthread_mutex_trylock(&t->mutex);
111         if (!res) {
112                 t->file = filename;
113                 t->lineno = lineno;
114                 t->func = func;
115                 t->thread = pthread_self();
116         }
117         return res;
118 }
119
120 #define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a)
121
122 static inline int __ast_pthread_mutex_unlock(char *filename, int lineno, char *func, ast_mutex_t *t) {
123         int res;
124         /* Assumes lock is actually held */
125         t->file = NULL;
126         t->lineno = 0;
127         t->func = NULL;
128         t->thread = 0;
129         res = pthread_mutex_unlock(&t->mutex);
130         if (res) {
131                 fprintf(stderr, "%s line %d (%s): Error releasing mutex: %s\n", 
132                                 filename, lineno, func, strerror(res));
133 #ifdef THREAD_CRASH
134                 DO_THREAD_CRASH;
135 #endif
136         }
137         return res;
138 }
139
140 #define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a)
141
142 static inline int __ast_pthread_mutex_destroy(char *filename, int lineno, char *func, ast_mutex_t *t)
143 {
144         int res;
145         t->file = NULL;
146         t->lineno = 0;
147         t->func = NULL;
148         t->thread = 0;
149         res = pthread_mutex_destroy(&t->mutex);
150         if (res) 
151                 fprintf(stderr, "%s line %d (%s): Error destroying mutex: %s\n",
152                                 filename, lineno, func, strerror(res));
153         return res;
154 }
155
156 #define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, a)
157
158 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
159 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
160 #define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
161 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
162 #define pthread_mutex_init use_ast_pthread_mutex_init_instead_of_pthread_mutex_init
163 #define pthread_mutex_destroy use_ast_pthread_mutex_destroy_instead_of_pthread_mutex_destroy
164
165 #else /* DEBUG_THREADS */
166
167 /* From now on, Asterisk REQUIRES Recursive (not error checking) mutexes
168    and will not run without them. */
169 #define AST_MUTEX_INITIALIZER      PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
170 #define AST_MUTEX_KIND             PTHREAD_MUTEX_RECURSIVE_NP
171
172 typedef pthread_mutex_t ast_mutex_t;
173
174 #define ast_mutex_lock(t) pthread_mutex_lock(t)
175 #define ast_mutex_unlock(t) pthread_mutex_unlock(t)
176 #define ast_mutex_trylock(t) pthread_mutex_trylock(t)
177 static inline int ast_mutex_init(ast_mutex_t *t)
178 {
179         pthread_mutexattr_t attr;
180         pthread_mutexattr_init(&attr);
181         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
182         return pthread_mutex_init(t, &attr);
183 }
184 #define ast_pthread_mutex_init(t,a) pthread_mutex_init(t,a)
185 #define ast_mutex_destroy(t) pthread_mutex_destroy(t)
186
187 #endif /* DEBUG_THREADS */
188
189 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
190
191 #endif