Annotation of embedaddon/strongswan/src/libstrongswan/threading/mutex.c, revision 1.1.1.2
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 */
1.1.1.2 ! misho 242: #if defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) && \
! 243: !defined(HAVE_CONDATTR_CLOCK_MONOTONIC)
1.1 misho 244: #define pthread_cond_timedwait pthread_cond_timedwait_monotonic
245: #endif
246:
247: METHOD(condvar_t, timed_wait_abs, bool,
248: private_condvar_t *this, private_mutex_t *mutex, timeval_t time)
249: {
250: struct timespec ts;
251: bool timed_out;
252:
253: ts.tv_sec = time.tv_sec;
254: ts.tv_nsec = time.tv_usec * 1000;
255:
256: if (mutex->recursive)
257: {
258: private_r_mutex_t* recursive = (private_r_mutex_t*)mutex;
259: thread_t *self = thread_current();
260: u_int times;
261:
262: times = recursive->times;
263: cas_ptr(&recursive->thread, self, NULL);
264: timed_out = pthread_cond_timedwait(&this->condvar, &mutex->mutex,
265: &ts) == ETIMEDOUT;
266: cas_ptr(&recursive->thread, NULL, self);
267: recursive->times = times;
268: }
269: else
270: {
271: timed_out = pthread_cond_timedwait(&this->condvar, &mutex->mutex,
272: &ts) == ETIMEDOUT;
273: }
274: return timed_out;
275: }
276:
277: METHOD(condvar_t, timed_wait, bool,
278: private_condvar_t *this, private_mutex_t *mutex, u_int timeout)
279: {
280: timeval_t tv;
281: u_int s, ms;
282:
283: time_monotonic(&tv);
284:
285: s = timeout / 1000;
286: ms = timeout % 1000;
287:
288: tv.tv_sec += s;
289: timeval_add_ms(&tv, ms);
290: return timed_wait_abs(this, mutex, tv);
291: }
292:
293: METHOD(condvar_t, signal_, void,
294: private_condvar_t *this)
295: {
296: pthread_cond_signal(&this->condvar);
297: }
298:
299: METHOD(condvar_t, broadcast, void,
300: private_condvar_t *this)
301: {
302: pthread_cond_broadcast(&this->condvar);
303: }
304:
305: METHOD(condvar_t, condvar_destroy, void,
306: private_condvar_t *this)
307: {
308: pthread_cond_destroy(&this->condvar);
309: free(this);
310: }
311:
312: /*
313: * see header file
314: */
315: condvar_t *condvar_create(condvar_type_t type)
316: {
317: switch (type)
318: {
319: case CONDVAR_TYPE_DEFAULT:
320: default:
321: {
322: private_condvar_t *this;
323:
324: INIT(this,
325: .public = {
326: .wait = (void*)_wait_,
327: .timed_wait = (void*)_timed_wait,
328: .timed_wait_abs = (void*)_timed_wait_abs,
329: .signal = _signal_,
330: .broadcast = _broadcast,
331: .destroy = _condvar_destroy,
332: }
333: );
334:
335: #ifdef HAVE_PTHREAD_CONDATTR_INIT
336: {
337: pthread_condattr_t condattr;
338: pthread_condattr_init(&condattr);
339: #ifdef HAVE_CONDATTR_CLOCK_MONOTONIC
1.1.1.2 ! misho 340: pthread_condattr_setclock(&condattr, TIME_CLOCK_ID);
1.1 misho 341: #endif
342: pthread_cond_init(&this->condvar, &condattr);
343: pthread_condattr_destroy(&condattr);
344: }
345: #endif
346:
347: return &this->public;
348: }
349: }
350: }
351:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>