dthreads.h 10.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*  Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
Marek Vavrusa's avatar
Marek Vavrusa committed
16 17
/*!
 * \file dthreads.h
18
 *
19
 * \author Marek Vavrusa <marek.vavusa@nic.cz>
Marek Vavrusa's avatar
Marek Vavrusa committed
20 21 22 23 24 25 26 27 28
 *
 * \brief Threading API.
 *
 * Dynamic threads provide:
 * - coherent and incoherent threading capabilities
 * - thread repurposing
 * - thread prioritization
 * - on-the-fly changing of threading unit size
 *
Marek Vavrusa's avatar
Marek Vavrusa committed
29 30 31 32 33 34
 * Coherent threading unit is when all threads execute
 * the same runnable function.
 *
 * Incoherent function is when at least one thread executes
 * a different runnable than the others.
 *
35
 * \addtogroup threading
Marek Vavrusa's avatar
Marek Vavrusa committed
36 37 38
 * @{
 */

Lubos Slovak's avatar
Lubos Slovak committed
39 40
#ifndef _KNOTD_DTHREADS_H_
#define _KNOTD_DTHREADS_H_
Marek Vavrusa's avatar
Marek Vavrusa committed
41 42 43 44 45

#include <pthread.h>

/* Forward decls */
struct dthread_t;
Marek Vavrusa's avatar
Marek Vavrusa committed
46
struct dt_unit_t;
Marek Vavrusa's avatar
Marek Vavrusa committed
47

48 49 50
/* Constants. */
#define DTHREADS_STACKSIZE (1024*1024) /* 1M lightweight stack size. */

Marek Vavrusa's avatar
Marek Vavrusa committed
51 52 53
/*!
 * \brief Thread state enumeration.
 */
Marek Vavrusa's avatar
Marek Vavrusa committed
54
typedef enum {
Marek Vavrusa's avatar
Marek Vavrusa committed
55
	ThreadJoined    = 1 << 0, /*!< Thread is finished and joined. */
Marek Vavrusa's avatar
Marek Vavrusa committed
56
	ThreadJoinable  = 1 << 1, /*!< Thread is waiting to be reclaimed. */
Marek Vavrusa's avatar
Marek Vavrusa committed
57 58 59 60
	ThreadCancelled = 1 << 2, /*!< Thread is cancelled, finishing task. */
	ThreadDead      = 1 << 3, /*!< Thread is finished, exiting. */
	ThreadIdle      = 1 << 4, /*!< Thread is idle, waiting for purpose. */
	ThreadActive    = 1 << 5  /*!< Thread is active, working on a task. */
Marek Vavrusa's avatar
Marek Vavrusa committed
61 62 63 64 65 66

} dt_state_t;

/*!
 * \brief Thread runnable prototype.
 *
Marek Vavrusa's avatar
Marek Vavrusa committed
67 68 69 70 71
 * Runnable is basically a pointer to function which is called on active
 * thread runtime.
 *
 * \note When implementing a runnable, keep in mind to check thread state as
 *       it may change, and implement a cooperative cancellation point.
Marek Vavrusa's avatar
Marek Vavrusa committed
72
 *
Marek Vavrusa's avatar
Marek Vavrusa committed
73
 *       Implement this by checking dt_is_cancelled() and return
Marek Vavrusa's avatar
Marek Vavrusa committed
74 75
 *       as soon as possible.
 */
Marek Vavrusa's avatar
Marek Vavrusa committed
76
typedef int (*runnable_t)(struct dthread_t *);
Marek Vavrusa's avatar
Marek Vavrusa committed
77 78 79 80

/*!
 * \brief Single thread descriptor public API.
 */
