Tor  0.4.7.0-alpha-dev
compat_mutex_pthreads.c
Go to the documentation of this file.
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
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
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
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
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
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
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. */
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 }
Utility macros to handle different features and behavior in different compilers.
Header for compat_mutex.c.
void tor_mutex_release(tor_mutex_t *m)
void tor_mutex_acquire(tor_mutex_t *m)
void tor_mutex_init_nonrecursive(tor_mutex_t *mutex)
static int attr_initialized
void tor_mutex_init(tor_mutex_t *mutex)
void tor_locking_init(void)
static pthread_mutexattr_t attr_recursive
void tor_mutex_uninit(tor_mutex_t *m)
Headers for torerr.c.