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
|
/*************************************************************************
* Copyright (C) 2010-2014 Tavian Barnes <tavianator@tavianator.com> *
* *
* This file is part of The Dimension Library. *
* *
* The Dimension Library is free software; you can redistribute it and/ *
* or modify it under the terms of the GNU Lesser General Public License *
* as published by the Free Software Foundation; either version 3 of the *
* License, or (at your option) any later version. *
* *
* The Dimension Library is distributed in the hope that it will be *
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty *
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this program. If not, see *
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
/**
* @file
* Background threading interface.
*/
#include <pthread.h>
/**
* Thread callback type.
* @param[in,out] ptr An arbitrary pointer.
* @return 0 on success, non-zero on failure.
*/
typedef int dmnsn_thread_fn(void *ptr);
/**
* Create a thread that cleans up after itself on errors.
* @param[in,out] future The future object to associate with the thread.
* @param[in] thread_fn The thread callback.
* @param[in,out] arg The pointer to pass to the thread callback.
*/
DMNSN_INTERNAL void dmnsn_new_thread(dmnsn_future *future,
dmnsn_thread_fn *thread_fn, void *arg);
/**
* Thread callback type for parallel tasks.
* @param[in,out] ptr An arbitrary pointer.
* @param[in] thread An ID for this thread, in [0, \p nthreads).
* @param[in] nthreads The number of concurrent threads.
* @return 0 on success, non-zero on failure.
*/
typedef int dmnsn_ccthread_fn(void *ptr, unsigned int thread,
unsigned int nthreads);
/**
* Run \p nthreads threads in parallel.
* @param[in,out] future The future object to associate with the threads,
* possibly NULL.
* @param[in] ccthread_fn The routine to run in each concurrent thread.
* @param[in,out] arg The pointer to pass to the thread callbacks.
* @param[in] nthreads The number of concurrent threads to run.
* @return 0 if all threads were successful, and an error code otherwise.
*/
DMNSN_INTERNAL int dmnsn_execute_concurrently(dmnsn_future *future,
dmnsn_ccthread_fn *ccthread_fn,
void *arg, unsigned int nthreads);
/**
* Initialize a mutex, bailing out on failure.
* @param[out] mutex The mutex to initialize.
*/
DMNSN_INTERNAL void dmnsn_initialize_mutex(pthread_mutex_t *mutex);
/** dmnsn_lock_mutex() implementation. */
DMNSN_INTERNAL void dmnsn_lock_mutex_impl(pthread_mutex_t *mutex);
/** dmnsn_unlock_mutex() implementation. */
DMNSN_INTERNAL void dmnsn_unlock_mutex_impl(void *mutex);
/**
* Lock a mutex, bailing out on failure.
* Contains a {, so must be used in the same block as dmnsn_unlock_mutex().
* @param[in,out] mutex The mutex to lock.
*/
#define dmnsn_lock_mutex(mutex) do { dmnsn_lock_mutex_impl((mutex))
/**
* Unlock a mutex, bailing out on failure.
* Contains a }, so must be used in the same block as dmnsn_lock_mutex().
* @param[in,out] mutex The mutex to unlock.
*/
#define dmnsn_unlock_mutex(mutex) dmnsn_unlock_mutex_impl((mutex)); } while (0)
/**
* Destroy a mutex, warning on failure.
* @param[in,out] mutex The mutex to destroy.
*/
DMNSN_INTERNAL void dmnsn_destroy_mutex(pthread_mutex_t *mutex);
/**
* Initialize a read-write lock, bailing out on failure.
* @param[out] rwlock The read-write lock to initialize.
*/
DMNSN_INTERNAL void dmnsn_initialize_rwlock(pthread_rwlock_t *rwlock);
/** dmnsn_read_lock() implementation. */
DMNSN_INTERNAL void dmnsn_read_lock_impl(pthread_rwlock_t *rwlock);
/** dmnsn_write_lock() implementation. */
DMNSN_INTERNAL void dmnsn_write_lock_impl(pthread_rwlock_t *rwlock);
/** dmnsn_unlock_rwlock() implementation. */
DMNSN_INTERNAL void dmnsn_unlock_rwlock_impl(pthread_rwlock_t *rwlock);
/**
* Read-lock a read-write lock, bailing out on failure.
* Contains a {, so must be used in the same block as dmnsn_unlock_rwlock().
* @param[in,out] rwlock The read-write lock to lock.
*/
#define dmnsn_read_lock(rwlock) do { dmnsn_read_lock_impl((rwlock))
/**
* Write-lock a read-write lock, bailing out on failure.
* Contains a {, so must be used in the same block as dmnsn_unlock_rwlock().
* @param[in,out] rwlock The read-write lock to lock.
*/
#define dmnsn_write_lock(rwlock) do { dmnsn_write_lock_impl((rwlock))
/**
* Unlock a read-write lock, bailing out on failure.
* Contains a }, so must be used in the same block as dmnsn_read_lock() or
* dmnsn_write_lock().
* @param[in,out] rwlock The read-write lock to lock.
*/
#define dmnsn_unlock_rwlock(rwlock) \
dmnsn_unlock_rwlock_impl((rwlock)); } while (0)
/**
* Destroy a read-write lock, warning on failure.
* @param[in,out] rwlock The read-write lock to destroy.
*/
DMNSN_INTERNAL void dmnsn_destroy_rwlock(pthread_rwlock_t *rwlock);
/**
* Initialize a condition variable, bailing out on failure.
* @param[out] cond The condition variable to initialize.
*/
DMNSN_INTERNAL void dmnsn_initialize_cond(pthread_cond_t *cond);
/**
* Wait on a condition variable, bailing out on error.
* @param[in] cond The condition variable to wait on.
* @param[in] mutex The associated mutex.
*/
DMNSN_INTERNAL void dmnsn_cond_wait(pthread_cond_t *cond,
pthread_mutex_t *mutex);
/**
* Wait on a condition variable, bailing out on error, and unlock the mutex if
* cancelled.
* @param[in] cond The condition variable to wait on.
* @param[in] mutex The associated mutex.
*/
#define dmnsn_cond_wait_safely(cond, mutex) \
do { \
pthread_cleanup_push(dmnsn_unlock_mutex_impl, (mutex)); \
dmnsn_cond_wait((cond), (mutex)); \
pthread_cleanup_pop(false); \
} while (0)
/**
* Signal a condition variable, bailing out on error.
* @param[in] cond The condition variable to signal.
*/
DMNSN_INTERNAL void dmnsn_cond_broadcast(pthread_cond_t *cond);
/**
* Destroy a condition variable, warning on failure.
* @param[in,out] cond The condition variable to destroy.
*/
DMNSN_INTERNAL void dmnsn_destroy_cond(pthread_cond_t *cond);
/**
* Once-called callback type.
*/
typedef void dmnsn_once_fn(void);
/**
* Call a function exactly once, bailing out on failure.
* @param[in,out] once The once control.
* @param[in] once_fn The function to call.
*/
DMNSN_INTERNAL void dmnsn_once(pthread_once_t *once, dmnsn_once_fn *once_fn);
/**
* Initialize a thread-local storage key, bailing out on failure.
* @param[out] key The key to initialize.
* @param[in] destructor An optional destructor callback.
*/
DMNSN_INTERNAL void dmnsn_key_create(pthread_key_t *key,
dmnsn_callback_fn *destructor);
/**
* Set a thread-specific pointer, bailing out on failure.
* @param[in] key The thread-local storage key.
* @param[in] value The value to set.
*/
DMNSN_INTERNAL void dmnsn_setspecific(pthread_key_t key, const void *value);
/**
* Destroy a thread-local storage key, warning on failure.
* @param[out] key The key to destroy.
*/
DMNSN_INTERNAL void dmnsn_key_delete(pthread_key_t key);
/**
* Join a thread, bailing out on failure.
* @param[in,out] thread The thread to join.
*/
DMNSN_INTERNAL void dmnsn_join_thread(pthread_t thread, void **retval);
|