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>