summaryrefslogtreecommitdiff
path: root/include/asterisk/taskprocessor.h
blob: 219166305749dee17224689c8c337c24a776b150 (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
/*
 * Asterisk -- An open source telephony toolkit.
 *
 * Copyright (C) 2007-2013, Digium, Inc.
 *
 * Dwayne M. Hubbard <dhubbard@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.
 */

/*!
 * \file taskprocessor.h
 * \brief An API for managing task processing threads that can be shared across modules
 *
 * \author Dwayne M. Hubbard <dhubbard@digium.com>
 *
 * \note A taskprocessor is a named object containing a task queue that
 * serializes tasks pushed into it by [a] module(s) that reference the taskprocessor.
 * A taskprocessor is created the first time its name is requested via the
 * ast_taskprocessor_get() function or the ast_taskprocessor_create_with_listener()
 * function and destroyed when the taskprocessor reference count reaches zero. A
 * taskprocessor also contains an accompanying listener that is notified when changes
 * in the task queue occur.
 *
 * A task is a wrapper around a task-handling function pointer and a data
 * pointer.  A task is pushed into a taskprocessor queue using the
 * ast_taskprocessor_push(taskprocessor, taskhandler, taskdata) function and freed by the
 * taskprocessor after the task handling function returns.  A module releases its
 * reference to a taskprocessor using the ast_taskprocessor_unreference() function which
 * may result in the destruction of the taskprocessor if the taskprocessor's reference
 * count reaches zero. When the taskprocessor's reference count reaches zero, its
 * listener's shutdown() callback will be called. Any further attempts to execute tasks
 * will be denied.
 *
 * The taskprocessor listener has the flexibility of doling out tasks to best fit the
 * module's needs. For instance, a taskprocessor listener may have a single dispatch
 * thread that handles all tasks, or it may dispatch tasks to a thread pool.
 *
 * There is a default taskprocessor listener that will be used if a taskprocessor is
 * created without any explicit listener. This default listener runs tasks sequentially
 * in a single thread. The listener will execute tasks as long as there are tasks to be
 * processed. When the taskprocessor is shut down, the default listener will stop
 * processing tasks and join its execution thread.
 */

#ifndef __AST_TASKPROCESSOR_H__
#define __AST_TASKPROCESSOR_H__

struct ast_taskprocessor;

/*!
 * \brief ast_tps_options for specification of taskprocessor options
 *
 * Specify whether a taskprocessor should be created via ast_taskprocessor_get() if the taskprocessor
 * does not already exist.  The default behavior is to create a taskprocessor if it does not already exist
 * and provide its reference to the calling function.  To only return a reference to a taskprocessor if
 * and only if it exists, use the TPS_REF_IF_EXISTS option in ast_taskprocessor_get().
 */
enum ast_tps_options {
	/*! \brief return a reference to a taskprocessor, create one if it does not exist */
	TPS_REF_DEFAULT = 0,
	/*! \brief return a reference to a taskprocessor ONLY if it already exists */
	TPS_REF_IF_EXISTS = (1 << 0),
};

struct ast_taskprocessor_listener;

struct ast_taskprocessor_listener_callbacks {
	/*!
	 * \brief The taskprocessor has started completely
	 *
	 * This indicates that the taskprocessor is fully set up and the listener
	 * can now start interacting with it.
	 *
	 * \param listener The listener to start
	 */
	int (*start)(struct ast_taskprocessor_listener *listener);
	/*!
	 * \brief Indicates a task was pushed to the processor
	 *
	 * \param listener The listener
	 * \param was_empty If non-zero, the taskprocessor was empty prior to the task being pushed
	 */
	void (*task_pushed)(struct ast_taskprocessor_listener *listener, int was_empty);
	/*!
	 * \brief Indicates the task processor has become empty
	 *
	 * \param listener The listener
	 */
	void (*emptied)(struct ast_taskprocessor_listener *listener);
	/*!
	 * \brief Indicates the taskprocessor wishes to die.
	 *
	 * All operations on the task processor must to be stopped in
	 * this callback. This is an opportune time to free the listener's
	 * user data if it is not going to be used anywhere else.
	 *
	 * After this callback returns, it is NOT safe to operate on the
	 * listener's reference to the taskprocessor.
	 *
	 * \param listener The listener
	 */
	void (*shutdown)(struct ast_taskprocessor_listener *listener);
};

/*!
 * \brief Get a reference to the listener's taskprocessor
 *
 * This will return the taskprocessor with its reference count increased. Release
 * the reference to this object by using ast_taskprocessor_unreference()
 *
 * \param listener The listener that has the taskprocessor
 * \return The taskprocessor
 */
struct ast_taskprocessor *ast_taskprocessor_listener_get_tps(const struct ast_taskprocessor_listener *listener);

/*!
 * \brief Get the user data from the listener
 * \param listener The taskprocessor listener
 * \return The listener's user data
 */
void *ast_taskprocessor_listener_get_user_data(const struct ast_taskprocessor_listener *listener);

/*!
 * \brief Allocate a taskprocessor listener
 *
 * \since 12.0.0
 *
 * This will result in the listener being allocated with the specified
 * callbacks.
 *
 * \param callbacks The callbacks to assign to the listener
 * \param user_data The user data for the listener
 * \retval NULL Failure
 * \retval non-NULL The newly allocated taskprocessor listener
 */
struct ast_taskprocessor_listener *ast_taskprocessor_listener_alloc(const struct ast_taskprocessor_listener_callbacks *callbacks, void *user_data);

/*!
 * \brief Get a reference to a taskprocessor with the specified name and create the taskprocessor if necessary
 *
 * The default behavior of instantiating a taskprocessor if one does not already exist can be
 * disabled by specifying the TPS_REF_IF_EXISTS ast_tps_options as the second argument to ast_taskprocessor_get().
 * \param name The name of the taskprocessor
 * \param create Use 0 by default or specify TPS_REF_IF_EXISTS to return NULL if the taskprocessor does
 * not already exist
 * return A pointer to a reference counted taskprocessor under normal conditions, or NULL if the
 * TPS_REF_IF_EXISTS reference type is specified and the taskprocessor does not exist
 * \since 1.6.1
 */
struct ast_taskprocessor *ast_taskprocessor_get(const char *name, enum ast_tps_options create);

/*!
 * \brief Create a taskprocessor with a custom listener
 *
 * \since 12.0.0
 *
 * Note that when a taskprocessor is created in this way, it does not create
 * any threads to execute the tasks. This job is left up to the listener.
 * The listener's start() callback will be called during this function.
 *
 * \param name The name of the taskprocessor to create
 * \param listener The listener for operations on this taskprocessor
 * \retval NULL Failure
 * \reval non-NULL success
 */
struct ast_taskprocessor *ast_taskprocessor_create_with_listener(const char *name, struct ast_taskprocessor_listener *listener);

/*!
 * \brief Unreference the specified taskprocessor and its reference count will decrement.
 *
 * Taskprocessors use astobj2 and will unlink from the taskprocessor singleton container and destroy
 * themself when the taskprocessor reference count reaches zero.
 * \param tps taskprocessor to unreference
 * \return NULL
 * \since 1.6.1
 */
void *ast_taskprocessor_unreference(struct ast_taskprocessor *tps);

/*!
 * \brief Push a task into the specified taskprocessor queue and signal the taskprocessor thread
 * \param tps The taskprocessor structure
 * \param task_exe The task handling function to push into the taskprocessor queue
 * \param datap The data to be used by the task handling function
 * \retval 0 success
 * \retval -1 failure
 * \since 1.6.1
 */
int ast_taskprocessor_push(struct ast_taskprocessor *tps, int (*task_exe)(void *datap), void *datap);

/*!
 * \brief Pop a task off the taskprocessor and execute it.
 *
 * \since 12.0.0
 *
 * \param tps The taskprocessor from which to execute.
 * \retval 0 There is no further work to be done.
 * \retval 1 Tasks still remain in the taskprocessor queue.
 */
int ast_taskprocessor_execute(struct ast_taskprocessor *tps);

/*!
 * \brief Return the name of the taskprocessor singleton
 * \since 1.6.1
 */
const char *ast_taskprocessor_name(struct ast_taskprocessor *tps);

#endif /* __AST_TASKPROCESSOR_H__ */