diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 18:37:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 18:37:14 +0000 |
commit | ea648e70a989cca190cd7403fe892fd2dcc290b4 (patch) | |
tree | e2b6b1c647da68b0d4d66082835e256eb30970e8 /lib/isc/pthreads | |
parent | Initial commit. (diff) | |
download | bind9-upstream.tar.xz bind9-upstream.zip |
Adding upstream version 1:9.11.5.P4+dfsg.upstream/1%9.11.5.P4+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | lib/isc/pthreads/Makefile.in | 30 | ||||
-rw-r--r-- | lib/isc/pthreads/condition.c | 74 | ||||
-rw-r--r-- | lib/isc/pthreads/include/Makefile.in | 17 | ||||
-rw-r--r-- | lib/isc/pthreads/include/isc/Makefile.in | 34 | ||||
-rw-r--r-- | lib/isc/pthreads/include/isc/condition.h | 58 | ||||
-rw-r--r-- | lib/isc/pthreads/include/isc/mutex.h | 138 | ||||
-rw-r--r-- | lib/isc/pthreads/include/isc/once.h | 43 | ||||
-rw-r--r-- | lib/isc/pthreads/include/isc/thread.h | 63 | ||||
-rw-r--r-- | lib/isc/pthreads/mutex.c | 302 | ||||
-rw-r--r-- | lib/isc/pthreads/thread.c | 103 |
10 files changed, 862 insertions, 0 deletions
diff --git a/lib/isc/pthreads/Makefile.in b/lib/isc/pthreads/Makefile.in new file mode 100644 index 0000000..af4fd6e --- /dev/null +++ b/lib/isc/pthreads/Makefile.in @@ -0,0 +1,30 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +CINCLUDES = -I${srcdir}/include \ + -I${srcdir}/../unix/include \ + -I../include \ + -I${srcdir}/../include \ + -I${srcdir}/.. + +CDEFINES = +CWARNINGS = + +OBJS = condition.@O@ mutex.@O@ thread.@O@ + +SRCS = condition.c mutex.c thread.c + +SUBDIRS = include +TARGETS = ${OBJS} + +@BIND9_MAKE_RULES@ diff --git a/lib/isc/pthreads/condition.c b/lib/isc/pthreads/condition.c new file mode 100644 index 0000000..a7f1928 --- /dev/null +++ b/lib/isc/pthreads/condition.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + + +/*! \file */ + +#include <config.h> + +#include <errno.h> + +#include <isc/condition.h> +#include <isc/msgs.h> +#include <isc/strerror.h> +#include <isc/string.h> +#include <isc/time.h> +#include <isc/util.h> + +isc_result_t +isc_condition_waituntil(isc_condition_t *c, isc_mutex_t *m, isc_time_t *t) { + int presult; + isc_result_t result; + struct timespec ts; + char strbuf[ISC_STRERRORSIZE]; + + REQUIRE(c != NULL && m != NULL && t != NULL); + + /* + * POSIX defines a timespec's tv_sec as time_t. + */ + result = isc_time_secondsastimet(t, &ts.tv_sec); + + /* + * If we have a range error ts.tv_sec is most probably a signed + * 32 bit value. Set ts.tv_sec to INT_MAX. This is a kludge. + */ + if (result == ISC_R_RANGE) + ts.tv_sec = INT_MAX; + else if (result != ISC_R_SUCCESS) + return (result); + + /*! + * POSIX defines a timespec's tv_nsec as long. isc_time_nanoseconds + * ensures its return value is < 1 billion, which will fit in a long. + */ + ts.tv_nsec = (long)isc_time_nanoseconds(t); + + do { +#if ISC_MUTEX_PROFILE + presult = pthread_cond_timedwait(c, &m->mutex, &ts); +#else + presult = pthread_cond_timedwait(c, m, &ts); +#endif + if (presult == 0) + return (ISC_R_SUCCESS); + if (presult == ETIMEDOUT) + return (ISC_R_TIMEDOUT); + } while (presult == EINTR); + + isc__strerror(presult, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "pthread_cond_timedwait() %s %s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_RETURNED, "returned"), + strbuf); + return (ISC_R_UNEXPECTED); +} diff --git a/lib/isc/pthreads/include/Makefile.in b/lib/isc/pthreads/include/Makefile.in new file mode 100644 index 0000000..d33c0fc --- /dev/null +++ b/lib/isc/pthreads/include/Makefile.in @@ -0,0 +1,17 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +SUBDIRS = isc +TARGETS = + +@BIND9_MAKE_RULES@ diff --git a/lib/isc/pthreads/include/isc/Makefile.in b/lib/isc/pthreads/include/isc/Makefile.in new file mode 100644 index 0000000..185534f --- /dev/null +++ b/lib/isc/pthreads/include/isc/Makefile.in @@ -0,0 +1,34 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +VERSION=@BIND9_VERSION@ + +HEADERS = condition.h mutex.h once.h thread.h + +SUBDIRS = +TARGETS = + +@BIND9_MAKE_RULES@ + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc + +install:: installdirs + for i in ${HEADERS}; do \ + ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/isc || exit 1; \ + done + +uninstall:: + for i in ${HEADERS}; do \ + rm -f ${DESTDIR}${includedir}/isc/$$i || exit 1; \ + done diff --git a/lib/isc/pthreads/include/isc/condition.h b/lib/isc/pthreads/include/isc/condition.h new file mode 100644 index 0000000..28338c7 --- /dev/null +++ b/lib/isc/pthreads/include/isc/condition.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + + +#ifndef ISC_CONDITION_H +#define ISC_CONDITION_H 1 + +/*! \file */ + +#include <isc/lang.h> +#include <isc/mutex.h> +#include <isc/result.h> +#include <isc/types.h> + +typedef pthread_cond_t isc_condition_t; + +#define isc_condition_init(cp) \ + ((pthread_cond_init((cp), NULL) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) + +#if ISC_MUTEX_PROFILE +#define isc_condition_wait(cp, mp) \ + ((pthread_cond_wait((cp), &((mp)->mutex)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) +#else +#define isc_condition_wait(cp, mp) \ + ((pthread_cond_wait((cp), (mp)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) +#endif + +#define isc_condition_signal(cp) \ + ((pthread_cond_signal((cp)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) + +#define isc_condition_broadcast(cp) \ + ((pthread_cond_broadcast((cp)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) + +#define isc_condition_destroy(cp) \ + ((pthread_cond_destroy((cp)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) + +ISC_LANG_BEGINDECLS + +isc_result_t +isc_condition_waituntil(isc_condition_t *, isc_mutex_t *, isc_time_t *); + +ISC_LANG_ENDDECLS + +#endif /* ISC_CONDITION_H */ diff --git a/lib/isc/pthreads/include/isc/mutex.h b/lib/isc/pthreads/include/isc/mutex.h new file mode 100644 index 0000000..6c34a69 --- /dev/null +++ b/lib/isc/pthreads/include/isc/mutex.h @@ -0,0 +1,138 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + + +#ifndef ISC_MUTEX_H +#define ISC_MUTEX_H 1 + +/*! \file */ + +#include <pthread.h> +#include <stdio.h> + +#include <isc/lang.h> +#include <isc/result.h> /* for ISC_R_ codes */ + +ISC_LANG_BEGINDECLS + +/*! + * Supply mutex attributes that enable deadlock detection + * (helpful when debugging). This is system dependent and + * currently only supported on NetBSD. + */ +#if ISC_MUTEX_DEBUG && defined(__NetBSD__) && defined(PTHREAD_MUTEX_ERRORCHECK) +extern pthread_mutexattr_t isc__mutex_attrs; +#define ISC__MUTEX_ATTRS &isc__mutex_attrs +#else +#define ISC__MUTEX_ATTRS NULL +#endif + +/* XXX We could do fancier error handling... */ + +/*! + * Define ISC_MUTEX_PROFILE to turn on profiling of mutexes by line. When + * enabled, isc_mutex_stats() can be used to print a table showing the + * number of times each type of mutex was locked and the amount of time + * waiting to obtain the lock. + */ +#ifndef ISC_MUTEX_PROFILE +#define ISC_MUTEX_PROFILE 0 +#endif + +#if ISC_MUTEX_PROFILE +typedef struct isc_mutexstats isc_mutexstats_t; + +typedef struct { + pthread_mutex_t mutex; /*%< The actual mutex. */ + isc_mutexstats_t * stats; /*%< Mutex statistics. */ +} isc_mutex_t; +#else +typedef pthread_mutex_t isc_mutex_t; +#endif + + +#if ISC_MUTEX_PROFILE +#define isc_mutex_init(mp) \ + isc_mutex_init_profile((mp), __FILE__, __LINE__) +#else +#if ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK) +#define isc_mutex_init(mp) \ + isc_mutex_init_errcheck((mp)) +#else +#define isc_mutex_init(mp) \ + isc__mutex_init((mp), __FILE__, __LINE__) +isc_result_t isc__mutex_init(isc_mutex_t *mp, const char *file, unsigned int line); +#endif +#endif + +#if ISC_MUTEX_PROFILE +#define isc_mutex_lock(mp) \ + isc_mutex_lock_profile((mp), __FILE__, __LINE__) +#else +#define isc_mutex_lock(mp) \ + ((pthread_mutex_lock((mp)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) +#endif + +#if ISC_MUTEX_PROFILE +#define isc_mutex_unlock(mp) \ + isc_mutex_unlock_profile((mp), __FILE__, __LINE__) +#else +#define isc_mutex_unlock(mp) \ + ((pthread_mutex_unlock((mp)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) +#endif + +#if ISC_MUTEX_PROFILE +#define isc_mutex_trylock(mp) \ + ((pthread_mutex_trylock((&(mp)->mutex)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_LOCKBUSY) +#else +#define isc_mutex_trylock(mp) \ + ((pthread_mutex_trylock((mp)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_LOCKBUSY) +#endif + +#if ISC_MUTEX_PROFILE +#define isc_mutex_destroy(mp) \ + ((pthread_mutex_destroy((&(mp)->mutex)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) +#else +#define isc_mutex_destroy(mp) \ + ((pthread_mutex_destroy((mp)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) +#endif + +#if ISC_MUTEX_PROFILE +#define isc_mutex_stats(fp) isc_mutex_statsprofile(fp); +#else +#define isc_mutex_stats(fp) +#endif + +#if ISC_MUTEX_PROFILE + +isc_result_t +isc_mutex_init_profile(isc_mutex_t *mp, const char * _file, int _line); +isc_result_t +isc_mutex_lock_profile(isc_mutex_t *mp, const char * _file, int _line); +isc_result_t +isc_mutex_unlock_profile(isc_mutex_t *mp, const char * _file, int _line); + +void +isc_mutex_statsprofile(FILE *fp); + +isc_result_t +isc_mutex_init_errcheck(isc_mutex_t *mp); + +#endif /* ISC_MUTEX_PROFILE */ + +ISC_LANG_ENDDECLS +#endif /* ISC_MUTEX_H */ diff --git a/lib/isc/pthreads/include/isc/once.h b/lib/isc/pthreads/include/isc/once.h new file mode 100644 index 0000000..a0e9559 --- /dev/null +++ b/lib/isc/pthreads/include/isc/once.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + + +#ifndef ISC_ONCE_H +#define ISC_ONCE_H 1 + +/*! \file */ + +#include <pthread.h> + +#include <isc/platform.h> +#include <isc/result.h> + +typedef pthread_once_t isc_once_t; + +#ifdef ISC_PLATFORM_BRACEPTHREADONCEINIT +/*! + * This accomodates systems that define PTHRAD_ONCE_INIT improperly. + */ +#define ISC_ONCE_INIT { PTHREAD_ONCE_INIT } +#else +/*! + * This is the usual case. + */ +#define ISC_ONCE_INIT PTHREAD_ONCE_INIT +#endif + +/* XXX We could do fancier error handling... */ + +#define isc_once_do(op, f) \ + ((pthread_once((op), (f)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) + +#endif /* ISC_ONCE_H */ diff --git a/lib/isc/pthreads/include/isc/thread.h b/lib/isc/pthreads/include/isc/thread.h new file mode 100644 index 0000000..798af33 --- /dev/null +++ b/lib/isc/pthreads/include/isc/thread.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + + +#ifndef ISC_THREAD_H +#define ISC_THREAD_H 1 + +/*! \file */ + +#include <pthread.h> + +#if defined(HAVE_PTHREAD_NP_H) +#include <pthread_np.h> +#endif + +#include <isc/lang.h> +#include <isc/result.h> + +ISC_LANG_BEGINDECLS + +typedef pthread_t isc_thread_t; +typedef void * isc_threadresult_t; +typedef void * isc_threadarg_t; +typedef isc_threadresult_t (*isc_threadfunc_t)(isc_threadarg_t); +typedef pthread_key_t isc_thread_key_t; + +isc_result_t +isc_thread_create(isc_threadfunc_t, isc_threadarg_t, isc_thread_t *); + +void +isc_thread_setconcurrency(unsigned int level); + +void +isc_thread_yield(void); + +void +isc_thread_setname(isc_thread_t thread, const char *name); + +/* XXX We could do fancier error handling... */ + +#define isc_thread_join(t, rp) \ + ((pthread_join((t), (rp)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) + +#define isc_thread_self \ + (unsigned long)pthread_self + +#define isc_thread_key_create pthread_key_create +#define isc_thread_key_getspecific pthread_getspecific +#define isc_thread_key_setspecific pthread_setspecific +#define isc_thread_key_delete pthread_key_delete + +ISC_LANG_ENDDECLS + +#endif /* ISC_THREAD_H */ diff --git a/lib/isc/pthreads/mutex.c b/lib/isc/pthreads/mutex.c new file mode 100644 index 0000000..cd45e6b --- /dev/null +++ b/lib/isc/pthreads/mutex.c @@ -0,0 +1,302 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + + +/*! \file */ + +#include <config.h> + +#include <stdbool.h> +#include <stdio.h> +#include <time.h> +#include <sys/time.h> +#include <errno.h> + +#include <isc/mutex.h> +#include <isc/util.h> +#include <isc/print.h> +#include <isc/strerror.h> +#include <isc/once.h> + +#if ISC_MUTEX_PROFILE + +/*@{*/ +/*% Operations on timevals; adapted from FreeBSD's sys/time.h */ +#define timevalclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0) +#define timevaladd(vvp, uvp) \ + do { \ + (vvp)->tv_sec += (uvp)->tv_sec; \ + (vvp)->tv_usec += (uvp)->tv_usec; \ + if ((vvp)->tv_usec >= 1000000) { \ + (vvp)->tv_sec++; \ + (vvp)->tv_usec -= 1000000; \ + } \ + } while (0) +#define timevalsub(vvp, uvp) \ + do { \ + (vvp)->tv_sec -= (uvp)->tv_sec; \ + (vvp)->tv_usec -= (uvp)->tv_usec; \ + if ((vvp)->tv_usec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_usec += 1000000; \ + } \ + } while (0) + +/*@}*/ + +#define ISC_MUTEX_MAX_LOCKERS 32 + +typedef struct { + const char * file; + int line; + unsigned count; + struct timeval locked_total; + struct timeval wait_total; +} isc_mutexlocker_t; + +struct isc_mutexstats { + const char * file; /*%< File mutex was created in. */ + int line; /*%< Line mutex was created on. */ + unsigned count; + struct timeval lock_t; + struct timeval locked_total; + struct timeval wait_total; + isc_mutexlocker_t * cur_locker; + isc_mutexlocker_t lockers[ISC_MUTEX_MAX_LOCKERS]; +}; + +#ifndef ISC_MUTEX_PROFTABLESIZE +#define ISC_MUTEX_PROFTABLESIZE (1024 * 1024) +#endif +static isc_mutexstats_t stats[ISC_MUTEX_PROFTABLESIZE]; +static int stats_next = 0; +static bool stats_init = false; +static pthread_mutex_t statslock = PTHREAD_MUTEX_INITIALIZER; + + +isc_result_t +isc_mutex_init_profile(isc_mutex_t *mp, const char *file, int line) { + int i, err; + + err = pthread_mutex_init(&mp->mutex, NULL); + if (err == ENOMEM) + return (ISC_R_NOMEMORY); + if (err != 0) + return (ISC_R_UNEXPECTED); + + RUNTIME_CHECK(pthread_mutex_lock(&statslock) == 0); + + if (stats_init == false) + stats_init = true; + + /* + * If all statistics entries have been used, give up and trigger an + * assertion failure. There would be no other way to deal with this + * because we'd like to keep record of all locks for the purpose of + * debugging and the number of necessary locks is unpredictable. + * If this failure is triggered while debugging, named should be + * rebuilt with an increased ISC_MUTEX_PROFTABLESIZE. + */ + RUNTIME_CHECK(stats_next < ISC_MUTEX_PROFTABLESIZE); + mp->stats = &stats[stats_next++]; + + RUNTIME_CHECK(pthread_mutex_unlock(&statslock) == 0); + + mp->stats->file = file; + mp->stats->line = line; + mp->stats->count = 0; + timevalclear(&mp->stats->locked_total); + timevalclear(&mp->stats->wait_total); + for (i = 0; i < ISC_MUTEX_MAX_LOCKERS; i++) { + mp->stats->lockers[i].file = NULL; + mp->stats->lockers[i].line = 0; + mp->stats->lockers[i].count = 0; + timevalclear(&mp->stats->lockers[i].locked_total); + timevalclear(&mp->stats->lockers[i].wait_total); + } + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_mutex_lock_profile(isc_mutex_t *mp, const char *file, int line) { + struct timeval prelock_t; + struct timeval postlock_t; + isc_mutexlocker_t *locker = NULL; + int i; + + gettimeofday(&prelock_t, NULL); + + if (pthread_mutex_lock(&mp->mutex) != 0) + return (ISC_R_UNEXPECTED); + + gettimeofday(&postlock_t, NULL); + mp->stats->lock_t = postlock_t; + + timevalsub(&postlock_t, &prelock_t); + + mp->stats->count++; + timevaladd(&mp->stats->wait_total, &postlock_t); + + for (i = 0; i < ISC_MUTEX_MAX_LOCKERS; i++) { + if (mp->stats->lockers[i].file == NULL) { + locker = &mp->stats->lockers[i]; + locker->file = file; + locker->line = line; + break; + } else if (mp->stats->lockers[i].file == file && + mp->stats->lockers[i].line == line) { + locker = &mp->stats->lockers[i]; + break; + } + } + + if (locker != NULL) { + locker->count++; + timevaladd(&locker->wait_total, &postlock_t); + } + + mp->stats->cur_locker = locker; + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_mutex_unlock_profile(isc_mutex_t *mp, const char *file, int line) { + struct timeval unlock_t; + + UNUSED(file); + UNUSED(line); + + if (mp->stats->cur_locker != NULL) { + gettimeofday(&unlock_t, NULL); + timevalsub(&unlock_t, &mp->stats->lock_t); + timevaladd(&mp->stats->locked_total, &unlock_t); + timevaladd(&mp->stats->cur_locker->locked_total, &unlock_t); + mp->stats->cur_locker = NULL; + } + + return ((pthread_mutex_unlock((&mp->mutex)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED); +} + + +void +isc_mutex_statsprofile(FILE *fp) { + isc_mutexlocker_t *locker; + int i, j; + + fprintf(fp, "Mutex stats (in us)\n"); + for (i = 0; i < stats_next; i++) { + fprintf(fp, "%-12s %4d: %10u %lu.%06lu %lu.%06lu %5d\n", + stats[i].file, stats[i].line, stats[i].count, + stats[i].locked_total.tv_sec, + stats[i].locked_total.tv_usec, + stats[i].wait_total.tv_sec, + stats[i].wait_total.tv_usec, + i); + for (j = 0; j < ISC_MUTEX_MAX_LOCKERS; j++) { + locker = &stats[i].lockers[j]; + if (locker->file == NULL) + continue; + fprintf(fp, " %-11s %4d: %10u %lu.%06lu %lu.%06lu %5d\n", + locker->file, locker->line, locker->count, + locker->locked_total.tv_sec, + locker->locked_total.tv_usec, + locker->wait_total.tv_sec, + locker->wait_total.tv_usec, + i); + } + } +} + +#endif /* ISC_MUTEX_PROFILE */ + +#if ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK) + +static bool errcheck_initialized = false; +static pthread_mutexattr_t errcheck; +static isc_once_t once_errcheck = ISC_ONCE_INIT; + +static void +initialize_errcheck(void) { + RUNTIME_CHECK(pthread_mutexattr_init(&errcheck) == 0); + RUNTIME_CHECK(pthread_mutexattr_settype + (&errcheck, PTHREAD_MUTEX_ERRORCHECK) == 0); + errcheck_initialized = true; +} + +isc_result_t +isc_mutex_init_errcheck(isc_mutex_t *mp) { + isc_result_t result; + int err; + + result = isc_once_do(&once_errcheck, initialize_errcheck); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + err = pthread_mutex_init(mp, &errcheck); + if (err == ENOMEM) + return (ISC_R_NOMEMORY); + return ((err == 0) ? ISC_R_SUCCESS : ISC_R_UNEXPECTED); +} +#endif + +#if ISC_MUTEX_DEBUG && defined(__NetBSD__) && defined(PTHREAD_MUTEX_ERRORCHECK) +pthread_mutexattr_t isc__mutex_attrs = { + PTHREAD_MUTEX_ERRORCHECK, /* m_type */ + 0 /* m_flags, which appears to be unused. */ +}; +#endif + +#if !(ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK)) && !ISC_MUTEX_PROFILE + +#ifdef HAVE_PTHREAD_MUTEX_ADAPTIVE_NP +static bool attr_initialized = false; +static pthread_mutexattr_t attr; +static isc_once_t once_attr = ISC_ONCE_INIT; +#endif /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP */ + +#ifdef HAVE_PTHREAD_MUTEX_ADAPTIVE_NP +static void +initialize_attr(void) { + RUNTIME_CHECK(pthread_mutexattr_init(&attr) == 0); + RUNTIME_CHECK(pthread_mutexattr_settype + (&attr, PTHREAD_MUTEX_ADAPTIVE_NP) == 0); + attr_initialized = true; +} +#endif /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP */ + +isc_result_t +isc__mutex_init(isc_mutex_t *mp, const char *file, unsigned int line) { + char strbuf[ISC_STRERRORSIZE]; + isc_result_t result = ISC_R_SUCCESS; + int err; + +#ifdef HAVE_PTHREAD_MUTEX_ADAPTIVE_NP + result = isc_once_do(&once_attr, initialize_attr); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + err = pthread_mutex_init(mp, &attr); +#else /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP */ + err = pthread_mutex_init(mp, ISC__MUTEX_ATTRS); +#endif /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP */ + + if (err == ENOMEM) + return (ISC_R_NOMEMORY); + if (err != 0) { + isc__strerror(err, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(file, line, "isc_mutex_init() failed: %s", + strbuf); + result = ISC_R_UNEXPECTED; + } + return (result); +} +#endif diff --git a/lib/isc/pthreads/thread.c b/lib/isc/pthreads/thread.c new file mode 100644 index 0000000..94fb2c2 --- /dev/null +++ b/lib/isc/pthreads/thread.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + + +/*! \file */ + +#include <config.h> + +#if defined(HAVE_SCHED_H) +#include <sched.h> +#endif + +#include <isc/thread.h> +#include <isc/util.h> + +#ifndef THREAD_MINSTACKSIZE +#define THREAD_MINSTACKSIZE (1024U * 1024) +#endif + +isc_result_t +isc_thread_create(isc_threadfunc_t func, isc_threadarg_t arg, + isc_thread_t *thread) +{ + pthread_attr_t attr; +#if defined(HAVE_PTHREAD_ATTR_GETSTACKSIZE) && \ + defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE) + size_t stacksize; +#endif + int ret; + + pthread_attr_init(&attr); + +#if defined(HAVE_PTHREAD_ATTR_GETSTACKSIZE) && \ + defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE) + ret = pthread_attr_getstacksize(&attr, &stacksize); + if (ret != 0) + return (ISC_R_UNEXPECTED); + + if (stacksize < THREAD_MINSTACKSIZE) { + ret = pthread_attr_setstacksize(&attr, THREAD_MINSTACKSIZE); + if (ret != 0) + return (ISC_R_UNEXPECTED); + } +#endif + +#if defined(PTHREAD_SCOPE_SYSTEM) && defined(NEED_PTHREAD_SCOPE_SYSTEM) + ret = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); + if (ret != 0) + return (ISC_R_UNEXPECTED); +#endif + + ret = pthread_create(thread, &attr, func, arg); + if (ret != 0) + return (ISC_R_UNEXPECTED); + + pthread_attr_destroy(&attr); + + return (ISC_R_SUCCESS); +} + +void +isc_thread_setconcurrency(unsigned int level) { +#if defined(CALL_PTHREAD_SETCONCURRENCY) + (void)pthread_setconcurrency(level); +#else + UNUSED(level); +#endif +} + +void +isc_thread_setname(isc_thread_t thread, const char *name) { +#if defined(HAVE_PTHREAD_SETNAME_NP) && defined(_GNU_SOURCE) + /* + * macOS has pthread_setname_np but only works on the + * current thread so it's not used here + */ + (void)pthread_setname_np(thread, name); +#elif defined(HAVE_PTHREAD_SET_NAME_NP) + (void)pthread_set_name_np(thread, name); +#else + UNUSED(thread); + UNUSED(name); +#endif +} + +void +isc_thread_yield(void) { +#if defined(HAVE_SCHED_YIELD) + sched_yield(); +#elif defined( HAVE_PTHREAD_YIELD) + pthread_yield(); +#elif defined( HAVE_PTHREAD_YIELD_NP) + pthread_yield_np(); +#endif +} |