Asterisk - The Open Source Telephony Project GIT-master-3dae2cf
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 <george.joseph@fairview5.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/*! \file
20 *
21 * \brief res_pjsip Scheduler
22 *
23 * \author George Joseph <george.joseph@fairview5.com>
24 */
25
26#include "asterisk.h"
27
28#include "asterisk/res_pjsip.h"
32
33#include <regex.h>
34
35#define TASK_BUCKETS 53
36
38static struct ao2_container *tasks;
39static 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 */
58 /*! ast_sched scheduler id */
60 /*! task is currently running */
62 /*! times run */
64 /*! the task reschedule, cleanup and policy flags */
66 /*! A name to be associated with the task */
67 char name[0];
68};
69
73
74static 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 */
80static 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 */
157static 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);
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
209 schtd->current_scheduler_id = -1;
210 ao2_unlock(schtd);
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
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
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{
331 NULL, NULL, NULL);
332}
333
334int 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
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
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
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
399static 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
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
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);
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
490static 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 }
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
610static struct ast_cli_entry cli_commands[] = {
611 AST_CLI_DEFINE(cli_show_tasks, "Show pjsip scheduled tasks"),
612};
613
615{
617 if (!scheduler_context) {
618 ast_log(LOG_ERROR, "Failed to create scheduler. Aborting load\n");
619 return -1;
620 }
621
623 ast_log(LOG_ERROR, "Failed to start scheduler. Aborting load\n");
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");
634 return -1;
635 }
636
638
639 return 0;
640}
641
643{
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 }
658 }
659
662 }
663
665 tasks = NULL;
666
667 return 0;
668}
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_log
Definition: astobj2.c:42
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 ao2_t_ref(o, delta, tag)
Definition: astobj2.h:460
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
@ AO2_ALLOC_OPT_LOCK_RWLOCK
Definition: astobj2.h:365
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
@ AO2_ITERATOR_UNLINK
Definition: astobj2.h:1863
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a red-black tree container.
Definition: astobj2.h:1349
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT
Reject objects with duplicate keys in container.
Definition: astobj2.h:1188
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define CLI_FAILURE
Definition: cli.h:46
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
static const char name[]
Definition: format_mp3.c:68
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
int(* ast_sip_task)(void *user_data)
Definition: res_pjsip.h:1869
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.
ast_sip_scheduler_task_flags
Task flags for the res_pjsip scheduler.
Definition: res_pjsip.h:2063
int ast_sip_sched_task_cancel_by_name(const char *name)
Cancels the next invocation of a task by name.
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:2099
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.
int ast_sip_sched_task_cancel(struct ast_sip_sched_task *schtd)
Cancels the next invocation of a task.
int ast_sip_sched_is_task_running(struct ast_sip_sched_task *schtd)
Checks if the task is currently running.
int ast_sip_sched_task_get_name(struct ast_sip_sched_task *schtd, char *name, size_t maxlen)
Gets the task name.
int ast_sip_sched_task_get_next_run(struct ast_sip_sched_task *schtd)
Gets the number of milliseconds until the next invocation.
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_next_run_by_name(const char *name)
Gets the number of milliseconds until the next invocation.
int ast_sip_sched_is_task_running_by_name(const char *name)
Checks if the task is currently running.
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.
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.
@ AST_SIP_SCHED_TASK_ONESHOT
Definition: res_pjsip.h:2086
@ AST_SIP_SCHED_TASK_DELAY
The next invocation of the task is at last finish + interval.
Definition: res_pjsip.h:2118
@ AST_SIP_SCHED_TASK_TRACK
The scheduled task's events are tracked in the debug log.
Definition: res_pjsip.h:2125
@ AST_SIP_SCHED_TASK_DATA_AO2
Definition: res_pjsip.h:2097
@ AST_SIP_SCHED_TASK_DATA_FREE
Definition: res_pjsip.h:2107
@ AST_SIP_SCHED_TASK_VARIABLE
Definition: res_pjsip.h:2080
#define LOG_DEBUG
#define LOG_ERROR
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_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
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:757
int ast_sip_initialize_scheduler(void)
Initialize scheduler.
#define TASK_BUCKETS
static int run_task(void *data)
static struct ast_cli_entry cli_commands[]
AO2_STRING_FIELD_CMP_FN(ast_sip_sched_task, name)
static char * cli_show_tasks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
AO2_STRING_FIELD_SORT_FN(ast_sip_sched_task, name)
static struct ast_sched_context * scheduler_context
int ast_sip_destroy_scheduler(void)
static int task_count
static void schtd_dtor(void *data)
static struct ao2_container * tasks
#define ID_LEN
static int push_to_serializer(const void *data)
AO2_STRING_FIELD_HASH_FN(ast_sip_sched_task, name)
#define TIME_FORMAT
#define NULL
Definition: resample.c:96
int ast_sched_del(struct ast_sched_context *con, int id) attribute_warn_unused_result
Deletes a scheduled event.
Definition: sched.c:614
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:567
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
Definition: sched.c:271
int ast_sched_start_thread(struct ast_sched_context *con)
Start a thread for processing scheduler entries.
Definition: sched.c:197
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
Definition: sched.c:238
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
struct timeval last_start
struct timeval next_periodic
struct timeval when_queued
struct timeval last_end
struct ast_taskprocessor * serializer
enum ast_sip_scheduler_task_flags flags
A ast_taskprocessor structure is a singleton by name.
Definition: taskprocessor.c:69
Scheduler ID holder.
Definition: sched.c:70
userdata associated with baseline taskprocessor test
An API for managing task processing threads that can be shared across modules.
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
static struct test_val a
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:282
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:117
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2282
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
Definition: time.h:235
#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:941
#define ARRAY_LEN(a)
Definition: utils.h:666