Marek Vavrusa's avatar
Marek Vavrusa committed
81
typedef struct dthread_t {
Marek Vavrusa's avatar
Marek Vavrusa committed
82 83 84 85 86
	volatile unsigned  state; /*!< Bitfield of dt_flag flags. */
	runnable_t           run; /*!< Runnable function or 0. */
	void               *data; /*!< Currently active data */
	struct dt_unit_t   *unit; /*!< Reference to assigned unit. */
	void             *_adata; /* Thread-specific data. */
Marek Vavrusa's avatar
Marek Vavrusa committed
87 88
	pthread_t           _thr; /* Thread */
	pthread_attr_t     _attr; /* Thread attributes */
Marek Vavrusa's avatar
Marek Vavrusa committed
89
	pthread_mutex_t      _mx; /* Thread state change lock. */
Marek Vavrusa's avatar
Marek Vavrusa committed
90 91 92 93 94 95 96 97 98
} dthread_t;

/*!
 * \brief Thread unit descriptor API.
 *
 * Thread unit consists of 1..N threads.
 * Unit is coherent if all threads execute
 * the same runnable.
 */
Marek Vavrusa's avatar
Marek Vavrusa committed
99
typedef struct dt_unit_t {
Marek Vavrusa's avatar
Marek Vavrusa committed
100
	int                   size; /*!< Unit width (number of threads) */
Marek Vavrusa's avatar
Marek Vavrusa committed
101 102 103 104 105 106
	struct dthread_t **threads; /*!< Array of threads */
	pthread_cond_t     _notify; /* Notify thread */
	pthread_mutex_t _notify_mx; /* Condition mutex */
	pthread_cond_t     _report; /* Report thread state */
	pthread_mutex_t _report_mx; /* Condition mutex */
	pthread_mutex_t        _mx; /* Unit lock */
Marek Vavrusa's avatar
Marek Vavrusa committed
107 108 109 110 111
} dt_unit_t;

/*!
 * \brief Create a set of threads with no initial runnable.
 *
112 113 114
 * \note All threads are created with Dead state.
 *       This means, they're not physically created unit dt_start() is called.
 *
Marek Vavrusa's avatar
Marek Vavrusa committed
115
 * \param count Requested thread count.
116
 *
117 118
 * \retval New instance if successful
 * \retval NULL on error
Marek Vavrusa's avatar
Marek Vavrusa committed
119
 */
120
dt_unit_t *dt_create(int count);
Marek Vavrusa's avatar
Marek Vavrusa committed
121 122 123 124

/*!
 * \brief Create a set of coherent threads.
 *
Marek Vavrusa's avatar
Marek Vavrusa committed
125 126
 * Coherent means, that the threads will share a common runnable and the data.
 *
Marek Vavrusa's avatar
Marek Vavrusa committed
127 128 129
 * \param count Requested thread count.
 * \param runnable Runnable function for all threads.
 * \param data Any data passed onto threads.
130
 *
131 132
 * \retval New instance if successful
 * \retval NULL on error
Marek Vavrusa's avatar
Marek Vavrusa committed
133
 */
134
dt_unit_t *dt_create_coherent(int count, runnable_t runnable, void *data);
Marek Vavrusa's avatar
Marek Vavrusa committed
135 136 137 138

/*!
 * \brief Free unit.
 *
Marek Vavrusa's avatar
Marek Vavrusa committed
139 140
 * \warning Behavior is undefined if threads are still active, make sure
 *          to call dt_join() first.
141 142
 *
 * \param unit Unit to be deleted.
Marek Vavrusa's avatar
Marek Vavrusa committed
143
 */
144
void dt_delete(dt_unit_t **unit);
Marek Vavrusa's avatar
Marek Vavrusa committed
145

146 147 148
/*!
 * \brief Resize unit to given number.
 *
Marek Vavrusa's avatar
Marek Vavrusa committed
149 150 151
 * \note Newly created dthreads will have no runnable or data, their state
 *       will be ThreadJoined (that means no thread will be physically created
 *       until the next dt_start()).
152
 *
Marek Vavrusa's avatar
Marek Vavrusa committed
153 154
 * \warning Be careful when shrinking unit, joined and idle threads are
 *          reclaimed first, but it may kill your active threads
155
 *          as a last resort.
Marek Vavrusa's avatar
Marek Vavrusa committed
156 157
 *          Threads will stop at their nearest cancellation point,
 *          so this is potentially an expensive and blocking operation.
158
 *
159
 * \param unit Unit to be resized.
160
 * \param size New unit size.
161
 *
Lubos Slovak's avatar
Lubos Slovak committed
162 163 164
 * \retval KNOTD_EOK on success.
 * \retval KNOTD_EINVAL on invalid parameters.
 * \retval KNOTD_ENOMEM out of memory error.
165 166 167
 */
