Separated the public interfaces of the threading primitives.
[strongswan.git] / src / libstrongswan / threading / mutex.c
1 /*
2 * Copyright (C) 2008-2009 Tobias Brunner
3 * Copyright (C) 2008 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #define _GNU_SOURCE
18 #include <pthread.h>
19
20 #include <library.h>
21 #include <debug.h>
22
23 #include "mutex.h"
24 #include "lock_profiler.h"
25
26 typedef struct private_mutex_t private_mutex_t;
27 typedef struct private_r_mutex_t private_r_mutex_t;
28
29 /**
30 * private data of mutex
31 */
32 struct private_mutex_t {
33
34 /**
35 * public functions
36 */
37 mutex_t public;
38
39 /**
40 * wrapped pthread mutex
41 */
42 pthread_mutex_t mutex;
43
44 /**
45 * is this a recursiv emutex, implementing private_r_mutex_t?
46 */
47 bool recursive;
48
49 /**
50 * profiling info, if enabled
51 */
52 lock_profile_t profile;
53 };
54
55 /**
56 * private data of mutex, extended by recursive locking information
57 */
58 struct private_r_mutex_t {
59
60 /**
61 * Extends private_mutex_t
62 */
63 private_mutex_t generic;
64
65 /**
66 * thread which currently owns mutex
67 */
68 pthread_t thread;
69
70 /**
71 * times we have locked the lock, stored per thread
72 */
73 pthread_key_t times;
74 };
75
76 /**
77 * Implementation of mutex_t.lock.
78 */
79 static void lock(private_mutex_t *this)
80 {
81 int err;
82
83 profiler_start(&this->profile);
84 err = pthread_mutex_lock(&this->mutex);
85 if (err)
86 {
87 DBG1("!!! MUTEX LOCK ERROR: %s !!!", strerror(err));
88 }
89 profiler_end(&this->profile);
90 }
91
92 /**
93 * Implementation of mutex_t.unlock.
94 */
95 static void unlock(private_mutex_t *this)
96 {
97 int err;
98
99 err = pthread_mutex_unlock(&this->mutex);
100 if (err)
101 {
102 DBG1("!!! MUTEX UNLOCK ERROR: %s !!!", strerror(err));
103 }
104 }
105
106 /**
107 * Implementation of mutex_t.lock.
108 */
109 static void lock_r(private_r_mutex_t *this)
110 {
111 pthread_t self = pthread_self();
112
113 if (this->thread == self)
114 {
115 uintptr_t times;
116
117 /* times++ */
118 times = (uintptr_t)pthread_getspecific(this->times);
119 pthread_setspecific(this->times, (void*)times + 1);
120 }
121 else
122 {
123 lock(&this->generic);
124 this->thread = self;
125 /* times = 1 */
126 pthread_setspecific(this->times, (void*)1);
127 }
128 }
129
130 /**
131 * Implementation of mutex_t.unlock.
132 */
133 static void unlock_r(private_r_mutex_t *this)
134 {
135 uintptr_t times;
136
137 /* times-- */
138 times = (uintptr_t)pthread_getspecific(this->times);
139 pthread_setspecific(this->times, (void*)--times);
140
141 if (times == 0)
142 {
143 this->thread = 0;
144 unlock(&this->generic);
145 }
146 }
147
148 /**
149 * Implementation of mutex_t.destroy
150 */
151 static void mutex_destroy(private_mutex_t *this)
152 {
153 profiler_cleanup(&this->profile);
154 pthread_mutex_destroy(&this->mutex);
155 free(this);
156 }
157
158 /**
159 * Implementation of mutex_t.destroy for recursive mutex'
160 */
161 static void mutex_destroy_r(private_r_mutex_t *this)
162 {
163 profiler_cleanup(&this->generic.profile);
164 pthread_mutex_destroy(&this->generic.mutex);
165 pthread_key_delete(this->times);
166 free(this);
167 }
168
169 /*
170 * see header file
171 */
172 mutex_t *mutex_create(mutex_type_t type)
173 {
174 switch (type)
175 {
176 case MUTEX_TYPE_RECURSIVE:
177 {
178 private_r_mutex_t *this = malloc_thing(private_r_mutex_t);
179
180 this->generic.public.lock = (void(*)(mutex_t*))lock_r;
181 this->generic.public.unlock = (void(*)(mutex_t*))unlock_r;
182 this->generic.public.destroy = (void(*)(mutex_t*))mutex_destroy_r;
183
184 pthread_mutex_init(&this->generic.mutex, NULL);
185 pthread_key_create(&this->times, NULL);
186 this->generic.recursive = TRUE;
187 profiler_init(&this->generic.profile);
188 this->thread = 0;
189
190 return &this->generic.public;
191 }
192 case MUTEX_TYPE_DEFAULT:
193 default:
194 {
195 private_mutex_t *this = malloc_thing(private_mutex_t);
196
197 this->public.lock = (void(*)(mutex_t*))lock;
198 this->public.unlock = (void(*)(mutex_t*))unlock;
199 this->public.destroy = (void(*)(mutex_t*))mutex_destroy;
200
201 pthread_mutex_init(&this->mutex, NULL);
202 this->recursive = FALSE;
203 profiler_init(&this->profile);
204
205 return &this->public;
206 }
207 }
208 }
209