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
|
/**
* \file thread.h
* A collection of thread methods.
*/
#ifndef THREAD_H
#define THREAD_H
#include "timespec.h"
#if HAVE_PTHREAD
#include <pthread.h>
/**
* Opaque type defining an once variable.
*/
typedef pthread_once_t thread_once_t;
/**
* Init value for an once variable
*/
#define THREAD_ONCE_INIT PTHREAD_ONCE_INIT
#else
# error missing thread_once_t implementation
#endif
/**
* Opaque type defining a joinable thread.
*/
typedef struct thread_t thread_t;
/**
* Opaque type defining an id.
*/
typedef struct thread_id_t thread_id_t;
/**
* Opaque type defining a lock.
*/
typedef struct thread_lock_t thread_lock_t;
/**
* Opaque type defining a conditional.
*/
typedef struct thread_cond_t thread_cond_t;
/**
* Opaque type defining a thread local variable.
*/
typedef struct thread_data_t thread_data_t;
/**
* Signature or function type for a thread run method.
* A thread run method is the thread main() if you will.
* When the method returns the thread is terminated.
* @param userdata argument given when starting the thread
*/
typedef void* (* thread_run_t)(void* userdata);
/**
* Create and start a thread.
* @param run thread run method
* @param userdata argument to run method, may not be NULL
* @return true if thread was started without errors, may be NULL
*/
NONULL_ARGS(1)
bool thread_new(thread_run_t run, void* userdata);
/**
* Create and start a joinable thread.
* Must call thread_join to free thread resources.
* @param run thread run method, may not be NULL
* @param userdata argument to run method, may be NULL
* @return NULL in case of error
*/
NONULL_ARGS(1)
MALLOC thread_t* thread_joinable_new(thread_run_t run, void* userdata);
/**
* Wait for a joinable thread to exit, free it and return the result.
* @param thread result from call to thread_joinable_new, may not be NULL
* @return result of the thread run method
*/
NONULL void* thread_join(thread_t* thread);
/**
* Create a unique thread id pointing to the given or current thread.
* If no thread is given then a id for the current running thread is returned.
* Returns NULL in case of error.
* @param thread result from call to thread_joinable_new or NULL
* @return a new thread id
*/
MALLOC thread_id_t* thread_id_new(thread_t* thread);
/**
* Free a thread id.
* @param id thread id to free, may be NULL
*/
void thread_id_free(thread_id_t* id);
/**
* Return true if the current thread matches the thread id.
* @param id thread id to check, may not be NULL
* @return true if the id matches the current thread
*/
NONULL bool thread_id_is_current(thread_id_t* id);
/**
* Thread yield, give another thread the chance to run.
*/
void thread_yield(void);
/**
* Create a possibly non-recursive lock (mutex).
* Returns NULL in case of error.
* @return a new thread lock
*/
MALLOC thread_lock_t* thread_lock_new(void);
/**
* Create a recursive lock (mutex).
* Returns NULL in case of error.
* @return a new thread lock
*/
MALLOC thread_lock_t* thread_lock_recursive_new(void);
/**
* Free a lock.
* The lock must not have a owner when freed or undefined behaviour will ensue.
* @param lock lock to free, may be NULL
*/
void thread_lock_free(thread_lock_t* lock);
/**
* Take ownership of the lock.
* If another thread has ownership of the lock, wait until that thread releases
* the lock.
* If the current thread already has ownership of the lock and the lock is
* recursive the current thread now owns the lock twice.
* Undefined behavior (abort or deadlock probably) if the lock isn't recursive
* and the current thread already has ownership.
* @param lock lock to take ownership of
*/
NONULL void thread_lock_lock(thread_lock_t* lock);
/**
* Release ownership of the lock.
* Only call if the current thread has one or more ownerships of the lock.
* If the lock is recursive only one ownership is released.
* Undefined behaviour (abort or deadlock probably) if the lock isn't owned
* by the current thread.
* @param lock lock to release
*/
NONULL void thread_lock_unlock(thread_lock_t* lock);
/**
* Create a conditional. Conditionals can be used to signal other threads
* that a condition has been fulfilled if they were waiting for it.
* Returns NULL in case of error.
* @return new conditional
*/
MALLOC thread_cond_t* thread_cond_new(void);
/**
* Free a conditional. No thread may be waiting on the conditional or undefined
* behaviour will ensue.
* @param cond conditional to free, may be NULL
*/
void thread_cond_free(thread_cond_t* cond);
/**
* Setup the current thread to wait for the condition to be signalled.
* The lock must be owned by the current thread before calling and will be
* release while the current thread is waiting but reclaimed upon return.
* @param cond conditonal to wait upon, may not be NULL
* @param lock lock to release and retake ownership of, may not be NULL
*/
NONULL void thread_cond_wait(thread_cond_t* cond, thread_lock_t* lock);
/**
* Setup the current thread to wait for the condition to be signalled until
* abstime.
* The lock must be owned by the current thread before calling and will be
* release while the current thread is waiting but reclaimed upon return.
* Use thread_abstime() to fill out the abstime.
* @param cond conditonal to wait upon, may not be NULL
* @param lock lock to release and retake ownership of, may not be NULL
* @param abstime time when to give up and return, may not be NULL
* @return true if the condition was signalled, false if it timed out
*/
NONULL bool thread_cond_timedwait(thread_cond_t* cond, thread_lock_t* lock,
const struct timespec *abstime);
/**
* Signal one thread that is currently waiting on the given condition.
* The selected thread (which one is random) will be woken up.
* The calling thread may or may not own the lock when calling
* thread_cond_signal but the signalled thread will not wake up before the lock
* is released.
* @param cond conditional to signal, may not be NULL
*/
NONULL void thread_cond_signal(thread_cond_t* cond);
/**
* Signal all threads that is currently waiting on the given condition.
* All waiting threads will be woken up but only one may get ownership
* of the lock.
* The calling thread may or may not own the lock when calling
* thread_cond_broadcast but the signalled threads will not wake up before the
* lock is released.
* @param cond conditional to signal, may not be NULL
*/
NONULL void thread_cond_broadcast(thread_cond_t* cond);
/**
* Get the current absolute time and add a certain number of milliseconds
* to it. To be used with thread_cond_timedwait.
* @param abstime struct to file with the current absolute time and the
* extra milliseconds.
* @param add_ms milliseconds to add to the current absolute time
*/
NONULL void thread_abstime(struct timespec *abstime, unsigned long add_ms);
/**
* Function type for a thread local variable value destructor
*/
typedef void (* thread_data_value_free_t)(void *value);
/**
* Create a thread local variable.
* Returns NULL in case of error.
* @param free_value destructor for set non-null value at thread exit,
* may be NULL
* @return new thread local variable or NULL
*/
MALLOC thread_data_t *thread_data_new(thread_data_value_free_t free_value);
/**
* Free a thread local variable.
* Does not call any destructor.
* @param data thread local variable to free, may be NULL
*/
void thread_data_free(thread_data_t *data);
/**
* Get the thread local value of the variable.
* @param data thread local variable, may not be NULL
* @return thread local value for variable
*/
NONULL void *thread_data_value(thread_data_t *data);
/**
* Set thread local value for variable.
* @param data thread local variable, may not be NULL
* @param value new value, may be NULL
*/
NONULL_ARGS(1)
void thread_data_set(thread_data_t *data, void *value);
/**
* Function type for a thread once method
*/
typedef void (* thread_run_once_t)(void);
/**
* The first thread calling this method will run "run". Any subsequent thread
* calling thread_once for the same once variable will do nothing.
* @param once address to a static once variable, may not be NULL
* @param run method to run if this is the first thread, may not be NULL
*/
NONULL void thread_once(thread_once_t *once, thread_run_once_t run);
#endif /* THREAD_H */
|