libfilezilla
mutex.hpp
Go to the documentation of this file.
1 #ifndef LIBFILEZILLA_MUTEX_HEADER
2 #define LIBFILEZILLA_MUTEX_HEADER
3 
7 #include "libfilezilla.hpp"
8 #include "time.hpp"
9 
10 #ifdef FZ_WINDOWS
11 #include "glue/windows.hpp"
12 #else
13 #include <pthread.h>
14 #endif
15 
16 //#define LFZ_DEBUG_MUTEXES
17 #ifdef LFZ_DEBUG_MUTEXES
18 
19 #include <list>
20 #include <memory>
21 #include <thread>
22 
23 namespace fz {
24 class mutex;
25 class mutex_debug;
26 
28 struct FZ_PUBLIC_SYMBOL lock_order final {
29  std::vector<mutex*> mutexes_;
30  std::vector<void*> backtrace_;
31 };
32 
34 struct FZ_PUBLIC_SYMBOL mutex_debug final
35 {
36  static void record_lock(void* m);
37  static void record_unlock(void* m);
38 
39  size_t count_{};
40  std::thread::id id_{};
41  std::vector<std::list<lock_order>::iterator> own_orders_;
42  bool unchecked_{};
43 };
44 }
45 #endif
46 
47 namespace fz {
48 enum class mutex_flags
49 {
50  recursive,
51 
52 #ifdef LFZ_DEBUG_MUTEXES
53  debug_unchecked,
55 #endif
56 };
57 inline bool operator&(mutex_flags lhs, mutex_flags rhs) {
58  return (static_cast<std::underlying_type_t<mutex_flags>>(lhs) & static_cast<std::underlying_type_t<mutex_flags>>(rhs)) != 0;
59 }
60 inline mutex_flags operator|(mutex_flags lhs, mutex_flags rhs)
61 {
62  return static_cast<mutex_flags>(static_cast<std::underlying_type_t<mutex_flags>>(lhs) | static_cast<std::underlying_type_t<mutex_flags>>(rhs));
63 }
64 
74 class FZ_PUBLIC_SYMBOL mutex final
75 {
76 public:
77  explicit mutex(bool recursive = true);
78  explicit mutex(mutex_flags flags);
79  ~mutex();
80 
81  mutex(mutex const&) = delete;
82  mutex& operator=(mutex const&) = delete;
83 
85  void lock();
86 
88  void unlock();
89 
91  bool try_lock();
92 
93 private:
94  friend class condition;
95  friend class scoped_lock;
96 
97 #ifdef FZ_WINDOWS
98  CRITICAL_SECTION m_;
99 #else
100  pthread_mutex_t m_;
101 #endif
102 #ifdef LFZ_DEBUG_MUTEXES
103 public:
104  mutex_debug debug_;
105 #endif
106 };
107 
116 class FZ_PUBLIC_SYMBOL scoped_lock final
117 {
118 public:
119  enum flag
120  {
121  try_lock
122  };
123 
124  explicit scoped_lock(mutex& m)
125  : m_(&m.m_)
126  {
127 #ifdef FZ_WINDOWS
128  EnterCriticalSection(m_);
129 #else
130  pthread_mutex_lock(m_);
131 #endif
132 #ifdef LFZ_DEBUG_MUTEXES
133  mutex_debug::record_lock(m_);
134 #endif
135  }
136 
137  explicit scoped_lock(mutex& m, flag)
138  : m_(&m.m_)
139  {
140  if (!m.try_lock()) {
141  locked_ = false;
142  }
143  }
144 
145  ~scoped_lock()
146  {
147  if (locked_) {
148 #ifdef LFZ_DEBUG_MUTEXES
149  mutex_debug::record_unlock(m_);
150 #endif
151 #ifdef FZ_WINDOWS
152  LeaveCriticalSection(m_);
153 #else
154  pthread_mutex_unlock(m_);
155 #endif
156  }
157 
158  }
159 
160  scoped_lock(scoped_lock const&) = delete;
161  scoped_lock& operator=(scoped_lock const&) = delete;
162 
163  scoped_lock(scoped_lock && op) noexcept
164  {
165  m_ = op.m_;
166  op.m_ = 0;
167  locked_ = op.locked_;
168  op.locked_ = false;
169  }
170 
171  scoped_lock& operator=(scoped_lock && op) noexcept
172  {
173  if (this != &op) {
174  m_ = op.m_;
175  op.m_ = 0;
176  locked_ = op.locked_;
177  op.locked_ = false;
178  }
179  return *this;
180  }
181 
186  void lock()
187  {
188  locked_ = true;
189 #ifdef FZ_WINDOWS
190  EnterCriticalSection(m_);
191 #else
192  pthread_mutex_lock(m_);
193 #endif
194 #ifdef LFZ_DEBUG_MUTEXES
195  mutex_debug::record_lock(m_);
196 #endif
197  }
198 
203  void unlock()
204  {
205  locked_ = false;
206 #ifdef LFZ_DEBUG_MUTEXES
207  mutex_debug::record_unlock(m_);
208 #endif
209 #ifdef FZ_WINDOWS
210  LeaveCriticalSection(m_);
211 #else
212  pthread_mutex_unlock(m_);
213 #endif
214  }
215 
216  explicit operator bool() const { return locked_; }
217 
218 private:
219  friend class condition;
220 
221 #ifdef FZ_WINDOWS
222  CRITICAL_SECTION * m_;
223 #else
224  pthread_mutex_t * m_;
225 #endif
226  bool locked_{true};
227 };
228 
233 class FZ_PUBLIC_SYMBOL condition final
234 {
235 public:
236  condition();
237  ~condition();
238 
239  condition(condition const&) = delete;
240  condition& operator=(condition const&) = delete;
241 
248  void wait(scoped_lock& l);
249 
261  bool wait(scoped_lock& l, duration const& timeout);
262 
272  void signal(scoped_lock& l);
273 
281  bool signalled(scoped_lock const&) const { return signalled_; }
282 private:
283 #ifdef FZ_WINDOWS
284  CONDITION_VARIABLE cond_;
285 #else
286  pthread_cond_t cond_;
287 #endif
288  bool signalled_{};
289 };
290 
291 }
292 #endif
A simple scoped lock.
Definition: mutex.hpp:116
bool signalled(scoped_lock const &) const
Check if condition is already signalled.
Definition: mutex.hpp:281
Waitable condition variable.
Definition: mutex.hpp:233
void lock()
Obtains the mutex.
Definition: mutex.hpp:186
Assorted classes dealing with time.
void unlock()
Releases the mutex.
Definition: mutex.hpp:203
The namespace used by libfilezilla.
Definition: apply.hpp:17
The duration class represents a time interval in milliseconds.
Definition: time.hpp:290
Sets some global macros and further includes string.hpp.
Lean replacement for std::(recursive_)mutex.
Definition: mutex.hpp:74
bool try_lock()
Beware, manual locking isn't exception safe.