tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

compat_mutex_pthreads.c (3635B)


      1 /* Copyright (c) 2003-2004, Roger Dingledine
      2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
      3 * Copyright (c) 2007-2021, The Tor Project, Inc. */
      4 /* See LICENSE for licensing information */
      5 
      6 /**
      7 * \file compat_mutex_pthreads.c
      8 *
      9 * \brief Implement the tor_mutex API using pthread_mutex_t.
     10 **/
     11 
     12 #include "lib/lock/compat_mutex.h"
     13 #include "lib/cc/compat_compiler.h"
     14 #include "lib/err/torerr.h"
     15 
     16 /** A mutex attribute that we're going to use to tell pthreads that we want
     17 * "recursive" mutexes (i.e., once we can re-lock if we're already holding
     18 * them.) */
     19 static pthread_mutexattr_t attr_recursive;
     20 /**
     21 * True iff <b>attr_recursive</b> has been initialized.
     22 **/
     23 static int attr_initialized = 0;
     24 
     25 /**
     26 * Initialize the locking module, if it is not already initialized.
     27 **/
     28 void
     29 tor_locking_init(void)
     30 {
     31  if (!attr_initialized) {
     32    pthread_mutexattr_init(&attr_recursive);
     33    pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE);
     34    attr_initialized = 1;
     35  }
     36 }
     37 
     38 /** Initialize <b>mutex</b> so it can be locked.  Every mutex must be set
     39 * up with tor_mutex_init() or tor_mutex_new(); not both. */
     40 void
     41 tor_mutex_init(tor_mutex_t *mutex)
     42 {
     43  if (PREDICT_UNLIKELY(!attr_initialized))
     44    tor_locking_init(); // LCOV_EXCL_LINE
     45  const int err = pthread_mutex_init(&mutex->mutex, &attr_recursive);
     46  if (PREDICT_UNLIKELY(err)) {
     47    // LCOV_EXCL_START
     48    raw_assert_unreached_msg("Error creating a mutex.");
     49    // LCOV_EXCL_STOP
     50  }
     51 }
     52 
     53 /** As tor_mutex_init, but initialize a mutex suitable that may be
     54 * non-recursive, if the OS supports that. */
     55 void
     56 tor_mutex_init_nonrecursive(tor_mutex_t *mutex)
     57 {
     58  int err;
     59  if (!attr_initialized)
     60    tor_locking_init(); // LCOV_EXCL_LINE
     61  err = pthread_mutex_init(&mutex->mutex, NULL);
     62  if (PREDICT_UNLIKELY(err)) {
     63    // LCOV_EXCL_START
     64    raw_assert_unreached_msg("Error creating a mutex.");
     65    // LCOV_EXCL_STOP
     66  }
     67 }
     68 
     69 /** Wait until <b>m</b> is free, then acquire it. */
     70 void
     71 tor_mutex_acquire(tor_mutex_t *m)
     72 {
     73  int err;
     74  raw_assert(m);
     75  err = pthread_mutex_lock(&m->mutex);
     76  if (PREDICT_UNLIKELY(err)) {
     77    // LCOV_EXCL_START
     78    raw_assert_unreached_msg("Error locking a mutex.");
     79    // LCOV_EXCL_STOP
     80  }
     81 }
     82 /** Release the lock <b>m</b> so another thread can have it. */
     83 void
     84 tor_mutex_release(tor_mutex_t *m)
     85 {
     86  int err;
     87  raw_assert(m);
     88  err = pthread_mutex_unlock(&m->mutex);
     89  if (PREDICT_UNLIKELY(err)) {
     90    // LCOV_EXCL_START
     91    raw_assert_unreached_msg("Error unlocking a mutex.");
     92    // LCOV_EXCL_STOP
     93  }
     94 }
     95 /** Clean up the mutex <b>m</b> so that it no longer uses any system
     96 * resources.  Does not free <b>m</b>.  This function must only be called on
     97 * mutexes from tor_mutex_init().
     98 *
     99 * Destroying a locked mutex is undefined behaviour. Global mutexes may be
    100 * locked when they are passed to this function, because multiple threads can
    101 * still access them. So we can either:
    102 *  - destroy on shutdown, and re-initialise when tor re-initialises, or
    103 *  - skip destroying and re-initialisation, using a sentinel variable.
    104 * See #31735 for details.
    105 */
    106 void
    107 tor_mutex_uninit(tor_mutex_t *m)
    108 {
    109  int err;
    110  raw_assert(m);
    111  /* If the mutex is already locked, wait until after it is unlocked to destroy
    112   * it. Locking and releasing the mutex makes undefined behaviour less likely,
    113   * but does not prevent it. Another thread can lock the mutex between release
    114   * and destroy. */
    115  tor_mutex_acquire(m);
    116  tor_mutex_release(m);
    117  err = pthread_mutex_destroy(&m->mutex);
    118  if (PREDICT_UNLIKELY(err)) {
    119    // LCOV_EXCL_START
    120    raw_assert_unreached_msg("Error destroying a mutex.");
    121    // LCOV_EXCL_STOP
    122  }
    123 }