forked from dyninc/OpenBFDD
-
Notifications
You must be signed in to change notification settings - Fork 1
/
threads.h
301 lines (253 loc) · 6.99 KB
/
threads.h
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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
/**************************************************************
* Copyright (c) 2010-2013, Dynamic Network Services, Inc.
* Jake Montgomery ([email protected]) & Tom Daly ([email protected])
* Distributed under the FreeBSD License - see LICENSE
***************************************************************/
// Various threading and lock routines
#pragma once
#include <pthread.h>
namespace openbfdd
{
/**
* Helper/wrapper for pthread_cond_t Could handle initialization failure better.
*/
class WaitCondition
{
public:
WaitCondition(bool init = true);
~WaitCondition();
/**
* Signals the condition.
*/
void Signal();
/**
* Only call if this is not created with init == true;
*
* @return bool - false on failure
*/
bool Init();
/**
* Waits on the signal and lock. Note that spurious wakeups can occur.
* On failure other than timeout the mutex and signal state will not have
* changed.
*
* @param lock [in]- Must not be NULL.
* @param msTimeout [in] - The timeout time, or 0 for no timeout.
*
* @return int - 0 on success. 1 on timeout, -1 on other failure.
*/
int Wait(pthread_mutex_t *lock, uint32_t msTimeout = 0);
private:
pthread_cond_t m_condition;
bool m_initDone; // the condition initialization succeeded.
};
/**
* Wrapper for a simple mutex.
*/
class QuickLock
{
public:
/**
* @param create - If true then the lock is created and initialized.
*/
QuickLock(bool create = false);
~QuickLock();
/**
* Use to create the lock, if constructor was not called with create.
*
* @return bool - false on failure. (Will log failure.)
*/
bool Create();
/**
* Permanently destroys the lock. Do not call any other methods after this
* unless Create is called.
*/
void Destroy();
/**
* Locks the lock. Normally use an AutoQuickLock on the stack to ensure that
* this gets unlocked.
*
* @return bool - false on failure. (Will log failure.)
*/
bool Lock();
/**
* Unlocks the lock. Normally use an AutoQuickLock on the stack to ensure that
* this gets unlocked.
*
* @return bool - false on failure. (Will log failure.)
*/
bool UnLock();
/**
* Signal a condition.
* Lock must be locked by us.
* On return, this is always unlocked. (even on failure)
*
* @param condition
*/
void SignalAndUnlock(WaitCondition &condition);
/**
*
* Waits on a condition. Lock must be locked by us.
* On return, this is still locked.
*
* @param condition
* @param msTimeout [in] - The timeout time, or 0 for no timeout.
*
* @return int - 0 on success. 1 on timeout, -1 on other failure.
*/
int LockWait(WaitCondition &condition, uint32_t msTimeout = 0);
private:
pthread_mutex_t m_Lock;
bool m_initialized;
};
// Helper for QuickLock. This object should only be used from a single thread.
class AutoQuickLock
{
public:
/**
*
*
* @param threadLock - The lock.
* @param lockInitial - Should the lock start in the locked state. Use
* IsLockedByMe to check for failure. Will log on failure.
*/
AutoQuickLock(QuickLock &threadLock, bool lockInitial = true);
~AutoQuickLock();
/**
* Lock the lock.
*
* @return bool - false on failure. (Will log failure.)
*/
bool Lock();
/**
* Check if this object had locked the lock.
*
* @return bool - true if this object had locked the lock.
*/
bool IsLockedByMe();
/**
* Unlock the lock.
* Called automatically when this is destroyed.
*
* @return bool - false on failure. (Will log failure.)
*/
bool UnLock();
/**
* Signal a condition.
* Lock must be locked by us.
* On return, this is always unlocked. (even on failure)
*
* @param condition
*/
void SignalAndUnlock(WaitCondition &condition);
/**
*
* Waits on a condition. Lock must be locked by us.
* On return, this is still locked.
*
* @param condition
* @param msTimeout [in] - The timeout time, or 0 for no timeout.
*
* @return int - 0 on success. 1 on timeout, -1 on other failure.
*/
int LockWait(WaitCondition &condition, uint32_t msTimeout = 0);
private:
QuickLock *m_quickLock;
bool m_isLockedByMe;
};
/**
* Wrapper for a read/write lock.
*/
class ReadWriteLock
{
public:
/**
* @param create - If true then the lock is created and initialized.
*/
ReadWriteLock(bool create = false);
~ReadWriteLock();
/**
* Use to create the lock, if constructor was not called with create.
*
* @return bool - false on failure. (Will log failure.)
*/
bool Create();
/**
* Permanently destroys the lock. Do not call any other methods after this
* unless Create is called.
*/
void Destroy();
/**
* Shared locks the lock. Normally use an AutoReadWriteLock on the stack
* to ensure that this gets unlocked.
*
* @return bool - false on failure. (Will log failure.)
*/
bool ReadLock();
/**
* Exclusive locks the lock . Normally use an AutoReadWriteLock on the stack to ensure
* that this gets unlocked.
*
* @return bool - false on failure. (Will log failure.)
*/
bool WriteLock();
/**
* Unlocks the lock. Normally use an AutoRWriteLock on the stack to ensure that
* this gets unlocked.
*
* @return bool - false on failure. (Will log failure.)
*/
bool UnLock();
private:
pthread_rwlock_t m_Lock;
bool m_initialized;
};
// Helper for RWriteLock. This object should only be used from a single thread.
class AutoReadWriteLock
{
public:
enum LockType
{
None, // not locked
Read, // Read locked
Write // write locked.
};
/**
*
*
* @param threadLock - The lock.
* @param lockInitial - Should the lock start in the locked state. Use
* IsLockedByMe to check for failure. Will log on failure.
*/
AutoReadWriteLock(ReadWriteLock &threadLock, AutoReadWriteLock::LockType lockInitial);
~AutoReadWriteLock();
/**
* Read lock the lock.
*
* @return bool - false on failure. (Will log failure.)
*/
bool ReadLock();
/**
* Exclusive lock the lock.
*
* @return bool - false on failure. (Will log failure.)
*/
bool WriteLock();
/**
* Check if this object had locked the lock.
*
* @return bool - true if this object had locked the lock.
*/
bool IsLockedByMe();
/**
* Unlock the lock.
* Called automatically when this is destroyed.
*
* @return bool - false on failure. (Will log failure.)
*/
bool UnLock();
private:
ReadWriteLock *m_rwLock;
AutoReadWriteLock::LockType m_lockedByMeType;
};
};