int dt_resize(dt_unit_t *unit, int size);

Marek Vavrusa's avatar
Marek Vavrusa committed
168 169 170
/*!
 * \brief Start all threads in selected unit.
 *
171
 * \param unit Unit to be started.
172
 *
Lubos Slovak's avatar
Lubos Slovak committed
173 174
 * \retval KNOTD_EOK on success.
 * \retval KNOTD_EINVAL on invalid parameters (unit is null).
Marek Vavrusa's avatar
Marek Vavrusa committed
175
 */
176
int dt_start(dt_unit_t *unit);
Marek Vavrusa's avatar
Marek Vavrusa committed
177

178 179 180
/*!
 * \brief Start given thread.
 *
181
 * \param thread Target thread instance.
182
 *
Lubos Slovak's avatar
Lubos Slovak committed
183 184
 * \retval KNOTD_EOK on success.
 * \retval KNOTD_EINVAL on invalid parameters.
185
 */
186
int dt_start_id(dthread_t *thread);
187

Marek Vavrusa's avatar
Marek Vavrusa committed
188
/*!
189
 * \brief Send given signal to thread.
Marek Vavrusa's avatar
Marek Vavrusa committed
190
 *
Marek Vavrusa's avatar
Marek Vavrusa committed
191 192
 * \note This is useful to interrupt some blocking I/O as well, for example
 *       with SIGALRM, which is handled by default.
193
 * \note Signal handler may be overriden in runnable.
Marek Vavrusa's avatar
Marek Vavrusa committed
194
 *
195
 * \param thread Target thread instance.
Marek Vavrusa's avatar
Marek Vavrusa committed
196
 * \param signum Signal code.
197
 *
Lubos Slovak's avatar
Lubos Slovak committed
198 199 200
 * \retval KNOTD_EOK on success.
 * \retval KNOTD_EINVAL on invalid parameters.
 * \retval KNOTD_ERROR unspecified error.
Marek Vavrusa's avatar
Marek Vavrusa committed
201
 */
202
int dt_signalize(dthread_t *thread, int signum);
Marek Vavrusa's avatar
Marek Vavrusa committed
203 204

/*!
205
 * \brief Wait for all thread in unit to finish.
Marek Vavrusa's avatar
Marek Vavrusa committed
206
 *
207
 * \param unit Unit to be joined.
208
 *
Lubos Slovak's avatar
Lubos Slovak committed
209 210
 * \retval KNOTD_EOK on success.
 * \retval KNOTD_EINVAL on invalid parameters.
Marek Vavrusa's avatar
Marek Vavrusa committed
211
 */
212
int dt_join(dt_unit_t *unit);
Marek Vavrusa's avatar
Marek Vavrusa committed
213

Marek Vavrusa's avatar
Marek Vavrusa committed
214
/*!
215
 * \brief Stop thread from running.
Marek Vavrusa's avatar
Marek Vavrusa committed
216
 *
Marek Vavrusa's avatar
Marek Vavrusa committed
217
 * Active thread is interrupted at the nearest runnable cancellation point.
Marek Vavrusa's avatar
Marek Vavrusa committed
218
 *
219
 * \param thread Target thread instance.
220
 *
Lubos Slovak's avatar
Lubos Slovak committed
221 222
 * \retval KNOTD_EOK on success.
 * \retval KNOTD_EINVAL on invalid parameters.
Marek Vavrusa's avatar
Marek Vavrusa committed
223
 */
