Annotation of embedaddon/ntp/lib/isc/pthreads/mutex.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2004, 2005, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
        !             3:  * Copyright (C) 2000-2002  Internet Software Consortium.
        !             4:  *
        !             5:  * Permission to use, copy, modify, and/or distribute this software for any
        !             6:  * purpose with or without fee is hereby granted, provided that the above
        !             7:  * copyright notice and this permission notice appear in all copies.
        !             8:  *
        !             9:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
        !            10:  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
        !            11:  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
        !            12:  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
        !            13:  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
        !            14:  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
        !            15:  * PERFORMANCE OF THIS SOFTWARE.
        !            16:  */
        !            17: 
        !            18: /* $Id: mutex.c,v 1.16 2008/04/04 23:47:01 tbox Exp $ */
        !            19: 
        !            20: /*! \file */
        !            21: 
        !            22: #include <config.h>
        !            23: 
        !            24: #include <stdio.h>
        !            25: #include <time.h>
        !            26: #include <sys/time.h>
        !            27: #include <errno.h>
        !            28: 
        !            29: #include <isc/mutex.h>
        !            30: #include <isc/util.h>
        !            31: #include <isc/strerror.h>
        !            32: 
        !            33: #if ISC_MUTEX_PROFILE
        !            34: 
        !            35: /*@{*/
        !            36: /*% Operations on timevals; adapted from FreeBSD's sys/time.h */
        !            37: #define timevalclear(tvp)      ((tvp)->tv_sec = (tvp)->tv_usec = 0)
        !            38: #define timevaladd(vvp, uvp)                                            \
        !            39:        do {                                                            \
        !            40:                (vvp)->tv_sec += (uvp)->tv_sec;                         \
        !            41:                (vvp)->tv_usec += (uvp)->tv_usec;                       \
        !            42:                if ((vvp)->tv_usec >= 1000000) {                        \
        !            43:                        (vvp)->tv_sec++;                                \
        !            44:                        (vvp)->tv_usec -= 1000000;                      \
        !            45:                }                                                       \
        !            46:        } while (0)
        !            47: #define timevalsub(vvp, uvp)                                            \
        !            48:        do {                                                            \
        !            49:                (vvp)->tv_sec -= (uvp)->tv_sec;                         \
        !            50:                (vvp)->tv_usec -= (uvp)->tv_usec;                       \
        !            51:                if ((vvp)->tv_usec < 0) {                               \
        !            52:                        (vvp)->tv_sec--;                                \
        !            53:                        (vvp)->tv_usec += 1000000;                      \
        !            54:                }                                                       \
        !            55:        } while (0)
        !            56: 
        !            57: /*@}*/
        !            58: 
        !            59: #define ISC_MUTEX_MAX_LOCKERS 32
        !            60: 
        !            61: typedef struct {
        !            62:        const char *            file;
        !            63:        int                     line;
        !            64:        unsigned                count;
        !            65:        struct timeval          locked_total;
        !            66:        struct timeval          wait_total;
        !            67: } isc_mutexlocker_t;
        !            68: 
        !            69: struct isc_mutexstats {
        !            70:        const char *            file;   /*%< File mutex was created in. */
        !            71:        int                     line;   /*%< Line mutex was created on. */
        !            72:        unsigned                count;
        !            73:        struct timeval          lock_t;
        !            74:        struct timeval          locked_total;
        !            75:        struct timeval          wait_total;
        !            76:        isc_mutexlocker_t *     cur_locker;
        !            77:        isc_mutexlocker_t       lockers[ISC_MUTEX_MAX_LOCKERS];
        !            78: };
        !            79: 
        !            80: #ifndef ISC_MUTEX_PROFTABLESIZE
        !            81: #define ISC_MUTEX_PROFTABLESIZE (16 * 1024)
        !            82: #endif
        !            83: static isc_mutexstats_t stats[ISC_MUTEX_PROFTABLESIZE];
        !            84: static int stats_next = 0;
        !            85: static isc_boolean_t stats_init = ISC_FALSE;
        !            86: static pthread_mutex_t statslock = PTHREAD_MUTEX_INITIALIZER;
        !            87: 
        !            88: 
        !            89: isc_result_t
        !            90: isc_mutex_init_profile(isc_mutex_t *mp, const char *file, int line) {
        !            91:        int i, err;
        !            92: 
        !            93:        err = pthread_mutex_init(&mp->mutex, NULL);
        !            94:        if (err == ENOMEM)
        !            95:                return (ISC_R_NOMEMORY);
        !            96:        if (err != 0)
        !            97:                return (ISC_R_UNEXPECTED);
        !            98: 
        !            99:        RUNTIME_CHECK(pthread_mutex_lock(&statslock) == 0);
        !           100: 
        !           101:        if (stats_init == ISC_FALSE)
        !           102:                stats_init = ISC_TRUE;
        !           103: 
        !           104:        /*
        !           105:         * If all statistics entries have been used, give up and trigger an
        !           106:         * assertion failure.  There would be no other way to deal with this
        !           107:         * because we'd like to keep record of all locks for the purpose of
        !           108:         * debugging and the number of necessary locks is unpredictable.
        !           109:         * If this failure is triggered while debugging, named should be
        !           110:         * rebuilt with an increased ISC_MUTEX_PROFTABLESIZE.
        !           111:         */
        !           112:        RUNTIME_CHECK(stats_next < ISC_MUTEX_PROFTABLESIZE);
        !           113:        mp->stats = &stats[stats_next++];
        !           114: 
        !           115:        RUNTIME_CHECK(pthread_mutex_unlock(&statslock) == 0);
        !           116: 
        !           117:        mp->stats->file = file;
        !           118:        mp->stats->line = line;
        !           119:        mp->stats->count = 0;
        !           120:        timevalclear(&mp->stats->locked_total);
        !           121:        timevalclear(&mp->stats->wait_total);
        !           122:        for (i = 0; i < ISC_MUTEX_MAX_LOCKERS; i++) {
        !           123:                mp->stats->lockers[i].file = NULL;
        !           124:                mp->stats->lockers[i].line = 0;
        !           125:                mp->stats->lockers[i].count = 0;
        !           126:                timevalclear(&mp->stats->lockers[i].locked_total);
        !           127:                timevalclear(&mp->stats->lockers[i].wait_total);
        !           128:        }
        !           129: 
        !           130:        return (ISC_R_SUCCESS);
        !           131: }
        !           132: 
        !           133: isc_result_t
        !           134: isc_mutex_lock_profile(isc_mutex_t *mp, const char *file, int line) {
        !           135:        struct timeval prelock_t;
        !           136:        struct timeval postlock_t;
        !           137:        isc_mutexlocker_t *locker = NULL;
        !           138:        int i;
        !           139: 
        !           140:        gettimeofday(&prelock_t, NULL);
        !           141: 
        !           142:        if (pthread_mutex_lock(&mp->mutex) != 0)
        !           143:                return (ISC_R_UNEXPECTED);
        !           144: 
        !           145:        gettimeofday(&postlock_t, NULL);
        !           146:        mp->stats->lock_t = postlock_t;
        !           147: 
        !           148:        timevalsub(&postlock_t, &prelock_t);
        !           149: 
        !           150:        mp->stats->count++;
        !           151:        timevaladd(&mp->stats->wait_total, &postlock_t);
        !           152: 
        !           153:        for (i = 0; i < ISC_MUTEX_MAX_LOCKERS; i++) {
        !           154:                if (mp->stats->lockers[i].file == NULL) {
        !           155:                        locker = &mp->stats->lockers[i];
        !           156:                        locker->file = file;
        !           157:                        locker->line = line;
        !           158:                        break;
        !           159:                } else if (mp->stats->lockers[i].file == file &&
        !           160:                           mp->stats->lockers[i].line == line) {
        !           161:                        locker = &mp->stats->lockers[i];
        !           162:                        break;
        !           163:                }
        !           164:        }
        !           165: 
        !           166:        if (locker != NULL) {
        !           167:                locker->count++;
        !           168:                timevaladd(&locker->wait_total, &postlock_t);
        !           169:        }
        !           170: 
        !           171:        mp->stats->cur_locker = locker;
        !           172: 
        !           173:        return (ISC_R_SUCCESS);
        !           174: }
        !           175: 
        !           176: isc_result_t
        !           177: isc_mutex_unlock_profile(isc_mutex_t *mp, const char *file, int line) {
        !           178:        struct timeval unlock_t;
        !           179: 
        !           180:        UNUSED(file);
        !           181:        UNUSED(line);
        !           182: 
        !           183:        if (mp->stats->cur_locker != NULL) {
        !           184:                gettimeofday(&unlock_t, NULL);
        !           185:                timevalsub(&unlock_t, &mp->stats->lock_t);
        !           186:                timevaladd(&mp->stats->locked_total, &unlock_t);
        !           187:                timevaladd(&mp->stats->cur_locker->locked_total, &unlock_t);
        !           188:                mp->stats->cur_locker = NULL;
        !           189:        }
        !           190: 
        !           191:        return ((pthread_mutex_unlock((&mp->mutex)) == 0) ? \
        !           192:                ISC_R_SUCCESS : ISC_R_UNEXPECTED);
        !           193: }
        !           194: 
        !           195: 
        !           196: void
        !           197: isc_mutex_statsprofile(FILE *fp) {
        !           198:        isc_mutexlocker_t *locker;
        !           199:        int i, j;
        !           200: 
        !           201:        fprintf(fp, "Mutex stats (in us)\n");
        !           202:        for (i = 0; i < stats_next; i++) {
        !           203:                fprintf(fp, "%-12s %4d: %10u  %lu.%06lu %lu.%06lu\n",
        !           204:                        stats[i].file, stats[i].line, stats[i].count,
        !           205:                        stats[i].locked_total.tv_sec,
        !           206:                        stats[i].locked_total.tv_usec,
        !           207:                        stats[i].wait_total.tv_sec,
        !           208:                        stats[i].wait_total.tv_usec
        !           209:                        );
        !           210:                for (j = 0; j < ISC_MUTEX_MAX_LOCKERS; j++) {
        !           211:                        locker = &stats[i].lockers[j];
        !           212:                        if (locker->file == NULL)
        !           213:                                continue;
        !           214:                        fprintf(fp, " %-11s %4d: %10u  %lu.%06lu %lu.%06lu\n",
        !           215:                                locker->file, locker->line, locker->count,
        !           216:                                locker->locked_total.tv_sec,
        !           217:                                locker->locked_total.tv_usec,
        !           218:                                locker->wait_total.tv_sec,
        !           219:                                locker->wait_total.tv_usec
        !           220:                                );
        !           221:                }
        !           222:        }
        !           223: }
        !           224: 
        !           225: #endif /* ISC_MUTEX_PROFILE */
        !           226: 
        !           227: #if ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK)
        !           228: isc_result_t
        !           229: isc_mutex_init_errcheck(isc_mutex_t *mp)
        !           230: {
        !           231:        pthread_mutexattr_t attr;
        !           232:        int err;
        !           233: 
        !           234:        if (pthread_mutexattr_init(&attr) != 0)
        !           235:                return (ISC_R_UNEXPECTED);
        !           236: 
        !           237:        if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) != 0)
        !           238:                return (ISC_R_UNEXPECTED);
        !           239: 
        !           240:        err = pthread_mutex_init(mp, &attr) != 0)
        !           241:        if (err == ENOMEM)
        !           242:                return (ISC_R_NOMEMORY);
        !           243:        return ((err == 0) ? ISC_R_SUCCESS : ISC_R_UNEXPECTED);
        !           244: }
        !           245: #endif
        !           246: 
        !           247: #if ISC_MUTEX_DEBUG && defined(__NetBSD__) && defined(PTHREAD_MUTEX_ERRORCHECK)
        !           248: pthread_mutexattr_t isc__mutex_attrs = {
        !           249:        PTHREAD_MUTEX_ERRORCHECK,       /* m_type */
        !           250:        0                               /* m_flags, which appears to be unused. */
        !           251: };
        !           252: #endif
        !           253: 
        !           254: #if !(ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK)) && !ISC_MUTEX_PROFILE
        !           255: isc_result_t
        !           256: isc__mutex_init(isc_mutex_t *mp, const char *file, unsigned int line) {
        !           257:        char strbuf[ISC_STRERRORSIZE];
        !           258:        isc_result_t result = ISC_R_SUCCESS;
        !           259:        int err;
        !           260: 
        !           261:        err = pthread_mutex_init(mp, ISC__MUTEX_ATTRS);
        !           262:        if (err == ENOMEM)
        !           263:                return (ISC_R_NOMEMORY);
        !           264:        if (err != 0) {
        !           265:                isc__strerror(errno, strbuf, sizeof(strbuf));
        !           266:                UNEXPECTED_ERROR(file, line, "isc_mutex_init() failed: %s",
        !           267:                                 strbuf);
        !           268:                result = ISC_R_UNEXPECTED;
        !           269:        }
        !           270:        return (result);
        !           271: }
        !           272: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>