libfilezilla
Loading...
Searching...
No Matches
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
23namespace fz {
24class mutex;
25class mutex_debug;
26
28struct FZ_PUBLIC_SYMBOL lock_order final {
29 std::vector<mutex*> mutexes_;
30 std::vector<void*> backtrace_;
31};
32
34struct 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
47namespace fz {
48enum class mutex_flags
49{
50 recursive,
51
52#ifdef LFZ_DEBUG_MUTEXES
54 debug_unchecked,
55#endif
56};
57inline 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}
60inline 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
74class FZ_PUBLIC_SYMBOL mutex final
75{
76public:
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
93private:
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
103public:
104 mutex_debug debug_;
105#endif
106};
107
116class FZ_PUBLIC_SYMBOL scoped_lock final
117{
118public:
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
218private:
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
233class FZ_PUBLIC_SYMBOL condition final
234{
235public:
236 condition();
237 ~condition();
238
239 condition(condition const&) = delete;
240 condition& operator=(condition const&) = delete;
241
249
261 bool wait(scoped_lock& l, duration const& timeout);
262
273
281 bool signalled(scoped_lock const&) const { return signalled_; }
282private:
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
void wait(scoped_lock &l)
Wait indefinitely for condition to become signalled.
bool wait(scoped_lock &l, duration const &timeout)
Wait until timeout for condition to become signalled.
bool signalled(scoped_lock const &) const
Check if condition is already signalled.
Definition mutex.hpp:281
void signal(scoped_lock &l)
Signal condition variable.
The duration class represents a time interval in milliseconds.
Definition time.hpp:291
Lean replacement for std::(recursive_)mutex.
Definition mutex.hpp:75
void unlock()
Beware, manual locking isn't exception safe, use scoped_lock.
bool try_lock()
Beware, manual locking isn't exception safe.
void lock()
Beware, manual locking isn't exception safe, use scoped_lock.
A simple scoped lock.
Definition mutex.hpp:117
void unlock()
Releases the mutex.
Definition mutex.hpp:203
void lock()
Obtains the mutex.
Definition mutex.hpp:186
Sets some global macros and further includes string.hpp.
The namespace used by libfilezilla.
Definition apply.hpp:17
Assorted classes dealing with time.