Marek Vavrusa's avatar
Marek Vavrusa committed
224
int dt_stop_id(dthread_t *thread);
225 226

/*!
227
 * \brief Stop all threads in unit.
228
 *
Marek Vavrusa's avatar
Marek Vavrusa committed
229
 * Thread is interrupted at the nearest runnable cancellation point.
230
 *
231
 * \param unit Unit to be stopped.
232
 *
Lubos Slovak's avatar
Lubos Slovak committed
233 234
 * \retval KNOTD_EOK on success.
 * \retval KNOTD_EINVAL on invalid parameters.
235
 */
236
int dt_stop(dt_unit_t *unit);
Marek Vavrusa's avatar
Marek Vavrusa committed
237

Marek Vavrusa's avatar
Marek Vavrusa committed
238 239 240
/*!
 * \brief Modify thread priority.
 *
241
 * \param thread Target thread instance.
Marek Vavrusa's avatar
Marek Vavrusa committed
242
 * \param prio Requested priority (positive integer, default is 0).
243
 *
244 245 246 247
 * \warning Thread priority setting is disabled as the compatible scheduler
 *          has significant performance deficiencies (SCHED_OTHER).
 *          (issue #1809)
 *
Lubos Slovak's avatar
Lubos Slovak committed
248 249
 * \retval KNOTD_EOK on success.
 * \retval KNOTD_EINVAL on invalid parameters.
Marek Vavrusa's avatar
Marek Vavrusa committed
250
 */
251
//int dt_setprio(dthread_t *thread, int prio);
Marek Vavrusa's avatar
Marek Vavrusa committed
252

253 254 255 256
/*!
 * \brief Set thread affinity to masked CPU's.
 *
 * \param thread Target thread instance.
257 258
 * \param cpu_id Array of CPU IDs to set affinity to.
 * \param cpu_count Number of CPUs in the array, set to 0 for no CPU.
259 260 261 262
 *
 * \retval KNOTD_EOK on success.
 * \retval KNOTD_EINVAL on invalid parameters.
 */
263
int dt_setaffinity(dthread_t *thread, unsigned* cpu_id, size_t cpu_count);
264

Marek Vavrusa's avatar
Marek Vavrusa committed
265
/*!
Marek Vavrusa's avatar
Marek Vavrusa committed
266
 * \brief Set thread to execute another runnable.
Marek Vavrusa's avatar
Marek Vavrusa committed
267
 *
268
 * \param thread Target thread instance.
Marek Vavrusa's avatar
Marek Vavrusa committed
269 270
 * \param runnable  Runnable function for target thread.
 * \param data      Data passed to target thread.
271
 *
Lubos Slovak's avatar
Lubos Slovak committed
272 273 274
 * \retval KNOTD_EOK on success.
 * \retval KNOTD_EINVAL on invalid parameters.
 * \retval KNOTD_ENOTSUP operation not supported.
Marek Vavrusa's avatar
Marek Vavrusa committed
275
 */
Marek Vavrusa's avatar
Marek Vavrusa committed
276
int dt_repurpose(dthread_t *thread, runnable_t runnable, void *data);
Marek Vavrusa's avatar
Marek Vavrusa committed
277

278 279 280
/*!
 * \brief Wake up thread from idle state.
 *
281 282 283 284 285
 * Thread is awoken from idle state and reenters runnable.
 * This function only affects idle threads.
 *
 * \note Unit needs to be started with dt_start() first, as the function
 *       doesn't affect dead threads.
286 287
 *
 * \param thread Target thread instance.
288
 *
Lubos Slovak's avatar
Lubos Slovak committed
289 290 291
 * \retval KNOTD_EOK on success.
 * \retval KNOTD_EINVAL on invalid parameters.
 * \retval KNOTD_ENOTSUP operation not supported.
292
 */
293
int dt_activate(dthread_t *thread);
294

