Annotation of embedaddon/ntp/lib/isc/pthreads/mutex.c, revision 1.1.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>