aboutsummaryrefslogtreecommitdiffstats
path: root/include/asterisk/lock.h
blob: 2b6182eba954bdef5bee4b1fcd2a789e5e943f65 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/*
 * Asterisk -- A telephony toolkit for Linux.
 *
 * General Asterisk channel definitions.
 * 
 * Copyright (C) 1999, Mark Spencer
 *
 * Mark Spencer <markster@linux-support.net>
 *
 * This program is free software, distributed under the terms of
 * the GNU General Public License
 */

#ifndef _ASTERISK_LOCK_H
#define _ASTERISK_LOCK_H

#include <pthread.h>

#ifdef DEBUG_THREADS
#ifdef THREAD_CRASH
#define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
#endif


#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>

// #define AST_MUTEX_INITIALIZER      PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
// #define AST_MUTEX_KIND             PTHREAD_MUTEX_RECURSIVE_NP
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
#define AST_MUTEX_INITIALIZER         { PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, NULL, 0, NULL, 0 }
#else
#ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
#define AST_MUTEX_INITIALIZER         { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, NULL, 0, NULL, 0 }
#else
#define AST_MUTEX_INITIALIZER         { PTHREAD_MUTEX_INITIALIZER, NULL, 0, NULL, 0 }
#endif
#endif
#ifdef PTHREAD_MUTEX_ERRORCHECK_NP
#define AST_MUTEX_KIND                PTHREAD_MUTEX_ERRORCHECK_NP
#else
#define AST_MUTEX_KIND                PTHREAD_MUTEX_ERRORCHECK
#endif

struct ast_mutex_info {
	pthread_mutex_t mutex;
	char *file;
	int lineno;
	char *func;
	pthread_t thread;
};

typedef struct ast_mutex_info ast_mutex_t;

static inline int ast_mutex_init(ast_mutex_t *t) {
	static pthread_mutexattr_t  attr;
	static int  init = 1;
	int res;
	extern int  pthread_mutexattr_setkind_np(pthread_mutexattr_t *, int);

	if (init) {
		pthread_mutexattr_init(&attr);
		pthread_mutexattr_setkind_np(&attr, AST_MUTEX_KIND);
		init = 0;
	}
	res = pthread_mutex_init(&t->mutex, &attr);
	t->file = NULL;
	t->lineno = 0;
	t->func = 0;
	t->thread  = 0;
	return res;
}

static inline int ast_pthread_mutex_init(ast_mutex_t *t, pthread_mutexattr_t *attr) 
{
	int res;
	res = pthread_mutex_init(&t->mutex, attr);
	t->file = NULL;
	t->lineno = 0;
	t->func = 0;
	t->thread  = 0;
	return res;
}

static inline int __ast_pthread_mutex_lock(char *filename, int lineno, char *func, ast_mutex_t *t) {
	int res;
	res = pthread_mutex_lock(&t->mutex);
	if (!res) {
		t->file = filename;
		t->lineno = lineno;
		t->func = func;
		t->thread = pthread_self();
	} else {
		fprintf(stderr, "%s line %d (%s): Error obtaining mutex: %s\n",
			filename, lineno, func, strerror(errno));
#ifdef THREAD_CRASH
		DO_THREAD_CRASH;
#endif
	}
	return res;
}

#define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a)

static inline int __ast_pthread_mutex_trylock(char *filename, int lineno, char *func, ast_mutex_t *t) {
	int res;
	res = pthread_mutex_trylock(&t->mutex);
	if (!res) {
		t->file = filename;
		t->lineno = lineno;
		t->func = func;
		t->thread = pthread_self();
	}
	return res;
}

#define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a)

static inline int __ast_pthread_mutex_unlock(char *filename, int lineno, char *func, ast_mutex_t *t) {
	int res;
	/* Assumes lock is actually held */
	t->file = NULL;
	t->lineno = 0;
	t->func = NULL;
	t->thread = 0;
	res = pthread_mutex_unlock(&t->mutex);
	if (res) {
		fprintf(stderr, "%s line %d (%s): Error releasing mutex: %s\n", 
				filename, lineno, func, strerror(res));
#ifdef THREAD_CRASH
		DO_THREAD_CRASH;
#endif
	}
	return res;
}

#define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a)

static inline int __ast_pthread_mutex_destroy(char *filename, int lineno, char *func, ast_mutex_t *t)
{
	int res;
	t->file = NULL;
	t->lineno = 0;
	t->func = NULL;
	t->thread = 0;
	res = pthread_mutex_destroy(&t->mutex);
	if (res) 
		fprintf(stderr, "%s line %d (%s): Error destroying mutex: %s\n",
				filename, lineno, func, strerror(res));
	return res;
}

#define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, a)

#define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
#define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
#define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
#define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
#define pthread_mutex_init use_ast_pthread_mutex_init_instead_of_pthread_mutex_init
#define pthread_mutex_destroy use_ast_pthread_mutex_destroy_instead_of_pthread_mutex_destroy

#else

#define AST_MUTEX_INITIALIZER      PTHREAD_MUTEX_INITIALIZER
#ifdef PTHREAD_MUTEX_FAST_NP
#define AST_MUTEX_KIND             PTHREAD_MUTEX_FAST_NP
#else
#define AST_MUTEX_KIND             PTHREAD_NORMAL
#endif

typedef pthread_mutex_t ast_mutex_t;

#define ast_mutex_lock(t) pthread_mutex_lock(t)
#define ast_mutex_unlock(t) pthread_mutex_unlock(t)
#define ast_mutex_trylock(t) pthread_mutex_trylock(t)
#define ast_mutex_init(t) pthread_mutex_init(t, NULL)
#define ast_pthread_mutex_init(t,a) pthread_mutex_init(t,a)
#define ast_mutex_destroy(t) pthread_mutex_destroy(t)

#endif


#endif