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>