Annotation of embedaddon/strongswan/src/libstrongswan/threading/mutex.c, revision 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>