1*00b67f09SDavid van Moolenbroek /* $NetBSD: mutex.c,v 1.6 2015/07/08 17:28:59 christos Exp $ */
2*00b67f09SDavid van Moolenbroek
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek * Copyright (C) 2004, 2005, 2007, 2008, 2011, 2012, 2014, 2015 Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek * Copyright (C) 2000-2002 Internet Software Consortium.
6*00b67f09SDavid van Moolenbroek *
7*00b67f09SDavid van Moolenbroek * Permission to use, copy, modify, and/or distribute this software for any
8*00b67f09SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
9*00b67f09SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
10*00b67f09SDavid van Moolenbroek *
11*00b67f09SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12*00b67f09SDavid van Moolenbroek * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13*00b67f09SDavid van Moolenbroek * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14*00b67f09SDavid van Moolenbroek * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15*00b67f09SDavid van Moolenbroek * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16*00b67f09SDavid van Moolenbroek * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*00b67f09SDavid van Moolenbroek * PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek */
19*00b67f09SDavid van Moolenbroek
20*00b67f09SDavid van Moolenbroek /* Id: mutex.c,v 1.18 2011/01/04 23:47:14 tbox Exp */
21*00b67f09SDavid van Moolenbroek
22*00b67f09SDavid van Moolenbroek /*! \file */
23*00b67f09SDavid van Moolenbroek
24*00b67f09SDavid van Moolenbroek #include <config.h>
25*00b67f09SDavid van Moolenbroek
26*00b67f09SDavid van Moolenbroek #include <stdio.h>
27*00b67f09SDavid van Moolenbroek #include <time.h>
28*00b67f09SDavid van Moolenbroek #include <sys/time.h>
29*00b67f09SDavid van Moolenbroek #include <errno.h>
30*00b67f09SDavid van Moolenbroek
31*00b67f09SDavid van Moolenbroek #include <isc/mutex.h>
32*00b67f09SDavid van Moolenbroek #include <isc/util.h>
33*00b67f09SDavid van Moolenbroek #include <isc/strerror.h>
34*00b67f09SDavid van Moolenbroek
35*00b67f09SDavid van Moolenbroek #if ISC_MUTEX_PROFILE
36*00b67f09SDavid van Moolenbroek
37*00b67f09SDavid van Moolenbroek /*@{*/
38*00b67f09SDavid van Moolenbroek /*% Operations on timevals; adapted from FreeBSD's sys/time.h */
39*00b67f09SDavid van Moolenbroek #define timevalclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0)
40*00b67f09SDavid van Moolenbroek #define timevaladd(vvp, uvp) \
41*00b67f09SDavid van Moolenbroek do { \
42*00b67f09SDavid van Moolenbroek (vvp)->tv_sec += (uvp)->tv_sec; \
43*00b67f09SDavid van Moolenbroek (vvp)->tv_usec += (uvp)->tv_usec; \
44*00b67f09SDavid van Moolenbroek if ((vvp)->tv_usec >= 1000000) { \
45*00b67f09SDavid van Moolenbroek (vvp)->tv_sec++; \
46*00b67f09SDavid van Moolenbroek (vvp)->tv_usec -= 1000000; \
47*00b67f09SDavid van Moolenbroek } \
48*00b67f09SDavid van Moolenbroek } while (/*CONSTCOND*/0)
49*00b67f09SDavid van Moolenbroek #define timevalsub(vvp, uvp) \
50*00b67f09SDavid van Moolenbroek do { \
51*00b67f09SDavid van Moolenbroek (vvp)->tv_sec -= (uvp)->tv_sec; \
52*00b67f09SDavid van Moolenbroek (vvp)->tv_usec -= (uvp)->tv_usec; \
53*00b67f09SDavid van Moolenbroek if ((vvp)->tv_usec < 0) { \
54*00b67f09SDavid van Moolenbroek (vvp)->tv_sec--; \
55*00b67f09SDavid van Moolenbroek (vvp)->tv_usec += 1000000; \
56*00b67f09SDavid van Moolenbroek } \
57*00b67f09SDavid van Moolenbroek } while (/*CONSTCOND*/0)
58*00b67f09SDavid van Moolenbroek
59*00b67f09SDavid van Moolenbroek /*@}*/
60*00b67f09SDavid van Moolenbroek
61*00b67f09SDavid van Moolenbroek #define ISC_MUTEX_MAX_LOCKERS 32
62*00b67f09SDavid van Moolenbroek
63*00b67f09SDavid van Moolenbroek typedef struct {
64*00b67f09SDavid van Moolenbroek const char * file;
65*00b67f09SDavid van Moolenbroek int line;
66*00b67f09SDavid van Moolenbroek unsigned count;
67*00b67f09SDavid van Moolenbroek struct timeval locked_total;
68*00b67f09SDavid van Moolenbroek struct timeval wait_total;
69*00b67f09SDavid van Moolenbroek } isc_mutexlocker_t;
70*00b67f09SDavid van Moolenbroek
71*00b67f09SDavid van Moolenbroek struct isc_mutexstats {
72*00b67f09SDavid van Moolenbroek const char * file; /*%< File mutex was created in. */
73*00b67f09SDavid van Moolenbroek int line; /*%< Line mutex was created on. */
74*00b67f09SDavid van Moolenbroek unsigned count;
75*00b67f09SDavid van Moolenbroek struct timeval lock_t;
76*00b67f09SDavid van Moolenbroek struct timeval locked_total;
77*00b67f09SDavid van Moolenbroek struct timeval wait_total;
78*00b67f09SDavid van Moolenbroek isc_mutexlocker_t * cur_locker;
79*00b67f09SDavid van Moolenbroek isc_mutexlocker_t lockers[ISC_MUTEX_MAX_LOCKERS];
80*00b67f09SDavid van Moolenbroek };
81*00b67f09SDavid van Moolenbroek
82*00b67f09SDavid van Moolenbroek #ifndef ISC_MUTEX_PROFTABLESIZE
83*00b67f09SDavid van Moolenbroek #define ISC_MUTEX_PROFTABLESIZE (1024 * 1024)
84*00b67f09SDavid van Moolenbroek #endif
85*00b67f09SDavid van Moolenbroek static isc_mutexstats_t stats[ISC_MUTEX_PROFTABLESIZE];
86*00b67f09SDavid van Moolenbroek static int stats_next = 0;
87*00b67f09SDavid van Moolenbroek static isc_boolean_t stats_init = ISC_FALSE;
88*00b67f09SDavid van Moolenbroek static pthread_mutex_t statslock = PTHREAD_MUTEX_INITIALIZER;
89*00b67f09SDavid van Moolenbroek
90*00b67f09SDavid van Moolenbroek
91*00b67f09SDavid van Moolenbroek isc_result_t
isc_mutex_init_profile(isc_mutex_t * mp,const char * file,int line)92*00b67f09SDavid van Moolenbroek isc_mutex_init_profile(isc_mutex_t *mp, const char *file, int line) {
93*00b67f09SDavid van Moolenbroek int i, err;
94*00b67f09SDavid van Moolenbroek
95*00b67f09SDavid van Moolenbroek err = pthread_mutex_init(&mp->mutex, NULL);
96*00b67f09SDavid van Moolenbroek if (err == ENOMEM)
97*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
98*00b67f09SDavid van Moolenbroek if (err != 0)
99*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTED);
100*00b67f09SDavid van Moolenbroek
101*00b67f09SDavid van Moolenbroek RUNTIME_CHECK(pthread_mutex_lock(&statslock) == 0);
102*00b67f09SDavid van Moolenbroek
103*00b67f09SDavid van Moolenbroek if (stats_init == ISC_FALSE)
104*00b67f09SDavid van Moolenbroek stats_init = ISC_TRUE;
105*00b67f09SDavid van Moolenbroek
106*00b67f09SDavid van Moolenbroek /*
107*00b67f09SDavid van Moolenbroek * If all statistics entries have been used, give up and trigger an
108*00b67f09SDavid van Moolenbroek * assertion failure. There would be no other way to deal with this
109*00b67f09SDavid van Moolenbroek * because we'd like to keep record of all locks for the purpose of
110*00b67f09SDavid van Moolenbroek * debugging and the number of necessary locks is unpredictable.
111*00b67f09SDavid van Moolenbroek * If this failure is triggered while debugging, named should be
112*00b67f09SDavid van Moolenbroek * rebuilt with an increased ISC_MUTEX_PROFTABLESIZE.
113*00b67f09SDavid van Moolenbroek */
114*00b67f09SDavid van Moolenbroek RUNTIME_CHECK(stats_next < ISC_MUTEX_PROFTABLESIZE);
115*00b67f09SDavid van Moolenbroek mp->stats = &stats[stats_next++];
116*00b67f09SDavid van Moolenbroek
117*00b67f09SDavid van Moolenbroek RUNTIME_CHECK(pthread_mutex_unlock(&statslock) == 0);
118*00b67f09SDavid van Moolenbroek
119*00b67f09SDavid van Moolenbroek mp->stats->file = file;
120*00b67f09SDavid van Moolenbroek mp->stats->line = line;
121*00b67f09SDavid van Moolenbroek mp->stats->count = 0;
122*00b67f09SDavid van Moolenbroek timevalclear(&mp->stats->locked_total);
123*00b67f09SDavid van Moolenbroek timevalclear(&mp->stats->wait_total);
124*00b67f09SDavid van Moolenbroek for (i = 0; i < ISC_MUTEX_MAX_LOCKERS; i++) {
125*00b67f09SDavid van Moolenbroek mp->stats->lockers[i].file = NULL;
126*00b67f09SDavid van Moolenbroek mp->stats->lockers[i].line = 0;
127*00b67f09SDavid van Moolenbroek mp->stats->lockers[i].count = 0;
128*00b67f09SDavid van Moolenbroek timevalclear(&mp->stats->lockers[i].locked_total);
129*00b67f09SDavid van Moolenbroek timevalclear(&mp->stats->lockers[i].wait_total);
130*00b67f09SDavid van Moolenbroek }
131*00b67f09SDavid van Moolenbroek
132*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
133*00b67f09SDavid van Moolenbroek }
134*00b67f09SDavid van Moolenbroek
135*00b67f09SDavid van Moolenbroek isc_result_t
isc_mutex_lock_profile(isc_mutex_t * mp,const char * file,int line)136*00b67f09SDavid van Moolenbroek isc_mutex_lock_profile(isc_mutex_t *mp, const char *file, int line) {
137*00b67f09SDavid van Moolenbroek struct timeval prelock_t;
138*00b67f09SDavid van Moolenbroek struct timeval postlock_t;
139*00b67f09SDavid van Moolenbroek isc_mutexlocker_t *locker = NULL;
140*00b67f09SDavid van Moolenbroek int i;
141*00b67f09SDavid van Moolenbroek
142*00b67f09SDavid van Moolenbroek gettimeofday(&prelock_t, NULL);
143*00b67f09SDavid van Moolenbroek
144*00b67f09SDavid van Moolenbroek if (pthread_mutex_lock(&mp->mutex) != 0)
145*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTED);
146*00b67f09SDavid van Moolenbroek
147*00b67f09SDavid van Moolenbroek gettimeofday(&postlock_t, NULL);
148*00b67f09SDavid van Moolenbroek mp->stats->lock_t = postlock_t;
149*00b67f09SDavid van Moolenbroek
150*00b67f09SDavid van Moolenbroek timevalsub(&postlock_t, &prelock_t);
151*00b67f09SDavid van Moolenbroek
152*00b67f09SDavid van Moolenbroek mp->stats->count++;
153*00b67f09SDavid van Moolenbroek timevaladd(&mp->stats->wait_total, &postlock_t);
154*00b67f09SDavid van Moolenbroek
155*00b67f09SDavid van Moolenbroek for (i = 0; i < ISC_MUTEX_MAX_LOCKERS; i++) {
156*00b67f09SDavid van Moolenbroek if (mp->stats->lockers[i].file == NULL) {
157*00b67f09SDavid van Moolenbroek locker = &mp->stats->lockers[i];
158*00b67f09SDavid van Moolenbroek locker->file = file;
159*00b67f09SDavid van Moolenbroek locker->line = line;
160*00b67f09SDavid van Moolenbroek break;
161*00b67f09SDavid van Moolenbroek } else if (mp->stats->lockers[i].file == file &&
162*00b67f09SDavid van Moolenbroek mp->stats->lockers[i].line == line) {
163*00b67f09SDavid van Moolenbroek locker = &mp->stats->lockers[i];
164*00b67f09SDavid van Moolenbroek break;
165*00b67f09SDavid van Moolenbroek }
166*00b67f09SDavid van Moolenbroek }
167*00b67f09SDavid van Moolenbroek
168*00b67f09SDavid van Moolenbroek if (locker != NULL) {
169*00b67f09SDavid van Moolenbroek locker->count++;
170*00b67f09SDavid van Moolenbroek timevaladd(&locker->wait_total, &postlock_t);
171*00b67f09SDavid van Moolenbroek }
172*00b67f09SDavid van Moolenbroek
173*00b67f09SDavid van Moolenbroek mp->stats->cur_locker = locker;
174*00b67f09SDavid van Moolenbroek
175*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
176*00b67f09SDavid van Moolenbroek }
177*00b67f09SDavid van Moolenbroek
178*00b67f09SDavid van Moolenbroek isc_result_t
isc_mutex_unlock_profile(isc_mutex_t * mp,const char * file,int line)179*00b67f09SDavid van Moolenbroek isc_mutex_unlock_profile(isc_mutex_t *mp, const char *file, int line) {
180*00b67f09SDavid van Moolenbroek struct timeval unlock_t;
181*00b67f09SDavid van Moolenbroek
182*00b67f09SDavid van Moolenbroek UNUSED(file);
183*00b67f09SDavid van Moolenbroek UNUSED(line);
184*00b67f09SDavid van Moolenbroek
185*00b67f09SDavid van Moolenbroek if (mp->stats->cur_locker != NULL) {
186*00b67f09SDavid van Moolenbroek gettimeofday(&unlock_t, NULL);
187*00b67f09SDavid van Moolenbroek timevalsub(&unlock_t, &mp->stats->lock_t);
188*00b67f09SDavid van Moolenbroek timevaladd(&mp->stats->locked_total, &unlock_t);
189*00b67f09SDavid van Moolenbroek timevaladd(&mp->stats->cur_locker->locked_total, &unlock_t);
190*00b67f09SDavid van Moolenbroek mp->stats->cur_locker = NULL;
191*00b67f09SDavid van Moolenbroek }
192*00b67f09SDavid van Moolenbroek
193*00b67f09SDavid van Moolenbroek return ((pthread_mutex_unlock((&mp->mutex)) == 0) ? \
194*00b67f09SDavid van Moolenbroek ISC_R_SUCCESS : ISC_R_UNEXPECTED);
195*00b67f09SDavid van Moolenbroek }
196*00b67f09SDavid van Moolenbroek
197*00b67f09SDavid van Moolenbroek
198*00b67f09SDavid van Moolenbroek void
isc_mutex_statsprofile(FILE * fp)199*00b67f09SDavid van Moolenbroek isc_mutex_statsprofile(FILE *fp) {
200*00b67f09SDavid van Moolenbroek isc_mutexlocker_t *locker;
201*00b67f09SDavid van Moolenbroek int i, j;
202*00b67f09SDavid van Moolenbroek
203*00b67f09SDavid van Moolenbroek fprintf(fp, "Mutex stats (in us)\n");
204*00b67f09SDavid van Moolenbroek for (i = 0; i < stats_next; i++) {
205*00b67f09SDavid van Moolenbroek fprintf(fp, "%-12s %4d: %10u %lu.%06lu %lu.%06lu %5d\n",
206*00b67f09SDavid van Moolenbroek stats[i].file, stats[i].line, stats[i].count,
207*00b67f09SDavid van Moolenbroek stats[i].locked_total.tv_sec,
208*00b67f09SDavid van Moolenbroek stats[i].locked_total.tv_usec,
209*00b67f09SDavid van Moolenbroek stats[i].wait_total.tv_sec,
210*00b67f09SDavid van Moolenbroek stats[i].wait_total.tv_usec,
211*00b67f09SDavid van Moolenbroek i);
212*00b67f09SDavid van Moolenbroek for (j = 0; j < ISC_MUTEX_MAX_LOCKERS; j++) {
213*00b67f09SDavid van Moolenbroek locker = &stats[i].lockers[j];
214*00b67f09SDavid van Moolenbroek if (locker->file == NULL)
215*00b67f09SDavid van Moolenbroek continue;
216*00b67f09SDavid van Moolenbroek fprintf(fp, " %-11s %4d: %10u %lu.%06lu %lu.%06lu %5d\n",
217*00b67f09SDavid van Moolenbroek locker->file, locker->line, locker->count,
218*00b67f09SDavid van Moolenbroek locker->locked_total.tv_sec,
219*00b67f09SDavid van Moolenbroek locker->locked_total.tv_usec,
220*00b67f09SDavid van Moolenbroek locker->wait_total.tv_sec,
221*00b67f09SDavid van Moolenbroek locker->wait_total.tv_usec,
222*00b67f09SDavid van Moolenbroek i);
223*00b67f09SDavid van Moolenbroek }
224*00b67f09SDavid van Moolenbroek }
225*00b67f09SDavid van Moolenbroek }
226*00b67f09SDavid van Moolenbroek
227*00b67f09SDavid van Moolenbroek #endif /* ISC_MUTEX_PROFILE */
228*00b67f09SDavid van Moolenbroek
229*00b67f09SDavid van Moolenbroek #if ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK)
230*00b67f09SDavid van Moolenbroek isc_result_t
isc_mutex_init_errcheck(isc_mutex_t * mp)231*00b67f09SDavid van Moolenbroek isc_mutex_init_errcheck(isc_mutex_t *mp)
232*00b67f09SDavid van Moolenbroek {
233*00b67f09SDavid van Moolenbroek pthread_mutexattr_t attr;
234*00b67f09SDavid van Moolenbroek int err, errd;
235*00b67f09SDavid van Moolenbroek
236*00b67f09SDavid van Moolenbroek if (pthread_mutexattr_init(&attr) != 0)
237*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTED);
238*00b67f09SDavid van Moolenbroek
239*00b67f09SDavid van Moolenbroek if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) != 0) {
240*00b67f09SDavid van Moolenbroek errd = pthread_mutexattr_destroy(&attr);
241*00b67f09SDavid van Moolenbroek RUNTIME_CHECK(errd == 0);
242*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTED);
243*00b67f09SDavid van Moolenbroek }
244*00b67f09SDavid van Moolenbroek
245*00b67f09SDavid van Moolenbroek err = pthread_mutex_init(mp, &attr) != 0)
246*00b67f09SDavid van Moolenbroek errd = pthread_mutexattr_destroy(&attr);
247*00b67f09SDavid van Moolenbroek RUNTIME_CHECK(errd == 0);
248*00b67f09SDavid van Moolenbroek if (err == ENOMEM)
249*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
250*00b67f09SDavid van Moolenbroek return ((err == 0) ? ISC_R_SUCCESS : ISC_R_UNEXPECTED);
251*00b67f09SDavid van Moolenbroek }
252*00b67f09SDavid van Moolenbroek #endif
253*00b67f09SDavid van Moolenbroek
254*00b67f09SDavid van Moolenbroek #if ISC_MUTEX_DEBUG && defined(__NetBSD__) && defined(PTHREAD_MUTEX_ERRORCHECK)
255*00b67f09SDavid van Moolenbroek pthread_mutexattr_t isc__mutex_attrs = {
256*00b67f09SDavid van Moolenbroek PTHREAD_MUTEX_ERRORCHECK, /* m_type */
257*00b67f09SDavid van Moolenbroek 0 /* m_flags, which appears to be unused. */
258*00b67f09SDavid van Moolenbroek };
259*00b67f09SDavid van Moolenbroek #endif
260*00b67f09SDavid van Moolenbroek
261*00b67f09SDavid van Moolenbroek #if !(ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK)) && !ISC_MUTEX_PROFILE
262*00b67f09SDavid van Moolenbroek isc_result_t
isc__mutex_init(isc_mutex_t * mp,const char * file,unsigned int line)263*00b67f09SDavid van Moolenbroek isc__mutex_init(isc_mutex_t *mp, const char *file, unsigned int line) {
264*00b67f09SDavid van Moolenbroek char strbuf[ISC_STRERRORSIZE];
265*00b67f09SDavid van Moolenbroek isc_result_t result = ISC_R_SUCCESS;
266*00b67f09SDavid van Moolenbroek int err;
267*00b67f09SDavid van Moolenbroek #ifdef HAVE_PTHREAD_MUTEX_ADAPTIVE_NP
268*00b67f09SDavid van Moolenbroek pthread_mutexattr_t attr;
269*00b67f09SDavid van Moolenbroek int errd;
270*00b67f09SDavid van Moolenbroek
271*00b67f09SDavid van Moolenbroek if (pthread_mutexattr_init(&attr) != 0)
272*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTED);
273*00b67f09SDavid van Moolenbroek if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP) != 0) {
274*00b67f09SDavid van Moolenbroek errd = pthread_mutexattr_destroy(&attr);
275*00b67f09SDavid van Moolenbroek RUNTIME_CHECK(errd == 0);
276*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTED);
277*00b67f09SDavid van Moolenbroek }
278*00b67f09SDavid van Moolenbroek err = pthread_mutex_init(mp, &attr);
279*00b67f09SDavid van Moolenbroek errd = pthread_mutexattr_destroy(&attr);
280*00b67f09SDavid van Moolenbroek RUNTIME_CHECK(errd == 0);
281*00b67f09SDavid van Moolenbroek #else /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP */
282*00b67f09SDavid van Moolenbroek err = pthread_mutex_init(mp, ISC__MUTEX_ATTRS);
283*00b67f09SDavid van Moolenbroek #endif /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP */
284*00b67f09SDavid van Moolenbroek
285*00b67f09SDavid van Moolenbroek if (err == ENOMEM)
286*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
287*00b67f09SDavid van Moolenbroek if (err != 0) {
288*00b67f09SDavid van Moolenbroek isc__strerror(err, strbuf, sizeof(strbuf));
289*00b67f09SDavid van Moolenbroek UNEXPECTED_ERROR(file, line, "isc_mutex_init() failed: %s",
290*00b67f09SDavid van Moolenbroek strbuf);
291*00b67f09SDavid van Moolenbroek result = ISC_R_UNEXPECTED;
292*00b67f09SDavid van Moolenbroek }
293*00b67f09SDavid van Moolenbroek return (result);
294*00b67f09SDavid van Moolenbroek }
295*00b67f09SDavid van Moolenbroek #endif
296