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>