summaryrefslogtreecommitdiffstats
path: root/src/common/ceph_mutex.h
blob: 81777c7dbe2a0962a51685c76853f7b00a049881 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab

#pragma once

#include <utility>
#include "common/containers.h"

// What and why
// ============
//
// For general code making use of mutexes, use these ceph:: types.
// The key requirement is that you make use of the ceph::make_mutex()
// and make_recursive_mutex() factory methods, which take a string
// naming the mutex for the purposes of the lockdep debug variant.

#if defined(WITH_SEASTAR) && !defined(WITH_ALIEN)

namespace ceph {
  // an empty class satisfying the mutex concept
  struct dummy_mutex {
    void lock() {}
    bool try_lock() {
      return true;
    }
    void unlock() {}
    void lock_shared() {}
    void unlock_shared() {}
  };

  struct dummy_shared_mutex : dummy_mutex {
    void lock_shared() {}
    void unlock_shared() {}
  };

  using mutex = dummy_mutex;
  using recursive_mutex = dummy_mutex;
  using shared_mutex = dummy_shared_mutex;
  // in seastar, we should use a difference interface for enforcing the
  // semantics of condition_variable

  template <typename ...Args>
  dummy_mutex make_mutex(Args&& ...args) {
    return {};
  }

  template <typename ...Args>
  recursive_mutex make_recursive_mutex(Args&& ...args) {
    return {};
  }

  template <typename ...Args>
  shared_mutex make_shared_mutex(Args&& ...args) {
    return {};
  }

  #define ceph_mutex_is_locked(m) true
  #define ceph_mutex_is_locked_by_me(m) true
}

#else  // defined (WITH_SEASTAR) && !defined(WITH_ALIEN)
//
// For legacy Mutex users that passed recursive=true, use
// ceph::make_recursive_mutex.  For legacy Mutex users that passed
// lockdep=false, use std::mutex directly.

#ifdef CEPH_DEBUG_MUTEX

// ============================================================================
// debug (lockdep-capable, various sanity checks and asserts)
// ============================================================================
//
// Note: this is known to cause deadlocks on Windows because
// of the winpthreads shared mutex implementation.

#include "common/condition_variable_debug.h"
#include "common/mutex_debug.h"
#include "common/shared_mutex_debug.h"

namespace ceph {
  typedef ceph::mutex_debug mutex;
  typedef ceph::mutex_recursive_debug recursive_mutex;
  typedef ceph::condition_variable_debug condition_variable;
  typedef ceph::shared_mutex_debug shared_mutex;

  // pass arguments to mutex_debug ctor
  template <typename ...Args>
  mutex make_mutex(Args&& ...args) {
    return {std::forward<Args>(args)...};
  }

  // pass arguments to recursive_mutex_debug ctor
  template <typename ...Args>
  recursive_mutex make_recursive_mutex(Args&& ...args) {
    return {std::forward<Args>(args)...};
  }

  // pass arguments to shared_mutex_debug ctor
  template <typename ...Args>
  shared_mutex make_shared_mutex(Args&& ...args) {
    return {std::forward<Args>(args)...};
  }

  // debug methods
  #define ceph_mutex_is_locked(m) ((m).is_locked())
  #define ceph_mutex_is_not_locked(m) (!(m).is_locked())
  #define ceph_mutex_is_rlocked(m) ((m).is_rlocked())
  #define ceph_mutex_is_wlocked(m) ((m).is_wlocked())
  #define ceph_mutex_is_locked_by_me(m) ((m).is_locked_by_me())
  #define ceph_mutex_is_not_locked_by_me(m) (!(m).is_locked_by_me())
}

#else

// ============================================================================
// release (fast and minimal)
// ============================================================================

#include <condition_variable>
#include <mutex>

// The winpthreads shared mutex implementation is broken.
// We'll use boost::shared_mutex instead.
// https://github.com/msys2/MINGW-packages/issues/3319
#if __MINGW32__
#include <boost/thread/shared_mutex.hpp>
#else
#include <shared_mutex>
#endif

namespace ceph {

  typedef std::mutex mutex;
  typedef std::recursive_mutex recursive_mutex;
  typedef std::condition_variable condition_variable;

#if __MINGW32__
  typedef boost::shared_mutex shared_mutex;
#else
  typedef std::shared_mutex shared_mutex;
#endif

  // discard arguments to make_mutex (they are for debugging only)
  template <typename ...Args>
  mutex make_mutex(Args&& ...args) {
    return {};
  }
  template <typename ...Args>
  recursive_mutex make_recursive_mutex(Args&& ...args) {
    return {};
  }
  template <typename ...Args>
  shared_mutex make_shared_mutex(Args&& ...args) {
    return {};
  }

  // debug methods.  Note that these can blindly return true
  // because any code that does anything other than assert these
  // are true is broken.
  #define ceph_mutex_is_locked(m) true
  #define ceph_mutex_is_not_locked(m) true
  #define ceph_mutex_is_rlocked(m) true
  #define ceph_mutex_is_wlocked(m) true
  #define ceph_mutex_is_locked_by_me(m) true
  #define ceph_mutex_is_not_locked_by_me(m) true

}

#endif	// CEPH_DEBUG_MUTEX

#endif	// WITH_SEASTAR

namespace ceph {

template <class LockT,
          class LockFactoryT>
ceph::containers::tiny_vector<LockT> make_lock_container(
  const std::size_t num_instances,
  LockFactoryT&& lock_factory)
{
  return {
    num_instances, [&](const std::size_t i, auto emplacer) {
      // this will be called `num_instances` times
      new (emplacer.data()) LockT {lock_factory(i)};
    }
  };
}
} // namespace ceph