Annotation of embedaddon/strongswan/src/libstrongswan/threading/mutex.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2008-2012 Tobias Brunner
3: * Copyright (C) 2008 Martin Willi
4: * HSR 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: #include <stdint.h>
20: #include <time.h>
21: #include <errno.h>
22:
23: #include <library.h>
24: #include <utils/debug.h>
25:
26: #include "thread.h"
27: #include "condvar.h"
28: #include "mutex.h"
29: #include "lock_profiler.h"
30:
31: typedef struct private_mutex_t private_mutex_t;
32: typedef struct private_r_mutex_t private_r_mutex_t;
33: typedef struct private_condvar_t private_condvar_t;
34:
35: /**
36: * private data of mutex
37: */
38: struct private_mutex_t {
39:
40: /**
41: * public functions
42: */
43: mutex_t public;
44:
45: /**
46: * wrapped pthread mutex
47: */
48: pthread_mutex_t mutex;
49:
50: /**
51: * is this a recursive mutex, implementing private_r_mutex_t?
52: */
53: bool recursive;
54:
55: /**
56: * profiling info, if enabled
57: */
58: lock_profile_t profile;
59: };
60:
61: /**
62: * private data of mutex, extended by recursive locking information
63: */
64: struct private_r_mutex_t {
65:
66: /**
67: * Extends private_mutex_t
68: */
69: private_mutex_t generic;
70:
71: /**
72: * thread which currently owns mutex
73: */
74: thread_t *thread;
75:
76: /**
77: * times the current thread locked the mutex
78: */
79: u_int times;
80: };
81:
82: /**
83: * private data of condvar
84: */
85: struct private_condvar_t {
86:
87: /**
88: * public functions
89: */
90: condvar_t public;
91:
92: /**
93: * wrapped pthread condvar
94: */
95: pthread_cond_t condvar;
96:
97: };
98:
99:
100: METHOD(mutex_t, lock, void,
101: private_mutex_t *this)
102: {
103: int err;
104:
105: profiler_start(&this->profile);
106: err = pthread_mutex_lock(&this->mutex);
107: if (err)
108: {
109: DBG1(DBG_LIB, "!!! MUTEX LOCK ERROR: %s !!!", strerror(err));
110: }
111: profiler_end(&this->profile);
112: }
113:
114: METHOD(mutex_t, unlock, void,
115: private_mutex_t *this)
116: {
117: int err;
118:
119: err = pthread_mutex_unlock(&this->mutex);
120: if (err)
121: {
122: DBG1(DBG_LIB, "!!! MUTEX UNLOCK ERROR: %s !!!", strerror(err));
123: }
124: }
125:
126: METHOD(mutex_t, lock_r, void,
127: private_r_mutex_t *this)
128: {
129: thread_t *self = thread_current();
130:
131: if (cas_ptr(&this->thread, self, self))
132: {
133: this->times++;
134: }
135: else
136: {
137: lock(&this->generic);
138: cas_ptr(&this->thread, NULL, self);
139: this->times = 1;
140: }
141: }
142:
143: METHOD(mutex_t, unlock_r, void,
144: private_r_mutex_t *this)
145: {
146: if (--this->times == 0)
147: {
148: cas_ptr(&this->thread, thread_current(), NULL);
149: unlock(&this->generic);
150: }
151: }
152:
153: METHOD(mutex_t, mutex_destroy, void,
154: private_mutex_t *this)
155: {
156: profiler_cleanup(&this->profile);
157: pthread_mutex_destroy(&this->mutex);
158: free(this);
159: }
160:
161: METHOD(mutex_t, mutex_destroy_r, void,
162: private_r_mutex_t *this)
163: {
164: profiler_cleanup(&this->generic.profile);
165: pthread_mutex_destroy(&this->generic.mutex);
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;
179:
180: INIT(this,
181: .generic = {
182: .public = {
183: .lock = _lock_r,
184: .unlock = _unlock_r,
185: .destroy = _mutex_destroy_r,
186: },
187: .recursive = TRUE,
188: },
189: );
190:
191: pthread_mutex_init(&this->generic.mutex, NULL);
192: profiler_init(&this->generic.profile);
193:
194: return &this->generic.public;
195: }
196: case MUTEX_TYPE_DEFAULT:
197: default:
198: {
199: private_mutex_t *this;
200:
201: INIT(this,
202: .public = {
203: .lock = _lock,
204: .unlock = _unlock,
205: .destroy = _mutex_destroy,
206: },
207: );
208:
209: pthread_mutex_init(&this->mutex, NULL);
210: profiler_init(&this->profile);
211:
212: return &this->public;
213: }
214: }
215: }
216:
217:
218: METHOD(condvar_t, wait_, void,
219: private_condvar_t *this, private_mutex_t *mutex)
220: {
221: if (mutex->recursive)
222: {
223: private_r_mutex_t* recursive = (private_r_mutex_t*)mutex;
224: thread_t *self = thread_current();
225: u_int times;
226:
227: /* keep track of the number of times this thread locked the mutex */
228: times = recursive->times;
229: /* mutex owner gets cleared during condvar wait */
230: cas_ptr(&recursive->thread, self, NULL);
231: pthread_cond_wait(&this->condvar, &mutex->mutex);
232: cas_ptr(&recursive->thread, NULL, self);
233: recursive->times = times;
234: }
235: else
236: {
237: pthread_cond_wait(&this->condvar, &mutex->mutex);
238: }
239: }
240:
241: /* use the monotonic clock based version of this function if available */
242: #ifdef HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
243: #define pthread_cond_timedwait pthread_cond_timedwait_monotonic
244: #endif
245:
246: METHOD(condvar_t, timed_wait_abs, bool,
247: private_condvar_t *this, private_mutex_t *mutex, timeval_t time)
248: {
249: struct timespec ts;
250: bool timed_out;
251:
252: ts.tv_sec = time.tv_sec;
253: ts.tv_nsec = time.tv_usec * 1000;
254:
255: if (mutex->recursive)
256: {
257: private_r_mutex_t* recursive = (private_r_mutex_t*)mutex;
258: thread_t *self = thread_current();
259: u_int times;
260:
261: times = recursive->times;
262: cas_ptr(&recursive->thread, self, NULL);
263: timed_out = pthread_cond_timedwait(&this->condvar, &mutex->mutex,
264: &ts) == ETIMEDOUT;
265: cas_ptr(&recursive->thread, NULL, self);
266: recursive->times = times;
267: }
268: else
269: {
270: timed_out = pthread_cond_timedwait(&this->condvar, &mutex->mutex,
271: &ts) == ETIMEDOUT;
272: }
273: return timed_out;
274: }
275:
276: METHOD(condvar_t, timed_wait, bool,
277: private_condvar_t *this, private_mutex_t *mutex, u_int timeout)
278: {
279: timeval_t tv;
280: u_int s, ms;
281:
282: time_monotonic(&tv);
283:
284: s = timeout / 1000;
285: ms = timeout % 1000;
286:
287: tv.tv_sec += s;
288: timeval_add_ms(&tv, ms);
289: return timed_wait_abs(this, mutex, tv);
290: }
291:
292: METHOD(condvar_t, signal_, void,
293: private_condvar_t *this)
294: {
295: pthread_cond_signal(&this->condvar);
296: }
297:
298: METHOD(condvar_t, broadcast, void,
299: private_condvar_t *this)
300: {
301: pthread_cond_broadcast(&this->condvar);
302: }
303:
304: METHOD(condvar_t, condvar_destroy, void,
305: private_condvar_t *this)
306: {
307: pthread_cond_destroy(&this->condvar);
308: free(this);
309: }
310:
311: /*
312: * see header file
313: */
314: condvar_t *condvar_create(condvar_type_t type)
315: {
316: switch (type)
317: {
318: case CONDVAR_TYPE_DEFAULT:
319: default:
320: {
321: private_condvar_t *this;
322:
323: INIT(this,
324: .public = {
325: .wait = (void*)_wait_,
326: .timed_wait = (void*)_timed_wait,
327: .timed_wait_abs = (void*)_timed_wait_abs,
328: .signal = _signal_,
329: .broadcast = _broadcast,
330: .destroy = _condvar_destroy,
331: }
332: );
333:
334: #ifdef HAVE_PTHREAD_CONDATTR_INIT
335: {
336: pthread_condattr_t condattr;
337: pthread_condattr_init(&condattr);
338: #ifdef HAVE_CONDATTR_CLOCK_MONOTONIC
339: pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC);
340: #endif
341: pthread_cond_init(&this->condvar, &condattr);
342: pthread_condattr_destroy(&condattr);
343: }
344: #endif
345:
346: return &this->public;
347: }
348: }
349: }
350:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>