Marek Vavrusa's avatar
Marek Vavrusa committed
295 296 297 298 299 300
/*!
 * \brief Put thread to idle state, cancells current runnable function.
 *
 * Thread is flagged with Cancel flag and returns from runnable at the nearest
 * cancellation point, which requires complying runnable function.
 *
Marek Vavrusa's avatar
Marek Vavrusa committed
301 302
 * \note Thread isn't disposed, but put to idle state until it's requested
 *       again or collected by dt_compact().
Marek Vavrusa's avatar
Marek Vavrusa committed
303
 *
304
 * \param thread Target thread instance.
305
 *
Lubos Slovak's avatar
Lubos Slovak committed
306 307
 * \retval KNOTD_EOK on success.
 * \retval KNOTD_EINVAL on invalid parameters.
Marek Vavrusa's avatar
Marek Vavrusa committed
308
 */
309
int dt_cancel(dthread_t *thread);
Marek Vavrusa's avatar
Marek Vavrusa committed
310 311 312 313

/*!
 * \brief Collect and dispose idle threads.
 *
314
 * \param unit Target unit instance.
315
 *
Lubos Slovak's avatar
Lubos Slovak committed
316 317
 * \retval KNOTD_EOK on success.
 * \retval KNOTD_EINVAL on invalid parameters.
Marek Vavrusa's avatar
Marek Vavrusa committed
318
 */
319
int dt_compact(dt_unit_t *unit);
Marek Vavrusa's avatar
Marek Vavrusa committed
320

321 322 323 324 325 326 327 328
/*!
 * \brief Return number of online processors.
 *
 * \retval Number of online CPU's if success.
 * \retval <0 on failure.
 */
int dt_online_cpus();

329 330 331
/*!
 * \brief Return optimal number of threads for instance.
 *
332
 * It is estimated as NUM_CPUs + CONSTANT.
333 334
 * Fallback is DEFAULT_THR_COUNT  (\see common.h).
 *
335
 * \return Number of threads.
336
 */
337
int dt_optimal_size();
338

339 340 341 342
/*!
 * \brief Return true if thread is cancelled.
 *
 * Synchronously check for ThreadCancelled flag.
343 344
 *
 * \param thread Target thread instance.
345
 *
346 347
 * \retval 1 if cancelled.
 * \retval 0 if not cancelled.
348
 */
349
int dt_is_cancelled(dthread_t *thread);
Marek Vavrusa's avatar
Marek Vavrusa committed
350

351 352 353 354 355 356 357 358 359 360 361 362

/*!
 * \brief Return thread index in threading unit.
 *
 * \note Returns 0 when thread doesn't have a unit.
 *
 * \param thread Target thread instance.
 *
 * \return Thread index.
 */
unsigned dt_get_id(dthread_t *thread);

363 364 365 366
/*!
 * \brief Lock unit to prevent parallel operations which could alter unit
 *        at the same time.
 *
367
 * \param unit Target unit instance.
368
 *
Lubos Slovak's avatar
Lubos Slovak committed
369 370 371 372
 * \retval KNOTD_EOK on success.
 * \retval KNOTD_EINVAL on invalid parameters.
 * \retval KNOTD_EAGAIN lack of resources to lock unit, try again.
 * \retval KNOTD_ERROR unspecified error.
373 374 375 376 377 378 379 380
 */
int dt_unit_lock(dt_unit_t *unit);

/*!
 * \brief Unlock unit.
 *
 * \see dt_unit_lock()
 *
381
 * \param unit Target unit instance.
382
 *
Lubos Slovak's avatar
Lubos Slovak committed
383 384 385 386
 * \retval KNOTD_EOK on success.
 * \retval KNOTD_EINVAL on invalid parameters.
 * \retval KNOTD_EAGAIN lack of resources to unlock unit, try again.
 * \retval KNOTD_ERROR unspecified error.
387 388 389
 */
int dt_unit_unlock(dt_unit_t *unit);

Lubos Slovak's avatar
Lubos Slovak committed
390
#endif // _KNOTD_DTHREADS_H_
Marek Vavrusa's avatar
Marek Vavrusa committed
391

392
/*! @} */