"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.11.23/lib/isc/pthreads/mutex.c" (7 Sep 2020, 7955 Bytes) of package /linux/misc/dns/bind9/9.11.23/bind-9.11.23.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "mutex.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
    3  *
    4  * This Source Code Form is subject to the terms of the Mozilla Public
    5  * License, v. 2.0. If a copy of the MPL was not distributed with this
    6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    7  *
    8  * See the COPYRIGHT file distributed with this work for additional
    9  * information regarding copyright ownership.
   10  */
   11 
   12 
   13 /*! \file */
   14 
   15 #include <config.h>
   16 
   17 #include <stdbool.h>
   18 #include <stdio.h>
   19 #include <time.h>
   20 #include <sys/time.h>
   21 #include <errno.h>
   22 
   23 #include <isc/mutex.h>
   24 #include <isc/util.h>
   25 #include <isc/print.h>
   26 #include <isc/strerror.h>
   27 #include <isc/once.h>
   28 
   29 #if ISC_MUTEX_PROFILE
   30 
   31 /*@{*/
   32 /*% Operations on timevals; adapted from FreeBSD's sys/time.h */
   33 #define timevalclear(tvp)      ((tvp)->tv_sec = (tvp)->tv_usec = 0)
   34 #define timevaladd(vvp, uvp)                        \
   35     do {                                \
   36         (vvp)->tv_sec += (uvp)->tv_sec;             \
   37         (vvp)->tv_usec += (uvp)->tv_usec;           \
   38         if ((vvp)->tv_usec >= 1000000) {            \
   39             (vvp)->tv_sec++;                \
   40             (vvp)->tv_usec -= 1000000;          \
   41         }                           \
   42     } while (0)
   43 #define timevalsub(vvp, uvp)                        \
   44     do {                                \
   45         (vvp)->tv_sec -= (uvp)->tv_sec;             \
   46         (vvp)->tv_usec -= (uvp)->tv_usec;           \
   47         if ((vvp)->tv_usec < 0) {               \
   48             (vvp)->tv_sec--;                \
   49             (vvp)->tv_usec += 1000000;          \
   50         }                           \
   51     } while (0)
   52 
   53 /*@}*/
   54 
   55 #define ISC_MUTEX_MAX_LOCKERS 32
   56 
   57 typedef struct {
   58     const char *        file;
   59     int         line;
   60     unsigned        count;
   61     struct timeval      locked_total;
   62     struct timeval      wait_total;
   63 } isc_mutexlocker_t;
   64 
   65 struct isc_mutexstats {
   66     const char *        file;   /*%< File mutex was created in. */
   67     int         line;   /*%< Line mutex was created on. */
   68     unsigned        count;
   69     struct timeval      lock_t;
   70     struct timeval      locked_total;
   71     struct timeval      wait_total;
   72     isc_mutexlocker_t * cur_locker;
   73     isc_mutexlocker_t   lockers[ISC_MUTEX_MAX_LOCKERS];
   74 };
   75 
   76 #ifndef ISC_MUTEX_PROFTABLESIZE
   77 #define ISC_MUTEX_PROFTABLESIZE (1024 * 1024)
   78 #endif
   79 static isc_mutexstats_t stats[ISC_MUTEX_PROFTABLESIZE];
   80 static int stats_next = 0;
   81 static bool stats_init = false;
   82 static pthread_mutex_t statslock = PTHREAD_MUTEX_INITIALIZER;
   83 
   84 
   85 isc_result_t
   86 isc_mutex_init_profile(isc_mutex_t *mp, const char *file, int line) {
   87     int i, err;
   88 
   89     err = pthread_mutex_init(&mp->mutex, NULL);
   90     if (err == ENOMEM)
   91         return (ISC_R_NOMEMORY);
   92     if (err != 0)
   93         return (ISC_R_UNEXPECTED);
   94 
   95     RUNTIME_CHECK(pthread_mutex_lock(&statslock) == 0);
   96 
   97     if (stats_init == false)
   98         stats_init = true;
   99 
  100     /*
  101      * If all statistics entries have been used, give up and trigger an
  102      * assertion failure.  There would be no other way to deal with this
  103      * because we'd like to keep record of all locks for the purpose of
  104      * debugging and the number of necessary locks is unpredictable.
  105      * If this failure is triggered while debugging, named should be
  106      * rebuilt with an increased ISC_MUTEX_PROFTABLESIZE.
  107      */
  108     RUNTIME_CHECK(stats_next < ISC_MUTEX_PROFTABLESIZE);
  109     mp->stats = &stats[stats_next++];
  110 
  111     RUNTIME_CHECK(pthread_mutex_unlock(&statslock) == 0);
  112 
  113     mp->stats->file = file;
  114     mp->stats->line = line;
  115     mp->stats->count = 0;
  116     timevalclear(&mp->stats->locked_total);
  117     timevalclear(&mp->stats->wait_total);
  118     for (i = 0; i < ISC_MUTEX_MAX_LOCKERS; i++) {
  119         mp->stats->lockers[i].file = NULL;
  120         mp->stats->lockers[i].line = 0;
  121         mp->stats->lockers[i].count = 0;
  122         timevalclear(&mp->stats->lockers[i].locked_total);
  123         timevalclear(&mp->stats->lockers[i].wait_total);
  124     }
  125 
  126     return (ISC_R_SUCCESS);
  127 }
  128 
  129 isc_result_t
  130 isc_mutex_lock_profile(isc_mutex_t *mp, const char *file, int line) {
  131     struct timeval prelock_t;
  132     struct timeval postlock_t;
  133     isc_mutexlocker_t *locker = NULL;
  134     int i;
  135 
  136     gettimeofday(&prelock_t, NULL);
  137 
  138     if (pthread_mutex_lock(&mp->mutex) != 0)
  139         return (ISC_R_UNEXPECTED);
  140 
  141     gettimeofday(&postlock_t, NULL);
  142     mp->stats->lock_t = postlock_t;
  143 
  144     timevalsub(&postlock_t, &prelock_t);
  145 
  146     mp->stats->count++;
  147     timevaladd(&mp->stats->wait_total, &postlock_t);
  148 
  149     for (i = 0; i < ISC_MUTEX_MAX_LOCKERS; i++) {
  150         if (mp->stats->lockers[i].file == NULL) {
  151             locker = &mp->stats->lockers[i];
  152             locker->file = file;
  153             locker->line = line;
  154             break;
  155         } else if (mp->stats->lockers[i].file == file &&
  156                mp->stats->lockers[i].line == line) {
  157             locker = &mp->stats->lockers[i];
  158             break;
  159         }
  160     }
  161 
  162     if (locker != NULL) {
  163         locker->count++;
  164         timevaladd(&locker->wait_total, &postlock_t);
  165     }
  166 
  167     mp->stats->cur_locker = locker;
  168 
  169     return (ISC_R_SUCCESS);
  170 }
  171 
  172 isc_result_t
  173 isc_mutex_unlock_profile(isc_mutex_t *mp, const char *file, int line) {
  174     struct timeval unlock_t;
  175 
  176     UNUSED(file);
  177     UNUSED(line);
  178 
  179     if (mp->stats->cur_locker != NULL) {
  180         gettimeofday(&unlock_t, NULL);
  181         timevalsub(&unlock_t, &mp->stats->lock_t);
  182         timevaladd(&mp->stats->locked_total, &unlock_t);
  183         timevaladd(&mp->stats->cur_locker->locked_total, &unlock_t);
  184         mp->stats->cur_locker = NULL;
  185     }
  186 
  187     return ((pthread_mutex_unlock((&mp->mutex)) == 0) ? \
  188         ISC_R_SUCCESS : ISC_R_UNEXPECTED);
  189 }
  190 
  191 
  192 void
  193 isc_mutex_statsprofile(FILE *fp) {
  194     isc_mutexlocker_t *locker;
  195     int i, j;
  196 
  197     fprintf(fp, "Mutex stats (in us)\n");
  198     for (i = 0; i < stats_next; i++) {
  199         fprintf(fp, "%-12s %4d: %10u  %lu.%06lu %lu.%06lu %5d\n",
  200             stats[i].file, stats[i].line, stats[i].count,
  201             stats[i].locked_total.tv_sec,
  202             stats[i].locked_total.tv_usec,
  203             stats[i].wait_total.tv_sec,
  204             stats[i].wait_total.tv_usec,
  205             i);
  206         for (j = 0; j < ISC_MUTEX_MAX_LOCKERS; j++) {
  207             locker = &stats[i].lockers[j];
  208             if (locker->file == NULL)
  209                 continue;
  210             fprintf(fp, " %-11s %4d: %10u  %lu.%06lu %lu.%06lu %5d\n",
  211                 locker->file, locker->line, locker->count,
  212                 locker->locked_total.tv_sec,
  213                 locker->locked_total.tv_usec,
  214                 locker->wait_total.tv_sec,
  215                 locker->wait_total.tv_usec,
  216                 i);
  217         }
  218     }
  219 }
  220 
  221 #endif /* ISC_MUTEX_PROFILE */
  222 
  223 #if ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK)
  224 
  225 static bool errcheck_initialized = false;
  226 static pthread_mutexattr_t errcheck;
  227 static isc_once_t once_errcheck = ISC_ONCE_INIT;
  228 
  229 static void
  230 initialize_errcheck(void) {
  231     RUNTIME_CHECK(pthread_mutexattr_init(&errcheck) == 0);
  232     RUNTIME_CHECK(pthread_mutexattr_settype
  233               (&errcheck, PTHREAD_MUTEX_ERRORCHECK) == 0);
  234     errcheck_initialized = true;
  235 }
  236 
  237 isc_result_t
  238 isc_mutex_init_errcheck(isc_mutex_t *mp) {
  239     isc_result_t result;
  240     int err;
  241 
  242     result = isc_once_do(&once_errcheck, initialize_errcheck);
  243     RUNTIME_CHECK(result == ISC_R_SUCCESS);
  244 
  245     err = pthread_mutex_init(mp, &errcheck);
  246     if (err == ENOMEM)
  247         return (ISC_R_NOMEMORY);
  248     return ((err == 0) ? ISC_R_SUCCESS : ISC_R_UNEXPECTED);
  249 }
  250 #endif
  251 
  252 #if ISC_MUTEX_DEBUG && defined(__NetBSD__) && defined(PTHREAD_MUTEX_ERRORCHECK)
  253 pthread_mutexattr_t isc__mutex_attrs = {
  254     PTHREAD_MUTEX_ERRORCHECK,   /* m_type */
  255     0               /* m_flags, which appears to be unused. */
  256 };
  257 #endif
  258 
  259 #if !(ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK)) && !ISC_MUTEX_PROFILE
  260 
  261 #ifdef HAVE_PTHREAD_MUTEX_ADAPTIVE_NP
  262 static bool attr_initialized = false;
  263 static pthread_mutexattr_t attr;
  264 static isc_once_t once_attr = ISC_ONCE_INIT;
  265 #endif /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP */
  266 
  267 #ifdef HAVE_PTHREAD_MUTEX_ADAPTIVE_NP
  268 static void
  269 initialize_attr(void) {
  270     RUNTIME_CHECK(pthread_mutexattr_init(&attr) == 0);
  271     RUNTIME_CHECK(pthread_mutexattr_settype
  272               (&attr, PTHREAD_MUTEX_ADAPTIVE_NP) == 0);
  273     attr_initialized = true;
  274 }
  275 #endif /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP */
  276 
  277 isc_result_t
  278 isc__mutex_init(isc_mutex_t *mp, const char *file, unsigned int line) {
  279     char strbuf[ISC_STRERRORSIZE];
  280     isc_result_t result = ISC_R_SUCCESS;
  281     int err;
  282 
  283 #ifdef HAVE_PTHREAD_MUTEX_ADAPTIVE_NP
  284     result = isc_once_do(&once_attr, initialize_attr);
  285     RUNTIME_CHECK(result == ISC_R_SUCCESS);
  286 
  287     err = pthread_mutex_init(mp, &attr);
  288 #else /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP */
  289     err = pthread_mutex_init(mp, ISC__MUTEX_ATTRS);
  290 #endif /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP */
  291 
  292     if (err == ENOMEM)
  293         return (ISC_R_NOMEMORY);
  294     if (err != 0) {
  295         isc__strerror(err, strbuf, sizeof(strbuf));
  296         UNEXPECTED_ERROR(file, line, "isc_mutex_init() failed: %s",
  297                  strbuf);
  298         result = ISC_R_UNEXPECTED;
  299     }
  300     return (result);
  301 }
  302 #endif