Wed Jan 8 2020 09:49:51

Asterisk developer's documentation


taskprocessor.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2007-2008, Digium, Inc.
5  *
6  * Dwayne M. Hubbard <dhubbard@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*!
20  * \file
21  * \brief Maintain a container of uniquely-named taskprocessor threads that can be shared across modules.
22  *
23  * \author Dwayne Hubbard <dhubbard@digium.com>
24  */
25 
26 /*** MODULEINFO
27  <support_level>core</support_level>
28  ***/
29 
30 #include "asterisk.h"
31 
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413586 $")
33 
34 #include "asterisk/_private.h"
35 #include "asterisk/module.h"
36 #include "asterisk/time.h"
37 #include "asterisk/astobj2.h"
38 #include "asterisk/cli.h"
39 #include "asterisk/taskprocessor.h"
40 
41 
42 /*!
43  * \brief tps_task structure is queued to a taskprocessor
44  *
45  * tps_tasks are processed in FIFO order and freed by the taskprocessing
46  * thread after the task handler returns. The callback function that is assigned
47  * to the execute() function pointer is responsible for releasing datap resources if necessary.
48  */
49 struct tps_task {
50  /*! \brief The execute() task callback function pointer */
51  int (*execute)(void *datap);
52  /*! \brief The data pointer for the task execute() function */
53  void *datap;
54  /*! \brief AST_LIST_ENTRY overhead */
56 };
57 
58 /*! \brief tps_taskprocessor_stats maintain statistics for a taskprocessor. */
60  /*! \brief This is the maximum number of tasks queued at any one time */
61  unsigned long max_qsize;
62  /*! \brief This is the current number of tasks processed */
63  unsigned long _tasks_processed_count;
64 };
65 
66 /*! \brief A ast_taskprocessor structure is a singleton by name */
68  /*! \brief Friendly name of the taskprocessor */
69  const char *name;
70  /*! \brief Thread poll condition */
72  /*! \brief Taskprocessor thread */
73  pthread_t poll_thread;
74  /*! \brief Taskprocessor lock */
76  /*! \brief Taskprocesor thread run flag */
77  unsigned char poll_thread_run;
78  /*! \brief Taskprocessor statistics */
80  /*! \brief Taskprocessor current queue size */
82  /*! \brief Taskprocessor queue */
84  /*! \brief Taskprocessor singleton list entry */
86 };
87 #define TPS_MAX_BUCKETS 7
88 /*! \brief tps_singletons is the astobj2 container for taskprocessor singletons */
90 
91 /*! \brief CLI <example>taskprocessor ping &lt;blah&gt;</example> operation requires a ping condition */
93 
94 /*! \brief CLI <example>taskprocessor ping &lt;blah&gt;</example> operation requires a ping condition lock */
96 
97 /*! \brief The astobj2 hash callback for taskprocessors */
98 static int tps_hash_cb(const void *obj, const int flags);
99 /*! \brief The astobj2 compare callback for taskprocessors */
100 static int tps_cmp_cb(void *obj, void *arg, int flags);
101 
102 /*! \brief The task processing function executed by a taskprocessor */
103 static void *tps_processing_function(void *data);
104 
105 /*! \brief Destroy the taskprocessor when its refcount reaches zero */
106 static void tps_taskprocessor_destroy(void *tps);
107 
108 /*! \brief CLI <example>taskprocessor ping &lt;blah&gt;</example> handler function */
109 static int tps_ping_handler(void *datap);
110 
111 /*! \brief Remove the front task off the taskprocessor queue */
112 static struct tps_task *tps_taskprocessor_pop(struct ast_taskprocessor *tps);
113 
114 /*! \brief Return the size of the taskprocessor queue */
115 static int tps_taskprocessor_depth(struct ast_taskprocessor *tps);
116 
117 static char *cli_tps_ping(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
118 static char *cli_tps_report(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
119 
121  AST_CLI_DEFINE(cli_tps_ping, "Ping a named task processor"),
122  AST_CLI_DEFINE(cli_tps_report, "List instantiated task processors and statistics"),
123 };
124 
125 /*! \internal \brief Clean up resources on Asterisk shutdown */
126 static void tps_shutdown(void)
127 {
129  ao2_t_ref(tps_singletons, -1, "Unref tps_singletons in shutdown");
130  tps_singletons = NULL;
131 }
132 
133 /* initialize the taskprocessor container and register CLI operations */
134 int ast_tps_init(void)
135 {
137  ast_log(LOG_ERROR, "taskprocessor container failed to initialize!\n");
138  return -1;
139  }
140 
142 
144 
146 
147  return 0;
148 }
149 
150 /* allocate resources for the task */
151 static struct tps_task *tps_task_alloc(int (*task_exe)(void *datap), void *datap)
152 {
153  struct tps_task *t;
154  if ((t = ast_calloc(1, sizeof(*t)))) {
155  t->execute = task_exe;
156  t->datap = datap;
157  }
158  return t;
159 }
160 
161 /* release task resources */
162 static void *tps_task_free(struct tps_task *task)
163 {
164  if (task) {
165  ast_free(task);
166  }
167  return NULL;
168 }
169 
170 /* taskprocessor tab completion */
172 {
173  int tklen;
174  int wordnum = 0;
175  char *name = NULL;
176  struct ao2_iterator i;
177 
178  if (a->pos != 3)
179  return NULL;
180 
181  tklen = strlen(a->word);
183  while ((p = ao2_iterator_next(&i))) {
184  if (!strncasecmp(a->word, p->name, tklen) && ++wordnum > a->n) {
185  name = ast_strdup(p->name);
186  ao2_ref(p, -1);
187  break;
188  }
189  ao2_ref(p, -1);
190  }
192  return name;
193 }
194 
195 /* ping task handling function */
196 static int tps_ping_handler(void *datap)
197 {
201  return 0;
202 }
203 
204 /* ping the specified taskprocessor and display the ping time on the CLI */
205 static char *cli_tps_ping(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
206 {
207  struct timeval begin, end, delta;
208  const char *name;
209  struct timeval when;
210  struct timespec ts;
211  struct ast_taskprocessor *tps = NULL;
212 
213  switch (cmd) {
214  case CLI_INIT:
215  e->command = "core ping taskprocessor";
216  e->usage =
217  "Usage: core ping taskprocessor <taskprocessor>\n"
218  " Displays the time required for a task to be processed\n";
219  return NULL;
220  case CLI_GENERATE:
221  return tps_taskprocessor_tab_complete(tps, a);
222  }
223 
224  if (a->argc != 4)
225  return CLI_SHOWUSAGE;
226 
227  name = a->argv[3];
228  if (!(tps = ast_taskprocessor_get(name, TPS_REF_IF_EXISTS))) {
229  ast_cli(a->fd, "\nping failed: %s not found\n\n", name);
230  return CLI_SUCCESS;
231  }
232  ast_cli(a->fd, "\npinging %s ...", name);
233  when = ast_tvadd((begin = ast_tvnow()), ast_samp2tv(1000, 1000));
234  ts.tv_sec = when.tv_sec;
235  ts.tv_nsec = when.tv_usec * 1000;
237  if (ast_taskprocessor_push(tps, tps_ping_handler, 0) < 0) {
238  ast_cli(a->fd, "\nping failed: could not push task to %s\n\n", name);
239  ao2_ref(tps, -1);
240  return CLI_FAILURE;
241  }
244  end = ast_tvnow();
245  delta = ast_tvsub(end, begin);
246  ast_cli(a->fd, "\n\t%24s ping time: %.1ld.%.6ld sec\n\n", name, (long)delta.tv_sec, (long int)delta.tv_usec);
247  ao2_ref(tps, -1);
248  return CLI_SUCCESS;
249 }
250 
251 static char *cli_tps_report(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
252 {
253  char name[256];
254  int tcount;
255  unsigned long qsize;
256  unsigned long maxqsize;
257  unsigned long processed;
258  struct ast_taskprocessor *p;
259  struct ao2_iterator i;
260 
261  switch (cmd) {
262  case CLI_INIT:
263  e->command = "core show taskprocessors";
264  e->usage =
265  "Usage: core show taskprocessors\n"
266  " Shows a list of instantiated task processors and their statistics\n";
267  return NULL;
268  case CLI_GENERATE:
269  return NULL;
270  }
271 
272  if (a->argc != e->args)
273  return CLI_SHOWUSAGE;
274 
275  ast_cli(a->fd, "\n\t+----- Processor -----+--- Processed ---+- In Queue -+- Max Depth -+");
277  while ((p = ao2_iterator_next(&i))) {
278  ast_copy_string(name, p->name, sizeof(name));
279  qsize = p->tps_queue_size;
280  maxqsize = p->stats->max_qsize;
281  processed = p->stats->_tasks_processed_count;
282  ast_cli(a->fd, "\n%24s %17lu %12lu %12lu", name, processed, qsize, maxqsize);
283  ao2_ref(p, -1);
284  }
287  ast_cli(a->fd, "\n\t+---------------------+-----------------+------------+-------------+\n\t%d taskprocessors\n\n", tcount);
288  return CLI_SUCCESS;
289 }
290 
291 /* this is the task processing worker function */
292 static void *tps_processing_function(void *data)
293 {
294  struct ast_taskprocessor *i = data;
295  struct tps_task *t;
296  int size;
297 
298  if (!i) {
299  ast_log(LOG_ERROR, "cannot start thread_function loop without a ast_taskprocessor structure.\n");
300  return NULL;
301  }
302 
303  while (i->poll_thread_run) {
305  if (!i->poll_thread_run) {
307  break;
308  }
309  if (!(size = tps_taskprocessor_depth(i))) {
311  if (!i->poll_thread_run) {
313  break;
314  }
315  }
317  /* stuff is in the queue */
318  if (!(t = tps_taskprocessor_pop(i))) {
319  ast_log(LOG_ERROR, "Wtf?? %d tasks in the queue, but we're popping blanks!\n", size);
320  continue;
321  }
322  if (!t->execute) {
323  ast_log(LOG_WARNING, "Task is missing a function to execute!\n");
324  tps_task_free(t);
325  continue;
326  }
327  t->execute(t->datap);
328 
330  if (i->stats) {
332  if (size > i->stats->max_qsize) {
333  i->stats->max_qsize = size;
334  }
335  }
337 
338  tps_task_free(t);
339  }
340  while ((t = tps_taskprocessor_pop(i))) {
341  tps_task_free(t);
342  }
343  return NULL;
344 }
345 
346 /* hash callback for astobj2 */
347 static int tps_hash_cb(const void *obj, const int flags)
348 {
349  const struct ast_taskprocessor *tps = obj;
350 
351  return ast_str_case_hash(tps->name);
352 }
353 
354 /* compare callback for astobj2 */
355 static int tps_cmp_cb(void *obj, void *arg, int flags)
356 {
357  struct ast_taskprocessor *lhs = obj, *rhs = arg;
358 
359  return !strcasecmp(lhs->name, rhs->name) ? CMP_MATCH | CMP_STOP : 0;
360 }
361 
362 /* destroy the taskprocessor */
363 static void tps_taskprocessor_destroy(void *tps)
364 {
365  struct ast_taskprocessor *t = tps;
366 
367  if (!tps) {
368  ast_log(LOG_ERROR, "missing taskprocessor\n");
369  return;
370  }
371  ast_log(LOG_DEBUG, "destroying taskprocessor '%s'\n", t->name);
372  /* kill it */
374  t->poll_thread_run = 0;
377  pthread_join(t->poll_thread, NULL);
381  /* free it */
382  if (t->stats) {
383  ast_free(t->stats);
384  t->stats = NULL;
385  }
386  ast_free((char *) t->name);
387 }
388 
389 /* pop the front task and return it */
391 {
392  struct tps_task *task;
393 
394  if (!tps) {
395  ast_log(LOG_ERROR, "missing taskprocessor\n");
396  return NULL;
397  }
399  if ((task = AST_LIST_REMOVE_HEAD(&tps->tps_queue, list))) {
400  tps->tps_queue_size--;
401  }
403  return task;
404 }
405 
407 {
408  return (tps) ? tps->tps_queue_size : -1;
409 }
410 
411 /* taskprocessor name accessor */
413 {
414  if (!tps) {
415  ast_log(LOG_ERROR, "no taskprocessor specified!\n");
416  return NULL;
417  }
418  return tps->name;
419 }
420 
421 /* Provide a reference to a taskprocessor. Create the taskprocessor if necessary, but don't
422  * create the taskprocessor if we were told via ast_tps_options to return a reference only
423  * if it already exists */
425 {
426  struct ast_taskprocessor *p, tmp_tps = {
427  .name = name,
428  };
429 
430  if (ast_strlen_zero(name)) {
431  ast_log(LOG_ERROR, "requesting a nameless taskprocessor!!!\n");
432  return NULL;
433  }
435  p = ao2_find(tps_singletons, &tmp_tps, OBJ_POINTER);
436  if (p) {
438  return p;
439  }
440  if (create & TPS_REF_IF_EXISTS) {
441  /* calling function does not want a new taskprocessor to be created if it doesn't already exist */
443  return NULL;
444  }
445  /* create a new taskprocessor */
446  if (!(p = ao2_alloc(sizeof(*p), tps_taskprocessor_destroy))) {
448  ast_log(LOG_WARNING, "failed to create taskprocessor '%s'\n", name);
449  return NULL;
450  }
451 
452  ast_cond_init(&p->poll_cond, NULL);
454 
455  if (!(p->stats = ast_calloc(1, sizeof(*p->stats)))) {
457  ast_log(LOG_WARNING, "failed to create taskprocessor stats for '%s'\n", name);
458  ao2_ref(p, -1);
459  return NULL;
460  }
461  if (!(p->name = ast_strdup(name))) {
463  ao2_ref(p, -1);
464  return NULL;
465  }
466  p->poll_thread_run = 1;
468  if (ast_pthread_create(&p->poll_thread, NULL, tps_processing_function, p) < 0) {
470  ast_log(LOG_ERROR, "Taskprocessor '%s' failed to create the processing thread.\n", p->name);
471  ao2_ref(p, -1);
472  return NULL;
473  }
474  if (!(ao2_link(tps_singletons, p))) {
476  ast_log(LOG_ERROR, "Failed to add taskprocessor '%s' to container\n", p->name);
477  ao2_ref(p, -1);
478  return NULL;
479  }
481  return p;
482 }
483 
484 /* decrement the taskprocessor reference count and unlink from the container if necessary */
486 {
487  if (tps) {
490  if (ao2_ref(tps, -1) > 1) {
491  ao2_link(tps_singletons, tps);
492  }
494  }
495  return NULL;
496 }
497 
498 /* push the task into the taskprocessor queue */
499 int ast_taskprocessor_push(struct ast_taskprocessor *tps, int (*task_exe)(void *datap), void *datap)
500 {
501  struct tps_task *t;
502 
503  if (!tps || !task_exe) {
504  ast_log(LOG_ERROR, "%s is missing!!\n", (tps) ? "task callback" : "taskprocessor");
505  return -1;
506  }
507  if (!(t = tps_task_alloc(task_exe, datap))) {
508  ast_log(LOG_ERROR, "failed to allocate task! Can't push to '%s'\n", tps->name);
509  return -1;
510  }
512  AST_LIST_INSERT_TAIL(&tps->tps_queue, t, list);
513  tps->tps_queue_size++;
514  ast_cond_signal(&tps->poll_cond);
516  return 0;
517 }
518 
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:471
static ast_cond_t cli_ping_cond
CLI taskprocessor ping &lt;blah&gt;operation requires a ping condition.
Definition: taskprocessor.c:92
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:191
Asterisk main include file. File version handling, generic pbx functions.
#define ao2_link(arg1, arg2)
Definition: astobj2.h:785
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
Definition: astobj2.c:470
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
const char * name
Friendly name of the taskprocessor.
Definition: taskprocessor.c:69
static void tps_shutdown(void)
#define ast_strdup(a)
Definition: astmm.h:109
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: cli.c:2177
Time-related functions and macros.
int ast_taskprocessor_push(struct ast_taskprocessor *tps, int(*task_exe)(void *datap), void *datap)
Push a task into the specified taskprocessor queue and signal the taskprocessor thread.
static int tps_cmp_cb(void *obj, void *arg, int flags)
The astobj2 compare callback for taskprocessors.
#define ao2_iterator_next(arg1)
Definition: astobj2.h:1126
descriptor for a cli entry.
Definition: cli.h:165
const int argc
Definition: cli.h:154
#define LOG_WARNING
Definition: logger.h:144
struct ast_taskprocessor * ast_taskprocessor_get(const char *name, enum ast_tps_options create)
Get a reference to a taskprocessor with the specified name and create the taskprocessor if necessary...
static int tps_hash_cb(const void *obj, const int flags)
The astobj2 hash callback for taskprocessors.
int ast_tps_init(void)
ast_cond_t poll_cond
Thread poll condition.
Definition: taskprocessor.c:71
static struct ao2_container * tps_singletons
tps_singletons is the astobj2 container for taskprocessor singletons
Definition: taskprocessor.c:89
Definition: cli.h:146
#define ast_cond_wait(cond, mutex)
Definition: lock.h:171
#define ast_cond_init(cond, attr)
Definition: lock.h:167
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:142
const char * ast_taskprocessor_name(struct ast_taskprocessor *tps)
Return the name of the taskprocessor singleton.
#define ast_mutex_lock(a)
Definition: lock.h:155
Taskprocessor queue.
Definition: taskprocessor.c:83
#define ao2_unlock(a)
Definition: astobj2.h:497
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags)
Create an iterator for a container.
Definition: astobj2.c:818
void ast_cli(int fd, const char *fmt,...)
Definition: cli.c:105
#define LOG_DEBUG
Definition: logger.h:122
static struct tps_task * tps_taskprocessor_pop(struct ast_taskprocessor *tps)
Remove the front task off the taskprocessor queue.
#define ast_cond_signal(cond)
Definition: lock.h:169
int args
This gets set in ast_cli_register()
Definition: cli.h:179
pthread_cond_t ast_cond_t
Definition: lock.h:144
static void * tps_processing_function(void *data)
The task processing function executed by a taskprocessor.
void * datap
The data pointer for the task execute() function.
Definition: taskprocessor.c:53
ast_mutex_t taskprocessor_lock
Taskprocessor lock.
Definition: taskprocessor.c:75
unsigned long _tasks_processed_count
This is the current number of tasks processed.
Definition: taskprocessor.c:63
static void tps_taskprocessor_destroy(void *tps)
Destroy the taskprocessor when its refcount reaches zero.
#define TPS_MAX_BUCKETS
Definition: taskprocessor.c:87
const int fd
Definition: cli.h:153
#define AST_PTHREADT_NULL
Definition: lock.h:65
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
const int n
Definition: cli.h:159
#define ao2_ref(o, delta)
Definition: astobj2.h:472
int ast_register_atexit(void(*func)(void))
Register a function to be executed before Asterisk exits.
Definition: asterisk.c:998
#define ao2_lock(a)
Definition: astobj2.h:488
struct timeval ast_samp2tv(unsigned int _nsamp, unsigned int _rate)
Returns a timeval corresponding to the duration of n samples at rate r. Useful to convert samples to ...
Definition: time.h:191
static ast_mutex_t cli_ping_cond_lock
CLI taskprocessor ping &lt;blah&gt;operation requires a ping condition lock.
Definition: taskprocessor.c:95
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
const char *const * argv
Definition: cli.h:155
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:224
#define LOG_ERROR
Definition: logger.h:155
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
ast_tps_options
ast_tps_options for specification of taskprocessor options
Definition: taskprocessor.h:56
#define CLI_SHOWUSAGE
Definition: cli.h:44
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: utils.c:1587
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ast_cond_destroy(cond)
Definition: lock.h:168
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:430
struct tps_task::@303 list
AST_LIST_ENTRY overhead.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
unsigned char poll_thread_run
Taskprocesor thread run flag.
Definition: taskprocessor.c:77
#define ao2_find(arg1, arg2, arg3)
Definition: astobj2.h:964
#define CLI_FAILURE
Definition: cli.h:45
static const char name[]
#define ast_free(a)
Definition: astmm.h:97
char * command
Definition: cli.h:180
#define ast_pthread_create(a, b, c, d)
Definition: utils.h:418
const char * word
Definition: cli.h:157
An API for managing task processing threads that can be shared across modules.
int(* execute)(void *datap)
The execute() task callback function pointer.
Definition: taskprocessor.c:51
void ao2_iterator_destroy(struct ao2_iterator *i)
Destroy a container iterator.
Definition: astobj2.c:833
struct ast_taskprocessor::tps_queue tps_queue
tps_taskprocessor_stats maintain statistics for a taskprocessor.
Definition: taskprocessor.c:59
tps_task structure is queued to a taskprocessor
Definition: taskprocessor.c:49
const char * usage
Definition: cli.h:171
pthread_t poll_thread
Taskprocessor thread.
Definition: taskprocessor.c:73
return a reference to a taskprocessor ONLY if it already exists
Definition: taskprocessor.h:60
static char * tps_taskprocessor_tab_complete(struct ast_taskprocessor *p, struct ast_cli_args *a)
#define CLI_SUCCESS
Definition: cli.h:43
long tps_queue_size
Taskprocessor current queue size.
Definition: taskprocessor.c:81
A ast_taskprocessor structure is a singleton by name.
Definition: taskprocessor.c:67
static struct ast_cli_entry taskprocessor_clis[]
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1053
static struct tps_task * tps_task_alloc(int(*task_exe)(void *datap), void *datap)
Standard Command Line Interface.
#define ast_calloc(a, b)
Definition: astmm.h:82
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
#define ao2_container_alloc(arg1, arg2, arg3)
Definition: astobj2.h:734
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
const int pos
Definition: cli.h:158
int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
Register multiple commands.
Definition: cli.c:2167
static int tps_ping_handler(void *datap)
CLI taskprocessor ping &lt;blah&gt;handler function.
static int tps_taskprocessor_depth(struct ast_taskprocessor *tps)
Return the size of the taskprocessor queue.
static char * cli_tps_report(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
struct timeval ast_tvsub(struct timeval a, struct timeval b)
Returns the difference of two timevals a - b.
Definition: utils.c:1601
#define ast_mutex_init(pmutex)
Definition: lock.h:152
#define ast_mutex_destroy(a)
Definition: lock.h:154
Asterisk module definitions.
struct tps_taskprocessor_stats * stats
Taskprocessor statistics.
Definition: taskprocessor.c:79
unsigned long max_qsize
This is the maximum number of tasks queued at any one time.
Definition: taskprocessor.c:61
#define ao2_unlink(arg1, arg2)
Definition: astobj2.h:817
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:172
static void * tps_task_free(struct tps_task *task)
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:526
Structure for mutex and tracking information.
Definition: lock.h:121
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:989
static char * cli_tps_ping(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
#define ast_mutex_unlock(a)
Definition: lock.h:156