2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000, 2001 Internet Software Consortium.
5 * Permission to use, copy, modify, and 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.
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.
18 /* $Id: mutex.c,v 1.6.2.1 2004/03/09 06:12:06 marka Exp $ */
26 #include <isc/mutex.h>
31 /* Operations on timevals; adapted from FreeBSD's sys/time.h */
32 #define timevalclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0)
33 #define timevaladd(vvp, uvp) \
35 (vvp)->tv_sec += (uvp)->tv_sec; \
36 (vvp)->tv_usec += (uvp)->tv_usec; \
37 if ((vvp)->tv_usec >= 1000000) { \
39 (vvp)->tv_usec -= 1000000; \
42 #define timevalsub(vvp, uvp) \
44 (vvp)->tv_sec -= (uvp)->tv_sec; \
45 (vvp)->tv_usec -= (uvp)->tv_usec; \
46 if ((vvp)->tv_usec < 0) { \
48 (vvp)->tv_usec += 1000000; \
52 #define ISC_MUTEX_MAX_LOCKERS 32
58 struct timeval locked_total
;
59 struct timeval wait_total
;
62 struct isc_mutexstats
{
63 const char * file
; /* File mutex was created in. */
64 int line
; /* Line mutex was created on. */
66 struct timeval lock_t
;
67 struct timeval locked_total
;
68 struct timeval wait_total
;
69 isc_mutexlocker_t
* cur_locker
;
70 isc_mutexlocker_t lockers
[ISC_MUTEX_MAX_LOCKERS
];
73 #define TABLESIZE (8 * 1024)
74 static isc_mutexstats_t stats
[TABLESIZE
];
75 static isc_boolean_t stats_init
= ISC_FALSE
;
76 static pthread_mutex_t statslock
= PTHREAD_MUTEX_INITIALIZER
;
80 isc_mutex_init_profile(isc_mutex_t
*mp
, const char *file
, int line
) {
83 if (pthread_mutex_init(&mp
->mutex
, NULL
) != 0)
84 return ISC_R_UNEXPECTED
;
86 RUNTIME_CHECK(pthread_mutex_lock(&statslock
) == 0);
88 if (stats_init
== ISC_FALSE
) {
89 for (i
= 0; i
< TABLESIZE
; i
++) {
92 stats_init
= ISC_TRUE
;
96 for (i
= 0; i
< TABLESIZE
; i
++) {
97 if (stats
[i
].file
== NULL
) {
98 mp
->stats
= &stats
[i
];
102 RUNTIME_CHECK(mp
->stats
!= NULL
);
104 RUNTIME_CHECK(pthread_mutex_unlock(&statslock
) == 0);
106 mp
->stats
->file
= file
;
107 mp
->stats
->line
= line
;
108 mp
->stats
->count
= 0;
109 timevalclear(&mp
->stats
->locked_total
);
110 timevalclear(&mp
->stats
->wait_total
);
111 for (i
= 0; i
< ISC_MUTEX_MAX_LOCKERS
; i
++) {
112 mp
->stats
->lockers
[i
].file
= NULL
;
113 mp
->stats
->lockers
[i
].line
= 0;
114 mp
->stats
->lockers
[i
].count
= 0;
115 timevalclear(&mp
->stats
->lockers
[i
].locked_total
);
116 timevalclear(&mp
->stats
->lockers
[i
].wait_total
);
119 return ISC_R_SUCCESS
;
123 isc_mutex_lock_profile(isc_mutex_t
*mp
, const char *file
, int line
) {
124 struct timeval prelock_t
;
125 struct timeval postlock_t
;
126 isc_mutexlocker_t
*locker
= NULL
;
129 for (i
= 0; i
< ISC_MUTEX_MAX_LOCKERS
; i
++) {
130 if (mp
->stats
->lockers
[i
].file
== NULL
) {
131 locker
= &mp
->stats
->lockers
[i
];
135 } else if (mp
->stats
->lockers
[i
].file
== file
&&
136 mp
->stats
->lockers
[i
].line
== line
) {
137 locker
= &mp
->stats
->lockers
[i
];
142 gettimeofday(&prelock_t
, NULL
);
144 if (pthread_mutex_lock(&mp
->mutex
) != 0)
145 return (ISC_R_UNEXPECTED
);
147 gettimeofday(&postlock_t
, NULL
);
148 mp
->stats
->lock_t
= postlock_t
;
150 timevalsub(&postlock_t
, &prelock_t
);
153 timevaladd(&mp
->stats
->wait_total
, &postlock_t
);
155 if (locker
!= NULL
) {
157 timevaladd(&locker
->wait_total
, &postlock_t
);
160 mp
->stats
->cur_locker
= locker
;
162 return ISC_R_SUCCESS
;
166 isc_mutex_unlock_profile(isc_mutex_t
*mp
, const char *file
, int line
) {
167 struct timeval unlock_t
;
172 if (mp
->stats
->cur_locker
!= NULL
) {
173 gettimeofday(&unlock_t
, NULL
);
174 timevalsub(&unlock_t
, &mp
->stats
->lock_t
);
175 timevaladd(&mp
->stats
->locked_total
, &unlock_t
);
176 timevaladd(&mp
->stats
->cur_locker
->locked_total
, &unlock_t
);
177 mp
->stats
->cur_locker
= NULL
;
180 return ((pthread_mutex_unlock((&mp
->mutex
)) == 0) ? \
181 ISC_R_SUCCESS
: ISC_R_UNEXPECTED
);
186 isc_mutex_statsprofile(FILE *fp
) {
187 isc_mutexlocker_t
*locker
;
189 fprintf(fp
, "Mutex stats (in us)\n");
190 for (i
= 0; i
< TABLESIZE
; i
++) {
191 if (stats
[i
].file
== NULL
)
193 fprintf(fp
, "%-12s %4d: %10u %lu.%06lu %lu.%06lu\n",
194 stats
[i
].file
, stats
[i
].line
, stats
[i
].count
,
195 stats
[i
].locked_total
.tv_sec
,
196 stats
[i
].locked_total
.tv_usec
,
197 stats
[i
].wait_total
.tv_sec
,
198 stats
[i
].wait_total
.tv_usec
200 for (j
= 0; j
< ISC_MUTEX_MAX_LOCKERS
; j
++) {
201 locker
= &stats
[i
].lockers
[j
];
202 if (locker
->file
== NULL
)
204 fprintf(fp
, " %-11s %4d: %10u %lu.%06lu %lu.%06lu\n",
205 locker
->file
, locker
->line
, locker
->count
,
206 locker
->locked_total
.tv_sec
,
207 locker
->locked_total
.tv_usec
,
208 locker
->wait_total
.tv_sec
,
209 locker
->wait_total
.tv_usec
215 #endif /* ISC_MUTEX_PROFILE */
217 #if ISC_MUTEX_DEBUG && defined(__NetBSD__) && defined(PTHREAD_MUTEX_ERRORCHECK)
218 pthread_mutexattr_t isc__mutex_attrs
= {
219 PTHREAD_MUTEX_ERRORCHECK
, /* m_type */
220 0 /* m_flags, which appears to be unused. */