Tor 0.4.9.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
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.) */
19static pthread_mutexattr_t attr_recursive;
20/**
21 * True iff <b>attr_recursive</b> has been initialized.
22 **/
23static int attr_initialized = 0;
24
25/**
26 * Initialize the locking module, if it is not already initialized.
27 **/
28void
30{
31 if (!attr_initialized) {
32 pthread_mutexattr_init(&attr_recursive);
33 pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE);
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. */
40void
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. */
55void
57{
58 int err;
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. */
70void
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. */
83void
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 */
106void
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.