summaryrefslogtreecommitdiff
path: root/include/asterisk/threadpool.h
blob: 0f360c7a4a49539d567fd19b04544c470e2d7360 (plain)
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
/*
 * Asterisk -- An open source telephony toolkit.
 *
 * Copyright (C) 2012-2013, Digium, Inc.
 *
 * Mark Michelson <mmmichelson@digium.com>
 *
 * See http://www.asterisk.org for more information about
 * the Asterisk project. Please do not directly contact
 * any of the maintainers of this project for assistance;
 * the project provides a web site, mailing lists and IRC
 * channels for your use.
 *
 * This program is free software, distributed under the terms of
 * the GNU General Public License Version 2. See the LICENSE file
 * at the top of the source tree.
 */


#ifndef _ASTERISK_THREADPOOL_H
#define _ASTERISK_THREADPOOL_H

struct ast_threadpool;
struct ast_taskprocessor;
struct ast_threadpool_listener;

struct ast_threadpool_listener_callbacks {
	/*!
	 * \brief Indicates that the state of threads in the pool has changed
	 *
	 * \param pool The pool whose state has changed
	 * \param listener The threadpool listener
	 * \param active_threads The number of active threads in the pool
	 * \param idle_threads The number of idle threads in the pool
	 */
	void (*state_changed)(struct ast_threadpool *pool,
			struct ast_threadpool_listener *listener,
			int active_threads,
			int idle_threads);
	/*!
	 * \brief Indicates that a task was pushed to the threadpool
	 *
	 * \param pool The pool that had a task pushed
	 * \param listener The threadpool listener
	 * \param was_empty Indicates whether there were any tasks prior to adding the new one.
	 */
	void (*task_pushed)(struct ast_threadpool *pool,
			struct ast_threadpool_listener *listener,
			int was_empty);
	/*!
	 * \brief Indicates the threadpool's taskprocessor has become empty
	 *
	 * \param pool The pool that has become empty
	 * \param listener The threadpool's listener
	 */
	void (*emptied)(struct ast_threadpool *pool, struct ast_threadpool_listener *listener);

	/*!
	 * \brief The threadpool is shutting down
	 *
	 * This would be an opportune time to free the listener's user data
	 * if one wishes. However, it is acceptable to not do so if the user data
	 * should persist beyond the lifetime of the pool.
	 *
	 * \param listener The threadpool's listener
	 */
	void (*shutdown)(struct ast_threadpool_listener *listener);
};

struct ast_threadpool_options {
#define AST_THREADPOOL_OPTIONS_VERSION 1
	/*! Version of threadpool options in use */
	int version;
	/*!
	 * \brief Time limit in seconds for idle threads
	 *
	 * A time of 0 or less will mean no timeout.
	 */
	int idle_timeout;
	/*!
	 * \brief Number of threads to increment pool by
	 *
	 * If a task is added into a pool and no idle thread is
	 * available to activate, then the pool can automatically
	 * grow by the given amount.
	 *
	 * Zero is a perfectly valid value to give here if you want
	 * to control threadpool growth yourself via your listener.
	 */
	int auto_increment;
	/*!
	 * \brief Number of threads the pool will start with
	 *
	 * When the threadpool is allocated, it will immediately size
	 * itself to have this number of threads in it.
	 *
	 * Zero is a valid value if the threadpool should start
	 * without any threads allocated.
	 */
	int initial_size;
	/*!
	 * \brief Maximum number of threads a pool may have
	 *
	 * When the threadpool's size increases, it can never increase
	 * beyond this number of threads.
	 *
	 * Zero is a valid value if the threadpool does not have a
	 * maximum size.
	 */
	int max_size;
	/*!
	 * \brief Function to call when a thread starts
	 *
	 * This is useful if there is something common that all threads
	 * in a threadpool need to do when they start.
	 */
	void (*thread_start)(void);
	/*!
	 * \brief Function to call when a thread ends
	 *
	 * This is useful if there is common cleanup to execute when
	 * a thread completes
	 */
	void (*thread_end)(void);
};

/*!
 * \brief Allocate a threadpool listener
 *
 * This function will call back into the alloc callback for the
 * listener.
 *
 * \param callbacks Listener callbacks to assign to the listener
 * \param user_data User data to be stored in the threadpool listener
 * \retval NULL Failed to allocate the listener
 * \retval non-NULL The newly-created threadpool listener
 */
struct ast_threadpool_listener *ast_threadpool_listener_alloc(
		const struct ast_threadpool_listener_callbacks *callbacks, void *user_data);

/*!
 * \brief Get the threadpool listener's user data
 * \param listener The threadpool listener
 * \return The user data
 */
void *ast_threadpool_listener_get_user_data(const struct ast_threadpool_listener *listener);

/*!
 * \brief Create a new threadpool
 *
 * This function creates a threadpool. Tasks may be pushed onto this thread pool
 * and will be automatically acted upon by threads within the pool.
 *
 * Only a single threadpool with a given name may exist. This function will fail
 * if a threadpool with the given name already exists.
 *
 * \param name The unique name for the threadpool
 * \param listener The listener the threadpool will notify of changes. Can be NULL.
 * \param options The behavioral options for this threadpool
 * \retval NULL Failed to create the threadpool
 * \retval non-NULL The newly-created threadpool
 */
