LCOV - code coverage report
Current view: top level - lib/lock - compat_mutex_pthreads.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 37 37 100.0 %
Date: 2021-11-24 03:28:48 Functions: 6 6 100.0 %

          Line data    Source code
       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       11122 : tor_locking_init(void)
      30             : {
      31       11122 :   if (!attr_initialized) {
      32        5562 :     pthread_mutexattr_init(&attr_recursive);
      33        5562 :     pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE);
      34        5562 :     attr_initialized = 1;
      35             :   }
      36       11122 : }
      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        5660 : tor_mutex_init(tor_mutex_t *mutex)
      42             : {
      43        5660 :   if (PREDICT_UNLIKELY(!attr_initialized))
      44             :     tor_locking_init(); // LCOV_EXCL_LINE
      45        5660 :   const int err = pthread_mutex_init(&mutex->mutex, &attr_recursive);
      46        5660 :   if (PREDICT_UNLIKELY(err)) {
      47             :     // LCOV_EXCL_START
      48             :     raw_assert_unreached_msg("Error creating a mutex.");
      49             :     // LCOV_EXCL_STOP
      50             :   }
      51        5660 : }
      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           9 : tor_mutex_init_nonrecursive(tor_mutex_t *mutex)
      57             : {
      58           9 :   int err;
      59           9 :   if (!attr_initialized)
      60             :     tor_locking_init(); // LCOV_EXCL_LINE
      61           9 :   err = pthread_mutex_init(&mutex->mutex, NULL);
      62           9 :   if (PREDICT_UNLIKELY(err)) {
      63             :     // LCOV_EXCL_START
      64             :     raw_assert_unreached_msg("Error creating a mutex.");
      65             :     // LCOV_EXCL_STOP
      66             :   }
      67           9 : }
      68             : 
      69             : /** Wait until <b>m</b> is free, then acquire it. */
      70             : void
      71      355082 : tor_mutex_acquire(tor_mutex_t *m)
      72             : {
      73      355082 :   int err;
      74      355082 :   raw_assert(m);
      75      355082 :   err = pthread_mutex_lock(&m->mutex);
      76      357238 :   if (PREDICT_UNLIKELY(err)) {
      77             :     // LCOV_EXCL_START
      78             :     raw_assert_unreached_msg("Error locking a mutex.");
      79             :     // LCOV_EXCL_STOP
      80             :   }
      81      357238 : }
      82             : /** Release the lock <b>m</b> so another thread can have it. */
      83             : void
      84      356483 : tor_mutex_release(tor_mutex_t *m)
      85             : {
      86      356483 :   int err;
      87      356483 :   raw_assert(m);
      88      356483 :   err = pthread_mutex_unlock(&m->mutex);
      89      357240 :   if (PREDICT_UNLIKELY(err)) {
      90             :     // LCOV_EXCL_START
      91             :     raw_assert_unreached_msg("Error unlocking a mutex.");
      92             :     // LCOV_EXCL_STOP
      93             :   }
      94      357240 : }
      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          60 : tor_mutex_uninit(tor_mutex_t *m)
     108             : {
     109          60 :   int err;
     110          60 :   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          60 :   tor_mutex_acquire(m);
     116          60 :   tor_mutex_release(m);
     117          60 :   err = pthread_mutex_destroy(&m->mutex);
     118          60 :   if (PREDICT_UNLIKELY(err)) {
     119             :     // LCOV_EXCL_START
     120             :     raw_assert_unreached_msg("Error destroying a mutex.");
     121             :     // LCOV_EXCL_STOP
     122             :   }
     123          60 : }

Generated by: LCOV version 1.14