00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include <stdio.h>
00025 #include <time.h>
00026 #include <sys/time.h>
00027 #include <errno.h>
00028
00029 #include <isc/mutex.h>
00030 #include <isc/util.h>
00031 #include <isc/strerror.h>
00032 #include <isc/once.h>
00033
00034 #if ISC_MUTEX_PROFILE
00035
00036
00037
00038 #define timevalclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0)
00039 #define timevaladd(vvp, uvp) \
00040 do { \
00041 (vvp)->tv_sec += (uvp)->tv_sec; \
00042 (vvp)->tv_usec += (uvp)->tv_usec; \
00043 if ((vvp)->tv_usec >= 1000000) { \
00044 (vvp)->tv_sec++; \
00045 (vvp)->tv_usec -= 1000000; \
00046 } \
00047 } while (0)
00048 #define timevalsub(vvp, uvp) \
00049 do { \
00050 (vvp)->tv_sec -= (uvp)->tv_sec; \
00051 (vvp)->tv_usec -= (uvp)->tv_usec; \
00052 if ((vvp)->tv_usec < 0) { \
00053 (vvp)->tv_sec--; \
00054 (vvp)->tv_usec += 1000000; \
00055 } \
00056 } while (0)
00057
00058
00059
00060 #define ISC_MUTEX_MAX_LOCKERS 32
00061
00062 typedef struct {
00063 const char * file;
00064 int line;
00065 unsigned count;
00066 struct timeval locked_total;
00067 struct timeval wait_total;
00068 } isc_mutexlocker_t;
00069
00070 struct isc_mutexstats {
00071 const char * file;
00072 int line;
00073 unsigned count;
00074 struct timeval lock_t;
00075 struct timeval locked_total;
00076 struct timeval wait_total;
00077 isc_mutexlocker_t * cur_locker;
00078 isc_mutexlocker_t lockers[ISC_MUTEX_MAX_LOCKERS];
00079 };
00080
00081 #ifndef ISC_MUTEX_PROFTABLESIZE
00082 #define ISC_MUTEX_PROFTABLESIZE (1024 * 1024)
00083 #endif
00084 static isc_mutexstats_t stats[ISC_MUTEX_PROFTABLESIZE];
00085 static int stats_next = 0;
00086 static isc_boolean_t stats_init = ISC_FALSE;
00087 static pthread_mutex_t statslock = PTHREAD_MUTEX_INITIALIZER;
00088
00089
00090 isc_result_t
00091 isc_mutex_init_profile(isc_mutex_t *mp, const char *file, int line) {
00092 int i, err;
00093
00094 err = pthread_mutex_init(&mp->mutex, NULL);
00095 if (err == ENOMEM)
00096 return (ISC_R_NOMEMORY);
00097 if (err != 0)
00098 return (ISC_R_UNEXPECTED);
00099
00100 RUNTIME_CHECK(pthread_mutex_lock(&statslock) == 0);
00101
00102 if (stats_init == ISC_FALSE)
00103 stats_init = ISC_TRUE;
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113 RUNTIME_CHECK(stats_next < ISC_MUTEX_PROFTABLESIZE);
00114 mp->stats = &stats[stats_next++];
00115
00116 RUNTIME_CHECK(pthread_mutex_unlock(&statslock) == 0);
00117
00118 mp->stats->file = file;
00119 mp->stats->line = line;
00120 mp->stats->count = 0;
00121 timevalclear(&mp->stats->locked_total);
00122 timevalclear(&mp->stats->wait_total);
00123 for (i = 0; i < ISC_MUTEX_MAX_LOCKERS; i++) {
00124 mp->stats->lockers[i].file = NULL;
00125 mp->stats->lockers[i].line = 0;
00126 mp->stats->lockers[i].count = 0;
00127 timevalclear(&mp->stats->lockers[i].locked_total);
00128 timevalclear(&mp->stats->lockers[i].wait_total);
00129 }
00130
00131 return (ISC_R_SUCCESS);
00132 }
00133
00134 isc_result_t
00135 isc_mutex_lock_profile(isc_mutex_t *mp, const char *file, int line) {
00136 struct timeval prelock_t;
00137 struct timeval postlock_t;
00138 isc_mutexlocker_t *locker = NULL;
00139 int i;
00140
00141 gettimeofday(&prelock_t, NULL);
00142
00143 if (pthread_mutex_lock(&mp->mutex) != 0)
00144 return (ISC_R_UNEXPECTED);
00145
00146 gettimeofday(&postlock_t, NULL);
00147 mp->stats->lock_t = postlock_t;
00148
00149 timevalsub(&postlock_t, &prelock_t);
00150
00151 mp->stats->count++;
00152 timevaladd(&mp->stats->wait_total, &postlock_t);
00153
00154 for (i = 0; i < ISC_MUTEX_MAX_LOCKERS; i++) {
00155 if (mp->stats->lockers[i].file == NULL) {
00156 locker = &mp->stats->lockers[i];
00157 locker->file = file;
00158 locker->line = line;
00159 break;
00160 } else if (mp->stats->lockers[i].file == file &&
00161 mp->stats->lockers[i].line == line) {
00162 locker = &mp->stats->lockers[i];
00163 break;
00164 }
00165 }
00166
00167 if (locker != NULL) {
00168 locker->count++;
00169 timevaladd(&locker->wait_total, &postlock_t);
00170 }
00171
00172 mp->stats->cur_locker = locker;
00173
00174 return (ISC_R_SUCCESS);
00175 }
00176
00177 isc_result_t
00178 isc_mutex_unlock_profile(isc_mutex_t *mp, const char *file, int line) {
00179 struct timeval unlock_t;
00180
00181 UNUSED(file);
00182 UNUSED(line);
00183
00184 if (mp->stats->cur_locker != NULL) {
00185 gettimeofday(&unlock_t, NULL);
00186 timevalsub(&unlock_t, &mp->stats->lock_t);
00187 timevaladd(&mp->stats->locked_total, &unlock_t);
00188 timevaladd(&mp->stats->cur_locker->locked_total, &unlock_t);
00189 mp->stats->cur_locker = NULL;
00190 }
00191
00192 return ((pthread_mutex_unlock((&mp->mutex)) == 0) ? \
00193 ISC_R_SUCCESS : ISC_R_UNEXPECTED);
00194 }
00195
00196
00197 void
00198 isc_mutex_statsprofile(FILE *fp) {
00199 isc_mutexlocker_t *locker;
00200 int i, j;
00201
00202 fprintf(fp, "Mutex stats (in us)\n");
00203 for (i = 0; i < stats_next; i++) {
00204 fprintf(fp, "%-12s %4d: %10u %lu.%06lu %lu.%06lu %5d\n",
00205 stats[i].file, stats[i].line, stats[i].count,
00206 stats[i].locked_total.tv_sec,
00207 stats[i].locked_total.tv_usec,
00208 stats[i].wait_total.tv_sec,
00209 stats[i].wait_total.tv_usec,
00210 i);
00211 for (j = 0; j < ISC_MUTEX_MAX_LOCKERS; j++) {
00212 locker = &stats[i].lockers[j];
00213 if (locker->file == NULL)
00214 continue;
00215 fprintf(fp, " %-11s %4d: %10u %lu.%06lu %lu.%06lu %5d\n",
00216 locker->file, locker->line, locker->count,
00217 locker->locked_total.tv_sec,
00218 locker->locked_total.tv_usec,
00219 locker->wait_total.tv_sec,
00220 locker->wait_total.tv_usec,
00221 i);
00222 }
00223 }
00224 }
00225
00226 #endif
00227
00228 #if ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK)
00229
00230 static isc_boolean_t errcheck_initialized = ISC_FALSE;
00231 static pthread_mutexattr_t errcheck;
00232 static isc_once_t once_errcheck = ISC_ONCE_INIT;
00233
00234 static void
00235 initialize_errcheck(void) {
00236 RUNTIME_CHECK(pthread_mutexattr_init(&errcheck) == 0);
00237 RUNTIME_CHECK(pthread_mutexattr_settype
00238 (&errcheck, PTHREAD_MUTEX_ERRORCHECK) == 0);
00239 errcheck_initialized = ISC_TRUE;
00240 }
00241
00242 isc_result_t
00243 isc_mutex_init_errcheck(isc_mutex_t *mp) {
00244 isc_result_t result;
00245 int err;
00246
00247 result = isc_once_do(&once_errcheck, initialize_errcheck);
00248 RUNTIME_CHECK(result == ISC_R_SUCCESS);
00249
00250 err = pthread_mutex_init(mp, &errcheck);
00251 if (err == ENOMEM)
00252 return (ISC_R_NOMEMORY);
00253 return ((err == 0) ? ISC_R_SUCCESS : ISC_R_UNEXPECTED);
00254 }
00255 #endif
00256
00257 #if ISC_MUTEX_DEBUG && defined(__NetBSD__) && defined(PTHREAD_MUTEX_ERRORCHECK)
00258 pthread_mutexattr_t isc__mutex_attrs = {
00259 PTHREAD_MUTEX_ERRORCHECK,
00260 0
00261 };
00262 #endif
00263
00264 #if !(ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK)) && !ISC_MUTEX_PROFILE
00265
00266 #ifdef HAVE_PTHREAD_MUTEX_ADAPTIVE_NP
00267 static isc_boolean_t attr_initialized = ISC_FALSE;
00268 static pthread_mutexattr_t attr;
00269 static isc_once_t once_attr = ISC_ONCE_INIT;
00270 #endif
00271
00272 #ifdef HAVE_PTHREAD_MUTEX_ADAPTIVE_NP
00273 static void
00274 initialize_attr(void) {
00275 RUNTIME_CHECK(pthread_mutexattr_init(&attr) == 0);
00276 RUNTIME_CHECK(pthread_mutexattr_settype
00277 (&attr, PTHREAD_MUTEX_ADAPTIVE_NP) == 0);
00278 attr_initialized = ISC_TRUE;
00279 }
00280 #endif
00281
00282 isc_result_t
00283 isc__mutex_init(isc_mutex_t *mp, const char *file, unsigned int line) {
00284 char strbuf[ISC_STRERRORSIZE];
00285 isc_result_t result = ISC_R_SUCCESS;
00286 int err;
00287
00288 #ifdef HAVE_PTHREAD_MUTEX_ADAPTIVE_NP
00289 result = isc_once_do(&once_attr, initialize_attr);
00290 RUNTIME_CHECK(result == ISC_R_SUCCESS);
00291
00292 err = pthread_mutex_init(mp, &attr);
00293 #else
00294 err = pthread_mutex_init(mp, ISC__MUTEX_ATTRS);
00295 #endif
00296
00297 if (err == ENOMEM)
00298 return (ISC_R_NOMEMORY);
00299 if (err != 0) {
00300 isc__strerror(err, strbuf, sizeof(strbuf));
00301 UNEXPECTED_ERROR(file, line, "isc_mutex_init() failed: %s",
00302 strbuf);
00303 result = ISC_R_UNEXPECTED;
00304 }
00305 return (result);
00306 }
00307 #endif