-
Notifications
You must be signed in to change notification settings - Fork 98
Expand file tree
/
Copy pathcelix_threads.h
More file actions
365 lines (292 loc) · 13.6 KB
/
celix_threads.h
File metadata and controls
365 lines (292 loc) · 13.6 KB
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
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef CELIX_THREADS_H_
#define CELIX_THREADS_H_
#include <pthread.h>
#include <stdbool.h>
#include <stddef.h>
#include "celix_cleanup.h"
#include "celix_errno.h"
#include "celix_utils_export.h"
#ifdef __cplusplus
extern "C" {
#endif
struct celix_thread {
bool threadInitialized;
pthread_t thread;
};
typedef pthread_once_t celix_thread_once_t;
#define CELIX_THREAD_ONCE_INIT PTHREAD_ONCE_INIT
typedef struct celix_thread celix_thread_t;
typedef pthread_attr_t celix_thread_attr_t;
typedef void *(*celix_thread_start_t)(void *);
CELIX_UTILS_EXPORT extern const celix_thread_t celix_thread_default;
CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_thread_attr_t, pthread_attr_destroy)
CELIX_UTILS_EXPORT celix_status_t
celixThread_create(celix_thread_t *new_thread, const celix_thread_attr_t *attr, celix_thread_start_t func, void *data);
/**
* If supported by the platform sets the name of the thread.
*/
CELIX_UTILS_EXPORT void celixThread_setName(celix_thread_t *thread, const char *threadName);
CELIX_UTILS_EXPORT void celixThread_exit(void *exitStatus);
CELIX_UTILS_EXPORT celix_status_t celixThread_detach(celix_thread_t thread);
CELIX_UTILS_EXPORT celix_status_t celixThread_join(celix_thread_t thread, void **status);
CELIX_UTILS_EXPORT celix_status_t celixThread_kill(celix_thread_t thread, int sig);
CELIX_UTILS_EXPORT celix_thread_t celixThread_self(void);
/**
* Return true - as int - if the threads are equals
* @param[in] thread1
* @param[in] thread2
* @return non-zero if the thread IDs t1 and t2 correspond to the same thread, otherwise it will return zero.
*/
CELIX_UTILS_EXPORT int celixThread_equals(celix_thread_t thread1, celix_thread_t thread2);
CELIX_UTILS_EXPORT bool celixThread_initialized(celix_thread_t thread);
typedef pthread_mutex_t celix_thread_mutex_t;
typedef pthread_mutexattr_t celix_thread_mutexattr_t;
#define CELIX_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
//MUTEX TYPES
enum {
CELIX_THREAD_MUTEX_NORMAL,
CELIX_THREAD_MUTEX_RECURSIVE,
CELIX_THREAD_MUTEX_ERRORCHECK,
CELIX_THREAD_MUTEX_DEFAULT
};
CELIX_UTILS_EXPORT celix_status_t celixThreadMutex_create(celix_thread_mutex_t *mutex, celix_thread_mutexattr_t *attr);
CELIX_UTILS_EXPORT celix_status_t celixThreadMutex_destroy(celix_thread_mutex_t *mutex);
CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(celix_thread_mutex_t, celixThreadMutex_destroy)
CELIX_UTILS_EXPORT celix_status_t celixThreadMutex_lock(celix_thread_mutex_t *mutex);
CELIX_UTILS_EXPORT celix_status_t celixThreadMutex_tryLock(celix_thread_mutex_t *mutex);
CELIX_UTILS_EXPORT celix_status_t celixThreadMutex_unlock(celix_thread_mutex_t *mutex);
/**
* @brief Lock guard for mutex.
*/
typedef struct celix_mutex_lock_guard {
celix_thread_mutex_t *mutex;
} celix_mutex_lock_guard_t;
/**
* @brief Initialize a lock guard for @a mutex.
*
* Lock @a mutex and return a celix_mutex_lock_guard_t.
* Unlock with celixMutexLockGuard_deinit(). Using celixThreadMutex_lock() on @a mutex
* while a celix_mutex_lock_guard_t exists can lead to undefined behaviour.
*
* No allocation is performed, it is equivalent to a celixThreadMutex_lock() call.
* This is intended to be used with celix_auto().
*
* @param mutex A mutex to lock.
* @return An initialized lock guard to be used with celix_auto().
*/
static CELIX_UNUSED inline celix_mutex_lock_guard_t celixMutexLockGuard_init(celix_thread_mutex_t* mutex) {
celix_mutex_lock_guard_t guard;
guard.mutex = mutex;
celixThreadMutex_lock(mutex);
return guard;
}
/**
* @brief Deinitialize a lock guard for @a mutex.
*
* Unlock the mutex of @a guard.
* No memory is freed, it is equivalent to a celixThreadMutex_unlock() call.
*
* @param guard A celix_mutex_lock_guard_t.
*/
static CELIX_UNUSED inline void celixMutexLockGuard_deinit(celix_mutex_lock_guard_t* guard) {
if (guard->mutex) {
celixThreadMutex_unlock(guard->mutex);
guard->mutex = NULL;
}
}
CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_mutex_lock_guard_t, celixMutexLockGuard_deinit)
CELIX_UTILS_EXPORT celix_status_t celixThreadMutexAttr_create(celix_thread_mutexattr_t *attr);
CELIX_UTILS_EXPORT celix_status_t celixThreadMutexAttr_destroy(celix_thread_mutexattr_t *attr);
CELIX_UTILS_EXPORT celix_status_t celixThreadMutexAttr_settype(celix_thread_mutexattr_t *attr, int type);
CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_thread_mutexattr_t, celixThreadMutexAttr_destroy)
typedef pthread_rwlock_t celix_thread_rwlock_t;
typedef pthread_rwlockattr_t celix_thread_rwlockattr_t;
CELIX_UTILS_EXPORT celix_status_t celixThreadRwlock_create(celix_thread_rwlock_t *lock, celix_thread_rwlockattr_t *attr);
CELIX_UTILS_EXPORT celix_status_t celixThreadRwlock_destroy(celix_thread_rwlock_t *lock);
CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(celix_thread_rwlock_t, celixThreadRwlock_destroy)
CELIX_UTILS_EXPORT celix_status_t celixThreadRwlock_readLock(celix_thread_rwlock_t *lock);
CELIX_UTILS_EXPORT celix_status_t celixThreadRwlock_tryReadLock(celix_thread_rwlock_t *lock);
CELIX_UTILS_EXPORT celix_status_t celixThreadRwlock_writeLock(celix_thread_rwlock_t *lock);
CELIX_UTILS_EXPORT celix_status_t celixThreadRwlock_tryWriteLock(celix_thread_rwlock_t *lock);
CELIX_UTILS_EXPORT celix_status_t celixThreadRwlock_unlock(celix_thread_rwlock_t *lock);
/**
* @brief A RAII style write lock guard for celix_thread_rwlock_t.
*
* The lock is obtained in the constructor and released in the destructor.
* This is intended to be used with celix_auto().
*/
typedef struct celix_rwlock_wlock_guard {
celix_thread_rwlock_t *lock;
} celix_rwlock_wlock_guard_t;
/**
* @brief Initialize a write lock guard for @a lock.
*
* Obtain a write lock on @a lock and return a celix_rwlock_wlock_guard_t.
* Unlock with celixRwlockWlockGuard_deinit(). Using celixThreadRwlock_unlock()
* on @lock while a celix_rwlock_rlock_guard_t exists can lead to undefined behaviour.
*
* No allocation is performed, it is equivalent to a celixThreadRwlock_readLock() call.
* This is intended to be used with celix_auto().
*
* @param lock A read-write lock to lock.
* @return An initialized write lock guard to be used with celix_auto().
*/
static CELIX_UNUSED inline celix_rwlock_wlock_guard_t celixRwlockWlockGuard_init(celix_thread_rwlock_t* lock) {
celix_rwlock_wlock_guard_t guard;
guard.lock = lock;
celixThreadRwlock_writeLock(lock);
return guard;
}
/**
* @brief Deinitialize a write lock guard.
*
* Release a write lock on the read-write lock contained in @a guard.
* See celixRwlockWlockGuard_init() for details.
* No memory is freed, it is equivalent to a celixThreadRwlock_unlock() call.
*
* @param guard A celix_rwlock_wlock_guard_t.
*/
static CELIX_UNUSED inline void celixRwlockWlockGuard_deinit(celix_rwlock_wlock_guard_t* guard) {
if (guard->lock) {
celixThreadRwlock_unlock(guard->lock);
guard->lock = NULL;
}
}
CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_rwlock_wlock_guard_t, celixRwlockWlockGuard_deinit)
/**
* @brief A RAII style read lock guard for celix_thread_rwlock_t.
*
* The lock is obtained in the constructor and released in the destructor.
* This is intended to be used with celix_auto().
*/
typedef struct celix_rwlock_rlock_guard {
celix_thread_rwlock_t *lock;
} celix_rwlock_rlock_guard_t;
/**
* @brief Initialize a read lock guard for @a lock.
*
* Obtain a read lock on @a lock and return a celix_rwlock_rlock_guard_t.
* Unlock with celix_RwlockRlockGuard_deinit(). Using celixThreadRwlock_unlock()
* on @lock while a celix_rwlock_rlock_guard_t exists can lead to undefined behaviour.
*
* No allocation is performed, it is equivalent to a celixThreadRwlock_readLock() call.
* This is intended to be used with celix_auto().
*
* @param lock A read-write lock to lock.
* @return A guard to be used with celix_auto().
*/
static CELIX_UNUSED inline celix_rwlock_rlock_guard_t celixRwlockRlockGuard_init(celix_thread_rwlock_t *lock) {
celix_rwlock_rlock_guard_t guard;
guard.lock = lock;
celixThreadRwlock_readLock(lock);
return guard;
}
/**
* @brief Deinitialize a read lock guard.
*
* Release a read lock on the read-write lock contained in @a guard.
* See celixRwlockRlockGuard_init() for details.
* No memory is freed, it is equivalent to a celixThreadRwlock_unlock() call.
*
* @param guard A celix_rwlock_rlock_guard_t.
*/
static CELIX_UNUSED inline void celixRwlockRlockGuard_deinit(celix_rwlock_rlock_guard_t* guard) {
if (guard->lock) {
celixThreadRwlock_unlock(guard->lock);
guard->lock = NULL;
}
}
CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_rwlock_rlock_guard_t, celixRwlockRlockGuard_deinit)
CELIX_UTILS_EXPORT celix_status_t celixThreadRwlockAttr_create(celix_thread_rwlockattr_t *attr);
CELIX_UTILS_EXPORT celix_status_t celixThreadRwlockAttr_destroy(celix_thread_rwlockattr_t *attr);
//NOTE: No support yet for setting specific rw lock attributes
CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_thread_rwlockattr_t, celixThreadRwlockAttr_destroy)
typedef pthread_cond_t celix_thread_cond_t;
typedef pthread_condattr_t celix_thread_condattr_t;
/**
* @brief Initialize the given condition variable.
*
* For Linux the condition clock is set to CLOCK_MONOTONIC whether or not the attr is NULL.
*
* @param[in] condition The condition variable to initialize.
* @param[in] attr The condition variable attributes to use. Can be NULL for default attributes.
* @return CELIX_SUCCESS if the condition variable is initialized successfully.
*/
CELIX_UTILS_EXPORT celix_status_t celixThreadCondition_init(celix_thread_cond_t *condition, celix_thread_condattr_t *attr);
CELIX_UTILS_EXPORT celix_status_t celixThreadCondition_destroy(celix_thread_cond_t *condition);
CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(celix_thread_cond_t, celixThreadCondition_destroy)
CELIX_UTILS_EXPORT celix_status_t celixThreadCondition_wait(celix_thread_cond_t *cond, celix_thread_mutex_t *mutex);
CELIX_UTILS_DEPRECATED_EXPORT celix_status_t celixThreadCondition_timedwaitRelative(celix_thread_cond_t *cond, celix_thread_mutex_t *mutex, long seconds, long nanoseconds);
CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_thread_condattr_t, pthread_condattr_destroy)
/**
* @brief Get the current time suitable for Celix thread conditions.
*
* This function returns the current time compatible with the Celix thread conditions, specifically for
* the function celixThreadCondition_waitUntil, as long as the condition is initialized with
* celixThreadCondition_init.
*
* Note: Do not use the returned time for logging or displaying the current time as the choice of clock
* varies based on the operating system.
*
* @return A struct timespec denoting the current time.
*/
CELIX_UTILS_EXPORT struct timespec celixThreadCondition_getTime();
/**
* @brief Calculate the current time incremented by a given delay, suitable for Celix thread conditions.
*
* This function provides the current time, increased by a specified delay (in seconds), compatible
* with Celix thread conditions. The resulting struct timespec can be used with the function
* celixThreadCondition_waitUntil, as long as the condition is initialized with celixThreadCondition_init.
*
* Note: Do not use the returned time for logging or displaying the current time as the choice of clock
* varies based on the operating system.
*
* @param[in] delayInSeconds The desired delay in seconds to be added to the current time.
* @return A struct timespec denoting the current time plus the provided delay.
*/
CELIX_UTILS_EXPORT struct timespec celixThreadCondition_getDelayedTime(double delayInSeconds);
/**
* @brief Wait for the condition to be signaled or until the given absolute time is reached.
*
* @section Errors
* - CELIX_SUCCESS if the condition is signaled before the delayInSeconds is reached.
* - CELIX_ILLEGAL_ARGUMENT if the absTime is null.
* - ETIMEDOUT If the absTime has passed.
* - EINTR Wait was interrupted by a signal.
*
* Values for absTime should be obtained by celixThreadCondition_getTime, celixThreadCondition_getDelayedTime or
* a modified timespec based on celixThreadCondition_getTime/celixThreadCondition_getDelayedTime.
*
* @param[in] cond The condition to wait for.
* @param[in] mutex The (locked) mutex to use.
* @param[in] absTime The absolute time to wait for the condition to be signaled.
* @return CELIX_SUCCESS if the condition is signaled before the delayInSeconds is reached.
*/
CELIX_UTILS_EXPORT celix_status_t celixThreadCondition_waitUntil(celix_thread_cond_t* cond,
celix_thread_mutex_t* mutex,
const struct timespec* absTime);
CELIX_UTILS_EXPORT celix_status_t celixThreadCondition_broadcast(celix_thread_cond_t *cond);
CELIX_UTILS_EXPORT celix_status_t celixThreadCondition_signal(celix_thread_cond_t *cond);
CELIX_UTILS_EXPORT celix_status_t celixThread_once(celix_thread_once_t *once_control, void (*init_routine)(void));
#ifdef __cplusplus
}
#endif
#endif /* CELIX_THREADS_H_ */