Asterisk - The Open Source Telephony Project  18.5.0
pjsip_scheduler.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2016, Fairview 5 Engineering, LLC
5  *
6  * George Joseph <[email protected]>
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 /*! \file
20  *
21  * \brief res_pjsip Scheduler
22  *
23  * \author George Joseph <[email protected]>
24  */
25 
26 #include "asterisk.h"
27 
28 #include "asterisk/res_pjsip.h"
30 #include "asterisk/res_pjsip_cli.h"
31 #include "asterisk/taskprocessor.h"
32 
33 #include <regex.h>
34 
35 #define TASK_BUCKETS 53
36 
38 static struct ao2_container *tasks;
39 static int task_count;
40 
42  /*! The serializer to be used (if any) (Holds a ref) */
44  /*! task data */
45  void *task_data;
46  /*! task function */
48  /*! the time the task was originally scheduled/queued */
49  struct timeval when_queued;
50  /*! the last time the task was started */
51  struct timeval last_start;
52  /*! the last time the task was ended */
53  struct timeval last_end;
54  /*! When the periodic task is next expected to run */
55  struct timeval next_periodic;
56  /*! reschedule interval in milliseconds */
57  int interval;
58  /*! ast_sched scheudler id */
60  /*! task is currently running */
62  /*! times run */
63  int run_count;
64  /*! the task reschedule, cleanup and policy flags */
66  /*! A name to be associated with the task */
67  char name[0];
68 };
69 
73 
74 static int push_to_serializer(const void *data);
75 
76 /*
77  * This function is run in the context of the serializer.
78  * It runs the task with a simple call and reschedules based on the result.
79  */
80 static int run_task(void *data)
81 {
82  RAII_VAR(struct ast_sip_sched_task *, schtd, data, ao2_cleanup);
83  int res;
84  int delay;
85 
86  if (!schtd->interval) {
87  /* Task was cancelled while waiting to be executed by the serializer */
88  return -1;
89  }
90 
91  if (schtd->flags & AST_SIP_SCHED_TASK_TRACK) {
92  ast_log(LOG_DEBUG, "Sched %p: Running %s\n", schtd, schtd->name);
93  }
94  ao2_lock(schtd);
95  schtd->last_start = ast_tvnow();
96  schtd->is_running = 1;
97  ++schtd->run_count;
98  ao2_unlock(schtd);
99 
100  res = schtd->task(schtd->task_data);
101 
102  ao2_lock(schtd);
103  schtd->is_running = 0;
104  schtd->last_end = ast_tvnow();
105 
106  /*
107  * Don't restart if the task returned <= 0 or if the interval
108  * was set to 0 while the task was running
109  */
110  if ((schtd->flags & AST_SIP_SCHED_TASK_ONESHOT) || res <= 0 || !schtd->interval) {
111  schtd->interval = 0;
112  ao2_unlock(schtd);
113  ao2_unlink(tasks, schtd);
114  return -1;
115  }
116 
117  if (schtd->flags & AST_SIP_SCHED_TASK_VARIABLE) {
118  schtd->interval = res;
119  }
120 
121  if (schtd->flags & AST_SIP_SCHED_TASK_DELAY) {
122  delay = schtd->interval;
123  } else {
124  int64_t diff;
125 
126  /* Determine next periodic interval we need to expire. */
127  do {
128  schtd->next_periodic = ast_tvadd(schtd->next_periodic,
129  ast_samp2tv(schtd->interval, 1000));
130  diff = ast_tvdiff_ms(schtd->next_periodic, schtd->last_end);
131  } while (diff <= 0);
132  delay = diff;
133  }
134 
135  schtd->current_scheduler_id = ast_sched_add(scheduler_context, delay, push_to_serializer, schtd);
136  if (schtd->current_scheduler_id < 0) {
137  schtd->interval = 0;
138  ao2_unlock(schtd);
139  ast_log(LOG_ERROR, "Sched %p: Failed to reschedule task %s\n", schtd, schtd->name);
140  ao2_unlink(tasks, schtd);
141  return -1;
142  }
143 
144  ao2_unlock(schtd);
145  if (schtd->flags & AST_SIP_SCHED_TASK_TRACK) {
146  ast_log(LOG_DEBUG, "Sched %p: Rescheduled %s for %d ms\n", schtd, schtd->name,
147  delay);
148  }
149 
150  return 0;
151 }
152 
153 /*
154  * This function is run by the scheduler thread. Its only job is to push the task
155  * to the serialize and return. It returns 0 so it's not rescheduled.
156  */
157 static int push_to_serializer(const void *data)
158 {
159  struct ast_sip_sched_task *schtd = (struct ast_sip_sched_task *)data;
160  int sched_id;
161 
162  ao2_lock(schtd);
163  sched_id = schtd->current_scheduler_id;
164  schtd->current_scheduler_id = -1;
165  ao2_unlock(schtd);
166  if (sched_id < 0) {
167  /* Task was cancelled while waiting on the lock */
168  return 0;
169  }
170 
171  if (schtd->flags & AST_SIP_SCHED_TASK_TRACK) {
172  ast_log(LOG_DEBUG, "Sched %p: Ready to run %s\n", schtd, schtd->name);
173  }
174  ao2_t_ref(schtd, +1, "Give ref to run_task()");
175  if (ast_sip_push_task(schtd->serializer, run_task, schtd)) {
176  /*
177  * Oh my. Have to cancel the scheduled item because we
178  * unexpectedly cannot run it anymore.
179  */
180  ao2_unlink(tasks, schtd);
181  ao2_lock(schtd);
182  schtd->interval = 0;
183  ao2_unlock(schtd);
184 
185  ao2_t_ref(schtd, -1, "Failed so release run_task() ref");
186  }
187 
188  return 0;
189 }
190 
192 {
193  int res;
194  int sched_id;
195 
196  if (schtd->flags & AST_SIP_SCHED_TASK_TRACK) {
197  ast_log(LOG_DEBUG, "Sched %p: Canceling %s\n", schtd, schtd->name);
198  }
199 
200  /*
201  * Prevent any tasks in the serializer queue from
202  * running and restarting the scheduled item on us
203  * first.
204  */
205  ao2_lock(schtd);
206  schtd->interval = 0;
207 
208  sched_id = schtd->current_scheduler_id;
209  schtd->current_scheduler_id = -1;
210  ao2_unlock(schtd);
211  res = ast_sched_del(scheduler_context, sched_id);
212 
213  ao2_unlink(tasks, schtd);
214 
215  return res;
216 }
217 
219 {
220  int res;
221  struct ast_sip_sched_task *schtd;
222 
223  if (ast_strlen_zero(name)) {
224  return -1;
225  }
226 
227  schtd = ao2_find(tasks, name, OBJ_SEARCH_KEY);
228  if (!schtd) {
229  return -1;
230  }
231 
232  res = ast_sip_sched_task_cancel(schtd);
233  ao2_ref(schtd, -1);
234  return res;
235 }
236 
238  struct timeval *queued, struct timeval *last_start, struct timeval *last_end,
239  int *interval, int *time_left, struct timeval *next_start)
240 {
241  ao2_lock(schtd);
242  if (queued) {
243  memcpy(queued, &schtd->when_queued, sizeof(struct timeval));
244  }
245  if (last_start) {
246  memcpy(last_start, &schtd->last_start, sizeof(struct timeval));
247  }
248  if (last_end) {
249  memcpy(last_end, &schtd->last_end, sizeof(struct timeval));
250  }
251 
252  if (interval) {
253  *interval = schtd->interval;
254  }
255 
256  if (time_left || next_start) {
257  int delay;
258  struct timeval since_when;
259  struct timeval now;
260  struct timeval next;
261 
262  if (schtd->interval) {
263  delay = schtd->interval;
264  now = ast_tvnow();
265 
266  if (schtd->flags & AST_SIP_SCHED_TASK_DELAY) {
267  since_when = schtd->is_running ? now : schtd->last_end;
268  } else {
269  since_when = schtd->last_start.tv_sec ? schtd->last_start : schtd->when_queued;
270  }
271 
272  delay -= ast_tvdiff_ms(now, since_when);
273 
274  delay = delay < 0 ? 0 : delay;
275 
276 
277  if (time_left) {
278  *time_left = delay;
279  }
280 
281  if (next_start) {
282  next = ast_tvadd(now, ast_tv(delay / 1000, (delay % 1000) * 1000));
283  memcpy(next_start, &next, sizeof(struct timeval));
284  }
285  } else {
286  if (time_left) {
287  *time_left = -1;
288  }
289  }
290 
291  }
292 
293  ao2_unlock(schtd);
294 
295  return 0;
296 }
297 
298 
300  struct timeval *queued, struct timeval *last_start, struct timeval *last_end)
301 {
302  return ast_sip_sched_task_get_times2(schtd, queued, last_start, last_end, NULL, NULL, NULL);
303 }
304 
306  struct timeval *queued, struct timeval *last_start, struct timeval *last_end,
307  int *interval, int *time_left, struct timeval *next_start)
308 {
309  int res;
310  struct ast_sip_sched_task *schtd;
311 
312  if (ast_strlen_zero(name)) {
313  return -1;
314  }
315 
316  schtd = ao2_find(tasks, name, OBJ_SEARCH_KEY);
317  if (!schtd) {
318  return -1;
319  }
320 
321  res = ast_sip_sched_task_get_times2(schtd, queued, last_start, last_end, interval, time_left,
322  next_start);
323  ao2_ref(schtd, -1);
324  return res;
325 }
326 
328  struct timeval *queued, struct timeval *last_start, struct timeval *last_end)
329 {
330  return ast_sip_sched_task_get_times_by_name2(name, queued, last_start, last_end,
331  NULL, NULL, NULL);
332 }
333 
334 int ast_sip_sched_task_get_name(struct ast_sip_sched_task *schtd, char *name, size_t maxlen)
335 {
336  if (maxlen <= 0) {
337  return -1;
338  }
339 
340  ao2_lock(schtd);
341  ast_copy_string(name, schtd->name, maxlen);
342  ao2_unlock(schtd);
343 
344  return 0;
345 }
346 
348 {
349  int delay;
350 
351  ast_sip_sched_task_get_times2(schtd, NULL, NULL, NULL, NULL, &delay, NULL);
352 
353  return delay;
354 }
355 
357 {
358  int next_run;
359  struct ast_sip_sched_task *schtd;
360 
361  if (ast_strlen_zero(name)) {
362  return -1;
363  }
364 
365  schtd = ao2_find(tasks, name, OBJ_SEARCH_KEY);
366  if (!schtd) {
367  return -1;
368  }
369 
370  next_run = ast_sip_sched_task_get_next_run(schtd);
371  ao2_ref(schtd, -1);
372  return next_run;
373 }
374 
376 {
377  return schtd ? schtd->is_running : 0;
378 }
379 
381 {
382  int is_running;
383  struct ast_sip_sched_task *schtd;
384 
385  if (ast_strlen_zero(name)) {
386  return 0;
387  }
388 
389  schtd = ao2_find(tasks, name, OBJ_SEARCH_KEY);
390  if (!schtd) {
391  return 0;
392  }
393 
394  is_running = schtd->is_running;
395  ao2_ref(schtd, -1);
396  return is_running;
397 }
398 
399 static void schtd_dtor(void *data)
400 {
401  struct ast_sip_sched_task *schtd = data;
402 
403  if (schtd->flags & AST_SIP_SCHED_TASK_TRACK) {
404  ast_log(LOG_DEBUG, "Sched %p: Destructor %s\n", schtd, schtd->name);
405  }
406  if (schtd->flags & AST_SIP_SCHED_TASK_DATA_AO2) {
407  /* release our own ref, then release the callers if asked to do so */
408  ao2_ref(schtd->task_data, (schtd->flags & AST_SIP_SCHED_TASK_DATA_FREE) ? -2 : -1);
409  } else if (schtd->task_data && (schtd->flags & AST_SIP_SCHED_TASK_DATA_FREE)) {
410  ast_free(schtd->task_data);
411  }
413 }
414 
416  int interval, ast_sip_task sip_task, const char *name, void *task_data,
418 {
419 #define ID_LEN 13 /* task_deadbeef */
420  struct ast_sip_sched_task *schtd;
421  int res;
422 
423  if (interval <= 0) {
424  return NULL;
425  }
426 
427  schtd = ao2_alloc((sizeof(*schtd) + (!ast_strlen_zero(name) ? strlen(name) : ID_LEN) + 1),
428  schtd_dtor);
429  if (!schtd) {
430  return NULL;
431  }
432 
433  schtd->serializer = ao2_bump(serializer);
434  schtd->task_data = task_data;
435  schtd->task = sip_task;
436  schtd->interval = interval;
437  schtd->flags = flags;
438  schtd->last_start = ast_tv(0, 0);
439  if (!ast_strlen_zero(name)) {
440  strcpy(schtd->name, name); /* Safe */
441  } else {
442  uint32_t task_id;
443 
444  task_id = ast_atomic_fetchadd_int(&task_count, 1);
445  sprintf(schtd->name, "task_%08x", task_id);
446  }
447  if (schtd->flags & AST_SIP_SCHED_TASK_TRACK) {
448  ast_log(LOG_DEBUG, "Sched %p: Scheduling %s for %d ms\n", schtd, schtd->name,
449  interval);
450  }
451  schtd->when_queued = ast_tvnow();
452  if (!(schtd->flags & AST_SIP_SCHED_TASK_DELAY)) {
453  schtd->next_periodic = ast_tvadd(schtd->when_queued,
454  ast_samp2tv(schtd->interval, 1000));
455  }
456 
457  if (flags & AST_SIP_SCHED_TASK_DATA_AO2) {
458  ao2_ref(task_data, +1);
459  }
460 
461  /*
462  * We must put it in the 'tasks' container before scheduling
463  * the task because we don't want the push_to_serializer()
464  * sched task to "remove" it on failure before we even put
465  * it in. If this happens then nothing would remove it from
466  * the 'tasks' container.
467  */
468  ao2_link(tasks, schtd);
469 
470  /*
471  * Lock so we are guaranteed to get the sched id set before
472  * the push_to_serializer() sched task can clear it.
473  */
474  ao2_lock(schtd);
475  res = ast_sched_add(scheduler_context, interval, push_to_serializer, schtd);
476  schtd->current_scheduler_id = res;
477  ao2_unlock(schtd);
478  if (res < 0) {
479  ao2_unlink(tasks, schtd);
480  ao2_ref(schtd, -1);
481  return NULL;
482  }
483 
484  return schtd;
485 #undef ID_LEN
486 }
487 
488 #define TIME_FORMAT "%a %T"
489 
490 static char *cli_show_tasks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
491 {
492  struct ao2_iterator iter;
493  struct ao2_container *sorted_tasks;
494  struct ast_sip_sched_task *schtd;
495  struct ast_tm tm;
496  char times_run[16];
497  char queued[32];
498  char last_start[32];
499  char next_start[32];
500  struct timeval now;
501  int using_regex = 0;
502  regex_t regex;
503 
504  switch (cmd) {
505  case CLI_INIT:
506  e->command = "pjsip show scheduled_tasks";
507  e->usage = "Usage: pjsip show scheduled_tasks [ like <pattern> ]\n"
508  " Show scheduled pjsip tasks\n";
509  return NULL;
510  case CLI_GENERATE:
511  return NULL;
512  }
513 
514  if (a->argc != 3 && a->argc != 5) {
515  return CLI_SHOWUSAGE;
516  }
517 
518  if (a->argc == 5) {
519  int regrc;
520  if (strcasecmp(a->argv[3], "like")) {
521  return CLI_SHOWUSAGE;
522  }
523  regrc = regcomp(&regex, a->argv[4], REG_EXTENDED | REG_ICASE | REG_NOSUB);
524  if (regrc) {
525  char err[256];
526  regerror(regrc, &regex, err, 256);
527  ast_cli(a->fd, "PJSIP Scheduled Tasks: Error: %s\n", err);
528  return CLI_FAILURE;
529  }
530  using_regex = 1;
531  }
532 
533  /* Get a sorted snapshot of the scheduled tasks */
535  ast_sip_sched_task_sort_fn, NULL);
536  if (!sorted_tasks) {
537  ast_cli(a->fd, "PJSIP Scheduled Tasks: Unable to allocate temporary container\n");
538  return CLI_FAILURE;
539  }
540  if (ao2_container_dup(sorted_tasks, tasks, 0)) {
541  ao2_ref(sorted_tasks, -1);
542  ast_cli(a->fd, "PJSIP Scheduled Tasks: Unable to sort temporary container\n");
543  return CLI_FAILURE;
544  }
545 
546  now = ast_tvnow();
547 
548  ast_localtime(&now, &tm, NULL);
549 
550  ast_cli(a->fd, "PJSIP Scheduled Tasks:\n\n");
551 
552  ast_cli(a->fd,
553  "<Task Name....................................> <Interval> <Times Run> <State>"
554  " <Queued....> <Last Start> <Next Start.....secs>\n"
555  "=============================================================================="
556  "===================================================\n");
557 
558  iter = ao2_iterator_init(sorted_tasks, AO2_ITERATOR_UNLINK);
559  for (; (schtd = ao2_iterator_next(&iter)); ao2_ref(schtd, -1)) {
560  int next_run_sec;
561  struct timeval next;
562 
563  ao2_lock(schtd);
564 
565  if (using_regex && regexec(&regex, schtd->name, 0, NULL, 0) == REG_NOMATCH) {
566  ao2_unlock(schtd);
567  continue;
568  }
569 
570  next_run_sec = ast_sip_sched_task_get_next_run(schtd) / 1000;
571  if (next_run_sec < 0) {
572  /* Scheduled task is now canceled */
573  ao2_unlock(schtd);
574  continue;
575  }
576  next = ast_tvadd(now, ast_tv(next_run_sec, 0));
577 
578  ast_localtime(&schtd->when_queued, &tm, NULL);
579  ast_strftime(queued, sizeof(queued), TIME_FORMAT, &tm);
580 
581  ast_localtime(&schtd->last_start, &tm, NULL);
582  ast_strftime(last_start, sizeof(last_start), TIME_FORMAT, &tm);
583 
584  ast_localtime(&next, &tm, NULL);
585  ast_strftime(next_start, sizeof(next_start), TIME_FORMAT, &tm);
586 
587  sprintf(times_run, "%d", schtd->run_count);
588 
589  ast_cli(a->fd, "%-46.46s %9d %9s %-5s %-12s %-12s %-12s %8d\n",
590  schtd->name,
591  schtd->interval / 1000,
592  schtd->flags & AST_SIP_SCHED_TASK_ONESHOT ? "oneshot" : times_run,
593  schtd->is_running ? "run" : "wait",
594  queued,
595  (ast_tvzero(schtd->last_start) || (schtd->flags & AST_SIP_SCHED_TASK_ONESHOT) ? "" : last_start),
596  next_start,
597  next_run_sec);
598  ao2_unlock(schtd);
599  }
600  if (using_regex) {
601  regfree(&regex);
602  }
603  ao2_iterator_destroy(&iter);
604  ast_cli(a->fd, "\nTotal Scheduled Tasks: %d\n\n", ao2_container_count(sorted_tasks));
605  ao2_ref(sorted_tasks, -1);
606 
607  return CLI_SUCCESS;
608 }
609 
610 static struct ast_cli_entry cli_commands[] = {
611  AST_CLI_DEFINE(cli_show_tasks, "Show pjsip scheduled tasks"),
612 };
613 
615 {
616  scheduler_context = ast_sched_context_create();
617  if (!scheduler_context) {
618  ast_log(LOG_ERROR, "Failed to create scheduler. Aborting load\n");
619  return -1;
620  }
621 
622  if (ast_sched_start_thread(scheduler_context)) {
623  ast_log(LOG_ERROR, "Failed to start scheduler. Aborting load\n");
624  ast_sched_context_destroy(scheduler_context);
625  return -1;
626  }
627 
629  AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, TASK_BUCKETS, ast_sip_sched_task_hash_fn,
630  ast_sip_sched_task_sort_fn, ast_sip_sched_task_cmp_fn);
631  if (!tasks) {
632  ast_log(LOG_ERROR, "Failed to allocate task container. Aborting load\n");
633  ast_sched_context_destroy(scheduler_context);
634  return -1;
635  }
636 
637  ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
638 
639  return 0;
640 }
641 
643 {
644  ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
645 
646  if (scheduler_context) {
647  if (tasks) {
648  struct ao2_iterator iter;
649  struct ast_sip_sched_task *schtd;
650 
651  /* Cancel all scheduled tasks */
652  iter = ao2_iterator_init(tasks, 0);
653  while ((schtd = ao2_iterator_next(&iter))) {
655  ao2_ref(schtd, -1);
656  }
657  ao2_iterator_destroy(&iter);
658  }
659 
660  ast_sched_context_destroy(scheduler_context);
661  scheduler_context = NULL;
662  }
663 
664  ao2_cleanup(tasks);
665  tasks = NULL;
666 
667  return 0;
668 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:463
int ast_sched_start_thread(struct ast_sched_context *con)
Start a thread for processing scheduler entries.
Definition: sched.c:195
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
ast_sip_scheduler_task_flags
Task flags for the res_pjsip scheduler.
Definition: res_pjsip.h:1767
Asterisk main include file. File version handling, generic pbx functions.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
AO2_STRING_FIELD_HASH_FN(ast_sip_sched_task, name)
struct timeval last_start
int ast_sip_sched_task_cancel(struct ast_sip_sched_task *schtd)
Cancels the next invocation of a task.
descriptor for a cli entry.
Definition: cli.h:171
const int argc
Definition: cli.h:160
static struct ast_sched_context * scheduler_context
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1739
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:108
Definition: cli.h:152
struct timeval when_queued
static char * cli_show_tasks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Scheduler ID holder.
Definition: sched.c:70
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
int ast_sip_destroy_scheduler(void)
#define ao2_unlock(a)
Definition: astobj2.h:730
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:98
#define ID_LEN
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
#define LOG_DEBUG
Definition: logger.h:241
int ast_sip_sched_task_get_times_by_name(const char *name, struct timeval *queued, struct timeval *last_start, struct timeval *last_end)
Gets the last start and end times of the task by name.
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:755
int ast_sip_sched_is_task_running(struct ast_sip_sched_task *schtd)
Checks if the task is currently running.
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ao2_bump(obj)
Definition: astobj2.h:491
struct ast_sip_sched_task * ast_sip_schedule_task(struct ast_taskprocessor *serializer, int interval, ast_sip_task sip_task, const char *name, void *task_data, enum ast_sip_scheduler_task_flags flags)
Schedule a task to run in the res_pjsip thread pool.
static int push_to_serializer(const void *data)
#define ast_log
Definition: astobj2.c:42
int ast_sip_sched_task_get_next_run_by_name(const char *name)
Gets the number of milliseconds until the next invocation.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
struct timeval next_periodic
const int fd
Definition: cli.h:159
#define TIME_FORMAT
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
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:238
int ast_sip_sched_task_get_times(struct ast_sip_sched_task *schtd, struct timeval *queued, struct timeval *last_start, struct timeval *last_end)
Gets the last start and end times of the task.
int ast_sip_sched_task_get_times_by_name2(const char *name, struct timeval *queued, struct timeval *last_start, struct timeval *last_end, int *interval, int *time_left, struct timeval *next_start)
Gets the queued, last start, last_end, time left, interval, next run by task name.
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
Definition: sched.c:236
const char *const * argv
Definition: cli.h:161
static struct ast_cli_entry cli_commands[]
#define LOG_ERROR
Definition: logger.h:285
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
int ast_sip_sched_is_task_running_by_name(const char *name)
Checks if the task is currently running.
#define ao2_unlink(container, obj)
Definition: astobj2.h:1598
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy all object references in the src container into the dest container.
#define CLI_SHOWUSAGE
Definition: cli.h:45
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:5138
int ast_sip_sched_task_get_times2(struct ast_sip_sched_task *schtd, struct timeval *queued, struct timeval *last_start, struct timeval *last_end, int *interval, int *time_left, struct timeval *next_start)
Gets the queued, last start, last_end, time left, interval, next run.
enum ast_sip_scheduler_task_flags flags
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2283
userdata associated with baseline taskprocessor test
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
int ast_sip_initialize_scheduler(void)
Initialize scheduler.
The next invocation of the task is at last finish + interval.
Definition: res_pjsip.h:1822
int ast_sip_sched_task_get_next_run(struct ast_sip_sched_task *schtd)
Gets the number of milliseconds until the next invocation.
#define CLI_FAILURE
Definition: cli.h:46
#define ast_free(a)
Definition: astmm.h:182
char * command
Definition: cli.h:186
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
Definition: func_strings.c:948
#define TASK_BUCKETS
static int task_count
int ast_sched_del(struct ast_sched_context *con, int id) attribute_warn_unused_result
Deletes a scheduled event.
Definition: sched.c:610
static int run_task(void *data)
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2524
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
An API for managing task processing threads that can be shared across modules.
int ast_sched_add(struct ast_sched_context *con, int when, ast_sched_cb callback, const void *data) attribute_warn_unused_result
Adds a scheduled event.
Definition: sched.c:565
The scheduled task&#39;s events are tracked in the debug log.
Definition: res_pjsip.h:1829
const char * usage
Definition: cli.h:177
struct timeval last_end
#define CLI_SUCCESS
Definition: cli.h:44
A ast_taskprocessor structure is a singleton by name.
Definition: taskprocessor.c:69
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static struct ao2_container * tasks
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
Definition: time.h:226
struct ast_taskprocessor * serializer
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Definition: astobj2.h:1358
Reject objects with duplicate keys in container.
Definition: astobj2.h:1192
static void schtd_dtor(void *data)
Generic container type.
int ast_sip_sched_task_get_name(struct ast_sip_sched_task *schtd, char *name, size_t maxlen)
Gets the task name.
AO2_STRING_FIELD_CMP_FN(ast_sip_sched_task, name)
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
Definition: sched.c:269
int(* ast_sip_task)(void *user_data)
Definition: res_pjsip.h:1573
int ast_sip_sched_task_cancel_by_name(const char *name)
Cancels the next invocation of a task by name.
AO2_STRING_FIELD_SORT_FN(ast_sip_sched_task, name)
static struct test_val a
#define ao2_link(container, obj)
Definition: astobj2.h:1549