struct ast_threadpool *ast_threadpool_create(const char *name,
		struct ast_threadpool_listener *listener,
		const struct ast_threadpool_options *options);

/*!
 * \brief Set the number of threads for the thread pool
 *
 * This number may be more or less than the current number of
 * threads in the threadpool.
 *
 * \param threadpool The threadpool to adjust
 * \param size The new desired size of the threadpool
 */
void ast_threadpool_set_size(struct ast_threadpool *threadpool, unsigned int size);

/*!
 * \brief Push a task to the threadpool
 *
 * Tasks pushed into the threadpool will be automatically taken by
 * one of the threads within
 * \param pool The threadpool to add the task to
 * \param task The task to add
 * \param data The parameter for the task
 * \retval 0 success
 * \retval -1 failure
 */
int ast_threadpool_push(struct ast_threadpool *pool, int (*task)(void *data), void *data);

/*!
 * \brief Shut down a threadpool and destroy it
 *
 * \param pool The pool to shut down
 */
void ast_threadpool_shutdown(struct ast_threadpool *pool);

struct ast_serializer_shutdown_group;

/*!
 * \brief Create a serializer group shutdown control object.
 * \since 13.5.0
 *
 * \return ao2 object to control shutdown of a serializer group.
 */
struct ast_serializer_shutdown_group *ast_serializer_shutdown_group_alloc(void);

/*!
 * \brief Wait for the serializers in the group to shutdown with timeout.
 * \since 13.5.0
 *
 * \param shutdown_group Group shutdown controller. (Returns 0 immediately if NULL)
 * \param timeout Number of seconds to wait for the serializers in the group to shutdown.
 *     Zero if the timeout is disabled.
 *
 * \return Number of seriaizers that did not get shutdown within the timeout.
 */
int ast_serializer_shutdown_group_join(struct ast_serializer_shutdown_group *shutdown_group, int timeout);

/*!
 * \brief Get the threadpool serializer currently associated with this thread.
 * \since 14.0.0
 *
 * \note The returned pointer is valid while the serializer
 * thread is running.
 *
 * \note Use ao2_ref() on serializer if you are going to keep it
 * for another thread.  To unref it you must then use
 * ast_taskprocessor_unreference().
 *
 * \retval serializer on success.
 * \retval NULL on error or no serializer associated with the thread.
 */
struct ast_taskprocessor *ast_threadpool_serializer_get_current(void);

/*!
 * \brief Serialized execution of tasks within a \ref ast_threadpool.
 *
 * \since 12.0.0
 *
 * A \ref ast_taskprocessor with the same contract as a default taskprocessor
 * (tasks execute serially) except instead of executing out of a dedicated
 * thread, execution occurs in a thread from a \ref ast_threadpool. Think of it
 * as a lightweight thread.
 *
 * While it guarantees that each task will complete before executing the next,
 * there is no guarantee as to which thread from the \c pool individual tasks
 * will execute. This normally only matters if your code relys on thread
 * specific information, such as thread locals.
 *
 * Use ast_taskprocessor_unreference() to dispose of the returned \ref
 * ast_taskprocessor.
 *
 * Only a single taskprocessor with a given name may exist. This function will fail
 * if a taskprocessor with the given name already exists.
 *
 * \param name Name of the serializer. (must be unique)
 * \param pool \ref ast_threadpool for execution.
 *
 * \return \ref ast_taskprocessor for enqueuing work.
 * \return \c NULL on error.
 */
struct ast_taskprocessor *ast_threadpool_serializer(const char *name, struct ast_threadpool *pool);

/*!
 * \brief Serialized execution of tasks within a \ref ast_threadpool.
 * \since 13.5.0
 *
 * A \ref ast_taskprocessor with the same contract as a default taskprocessor
 * (tasks execute serially) except instead of executing out of a dedicated
 * thread, execution occurs in a thread from a \ref ast_threadpool. Think of it
 * as a lightweight thread.
 *
 * While it guarantees that each task will complete before executing the next,
 * there is no guarantee as to which thread from the \c pool individual tasks
 * will execute. This normally only matters if your code relys on thread
 * specific information, such as thread locals.
 *
 * Use ast_taskprocessor_unreference() to dispose of the returned \ref
 * ast_taskprocessor.
 *
 * Only a single taskprocessor with a given name may exist. This function will fail
 * if a taskprocessor with the given name already exists.
 *
 * \param name Name of the serializer. (must be unique)
 * \param pool \ref ast_threadpool for execution.
 * \param shutdown_group Group shutdown controller. (NULL if no group association)
 *
 * \return \ref ast_taskprocessor for enqueuing work.
 * \return \c NULL on error.
 */
struct ast_taskprocessor *ast_threadpool_serializer_group(const char *name,
	struct ast_threadpool *pool, struct ast_serializer_shutdown_group *shutdown_group);

/*!
 * \brief Return the size of the threadpool's task queue
 * \since 13.7.0
 */
long ast_threadpool_queue_size(struct ast_threadpool *pool);

#endif /* ASTERISK_THREADPOOL_H */