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>