pjsip_scheduler.c: Add type ONESHOT and enhance cli show command
* Added a ONESHOT type that never reschedules. * Added "like" capability to "pjsip show scheduled_tasks" so you can do the following: CLI> pjsip show scheduled_tasks like outreg PJSIP Scheduled Tasks: Task Name Interval Times Run ... ============================================= ========= ========= ... pjsip/outreg/testtrunk-reg-0-00000074 50.000 oneshot ... pjsip/outreg/voipms-reg-0-00000073 110.000 oneshot ... * Fixed incorrect display of "Next Start". * Compacted the displays of times in the CLI. * Added two new functions (ast_sip_sched_task_get_times2, ast_sip_sched_task_get_times_by_name2) that retrieve the interval, next start time, and next run time in addition to the times already returned by ast_sip_sched_task_get_times(). Change-Id: Ie718ca9fd30490b8a167bedf6b0b06d619dc52f3
This commit is contained in:
parent
728cd55cde
commit
80f116c156
|
@ -1708,6 +1708,12 @@ enum ast_sip_scheduler_task_flags {
|
|||
*/
|
||||
AST_SIP_SCHED_TASK_VARIABLE = (1 << 0),
|
||||
|
||||
/*!
|
||||
* Run just once.
|
||||
* Return values are ignored.
|
||||
*/
|
||||
AST_SIP_SCHED_TASK_ONESHOT = (1 << 6),
|
||||
|
||||
/*!
|
||||
* The task data is not an AO2 object.
|
||||
*/
|
||||
|
@ -1829,6 +1835,26 @@ int ast_sip_sched_task_cancel_by_name(const char *name);
|
|||
int ast_sip_sched_task_get_times(struct ast_sip_sched_task *schtd,
|
||||
struct timeval *when_queued, struct timeval *last_start, struct timeval *last_end);
|
||||
|
||||
/*!
|
||||
* \brief Gets the queued, last start, last_end, time left, interval, next run
|
||||
* \since 16.15.0
|
||||
* \since 18.1.0
|
||||
*
|
||||
* \param schtd The task structure pointer
|
||||
* \param[out] when_queued Pointer to a timeval structure to contain the time when queued
|
||||
* \param[out] last_start Pointer to a timeval structure to contain the time when last started
|
||||
* \param[out] last_end Pointer to a timeval structure to contain the time when last ended
|
||||
* \param[out] interval Pointer to an int to contain the interval in ms
|
||||
* \param[out] time_left Pointer to an int to contain the ms left to the next run
|
||||
* \param[out] last_end Pointer to a timeval structure to contain the next run time
|
||||
* \retval 0 Success
|
||||
* \retval -1 Failure
|
||||
* \note Any of the pointers can be NULL if you don't need them.
|
||||
*/
|
||||
int ast_sip_sched_task_get_times2(struct ast_sip_sched_task *schtd,
|
||||
struct timeval *when_queued, struct timeval *last_start, struct timeval *last_end,
|
||||
int *interval, int *time_left, struct timeval *next_start);
|
||||
|
||||
/*!
|
||||
* \brief Gets the last start and end times of the task by name
|
||||
* \since 13.9.0
|
||||
|
@ -1844,6 +1870,26 @@ int ast_sip_sched_task_get_times(struct ast_sip_sched_task *schtd,
|
|||
int ast_sip_sched_task_get_times_by_name(const char *name,
|
||||
struct timeval *when_queued, struct timeval *last_start, struct timeval *last_end);
|
||||
|
||||
/*!
|
||||
* \brief Gets the queued, last start, last_end, time left, interval, next run by task name
|
||||
* \since 16.15.0
|
||||
* \since 18.1.0
|
||||
*
|
||||
* \param name The task name
|
||||
* \param[out] when_queued Pointer to a timeval structure to contain the time when queued
|
||||
* \param[out] last_start Pointer to a timeval structure to contain the time when last started
|
||||
* \param[out] last_end Pointer to a timeval structure to contain the time when last ended
|
||||
* \param[out] interval Pointer to an int to contain the interval in ms
|
||||
* \param[out] time_left Pointer to an int to contain the ms left to the next run
|
||||
* \param[out] last_end Pointer to a timeval structure to contain the next run time
|
||||
* \retval 0 Success
|
||||
* \retval -1 Failure
|
||||
* \note Any of the pointers can be NULL if you don't need them.
|
||||
*/
|
||||
int ast_sip_sched_task_get_times_by_name2(const char *name,
|
||||
struct timeval *when_queued, struct timeval *last_start, struct timeval *last_end,
|
||||
int *interval, int *time_left, struct timeval *next_start);
|
||||
|
||||
/*!
|
||||
* \brief Gets the number of milliseconds until the next invocation
|
||||
* \since 13.9.0
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
#include "asterisk/res_pjsip_cli.h"
|
||||
#include "asterisk/taskprocessor.h"
|
||||
|
||||
#include <regex.h>
|
||||
|
||||
#define TASK_BUCKETS 53
|
||||
|
||||
static struct ast_sched_context *scheduler_context;
|
||||
|
@ -105,7 +107,7 @@ static int run_task(void *data)
|
|||
* Don't restart if the task returned <= 0 or if the interval
|
||||
* was set to 0 while the task was running
|
||||
*/
|
||||
if (res <= 0 || !schtd->interval) {
|
||||
if ((schtd->flags & AST_SIP_SCHED_TASK_ONESHOT) || res <= 0 || !schtd->interval) {
|
||||
schtd->interval = 0;
|
||||
ao2_unlock(schtd);
|
||||
ao2_unlink(tasks, schtd);
|
||||
|
@ -232,9 +234,9 @@ int ast_sip_sched_task_cancel_by_name(const char *name)
|
|||
return res;
|
||||
}
|
||||
|
||||
|
||||
int ast_sip_sched_task_get_times(struct ast_sip_sched_task *schtd,
|
||||
struct timeval *queued, struct timeval *last_start, struct timeval *last_end)
|
||||
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)
|
||||
{
|
||||
ao2_lock(schtd);
|
||||
if (queued) {
|
||||
|
@ -246,13 +248,63 @@ int ast_sip_sched_task_get_times(struct ast_sip_sched_task *schtd,
|
|||
if (last_end) {
|
||||
memcpy(last_end, &schtd->last_end, sizeof(struct timeval));
|
||||
}
|
||||
|
||||
if (interval) {
|
||||
*interval = schtd->interval;
|
||||
}
|
||||
|
||||
if (time_left || next_start) {
|
||||
int delay;
|
||||
struct timeval since_when;
|
||||
struct timeval now;
|
||||
struct timeval next;
|
||||
|
||||
if (schtd->interval) {
|
||||
delay = schtd->interval;
|
||||
now = ast_tvnow();
|
||||
|
||||
if (schtd->flags & AST_SIP_SCHED_TASK_DELAY) {
|
||||
since_when = schtd->is_running ? now : schtd->last_end;
|
||||
} else {
|
||||
since_when = schtd->last_start.tv_sec ? schtd->last_start : schtd->when_queued;
|
||||
}
|
||||
|
||||
delay -= ast_tvdiff_ms(now, since_when);
|
||||
|
||||
delay = delay < 0 ? 0 : delay;
|
||||
|
||||
|
||||
if (time_left) {
|
||||
*time_left = delay;
|
||||
}
|
||||
|
||||
if (next_start) {
|
||||
next = ast_tvadd(now, ast_tv(delay / 1000, (delay % 1000) * 1000));
|
||||
memcpy(next_start, &next, sizeof(struct timeval));
|
||||
}
|
||||
} else {
|
||||
if (time_left) {
|
||||
*time_left = -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ao2_unlock(schtd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ast_sip_sched_task_get_times_by_name(const char *name,
|
||||
|
||||
int ast_sip_sched_task_get_times(struct ast_sip_sched_task *schtd,
|
||||
struct timeval *queued, struct timeval *last_start, struct timeval *last_end)
|
||||
{
|
||||
return ast_sip_sched_task_get_times2(schtd, queued, last_start, last_end, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int res;
|
||||
struct ast_sip_sched_task *schtd;
|
||||
|
@ -266,11 +318,19 @@ int ast_sip_sched_task_get_times_by_name(const char *name,
|
|||
return -1;
|
||||
}
|
||||
|
||||
res = ast_sip_sched_task_get_times(schtd, queued, last_start, last_end);
|
||||
res = ast_sip_sched_task_get_times2(schtd, queued, last_start, last_end, interval, time_left,
|
||||
next_start);
|
||||
ao2_ref(schtd, -1);
|
||||
return res;
|
||||
}
|
||||
|
||||
int ast_sip_sched_task_get_times_by_name(const char *name,
|
||||
struct timeval *queued, struct timeval *last_start, struct timeval *last_end)
|
||||
{
|
||||
return ast_sip_sched_task_get_times_by_name2(name, queued, last_start, last_end,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
int ast_sip_sched_task_get_name(struct ast_sip_sched_task *schtd, char *name, size_t maxlen)
|
||||
{
|
||||
if (maxlen <= 0) {
|
||||
|
@ -287,29 +347,8 @@ int ast_sip_sched_task_get_name(struct ast_sip_sched_task *schtd, char *name, si
|
|||
int ast_sip_sched_task_get_next_run(struct ast_sip_sched_task *schtd)
|
||||
{
|
||||
int delay;
|
||||
struct timeval since_when;
|
||||
struct timeval now;
|
||||
|
||||
ao2_lock(schtd);
|
||||
|
||||
if (schtd->interval) {
|
||||
delay = schtd->interval;
|
||||
now = ast_tvnow();
|
||||
|
||||
if (schtd->flags & AST_SIP_SCHED_TASK_DELAY) {
|
||||
since_when = schtd->is_running ? now : schtd->last_end;
|
||||
} else {
|
||||
since_when = schtd->last_start.tv_sec ? schtd->last_start : schtd->when_queued;
|
||||
}
|
||||
|
||||
delay -= ast_tvdiff_ms(now, since_when);
|
||||
|
||||
delay = delay < 0 ? 0 : delay;
|
||||
} else {
|
||||
delay = -1;
|
||||
}
|
||||
|
||||
ao2_unlock(schtd);
|
||||
ast_sip_sched_task_get_times2(schtd, NULL, NULL, NULL, NULL, &delay, NULL);
|
||||
|
||||
return delay;
|
||||
}
|
||||
|
@ -396,6 +435,7 @@ struct ast_sip_sched_task *ast_sip_schedule_task(struct ast_taskprocessor *seria
|
|||
schtd->task = sip_task;
|
||||
schtd->interval = interval;
|
||||
schtd->flags = flags;
|
||||
schtd->last_start = ast_tv(0, 0);
|
||||
if (!ast_strlen_zero(name)) {
|
||||
strcpy(schtd->name, name); /* Safe */
|
||||
} else {
|
||||
|
@ -445,60 +485,75 @@ struct ast_sip_sched_task *ast_sip_schedule_task(struct ast_taskprocessor *seria
|
|||
#undef ID_LEN
|
||||
}
|
||||
|
||||
#define TIME_FORMAT "%a %T"
|
||||
|
||||
static char *cli_show_tasks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
{
|
||||
struct ao2_iterator iter;
|
||||
struct ao2_container *sorted_tasks;
|
||||
struct ast_sip_sched_task *schtd;
|
||||
const char *log_format;
|
||||
struct ast_tm tm;
|
||||
char times_run[16];
|
||||
char queued[32];
|
||||
char last_start[32];
|
||||
char next_start[32];
|
||||
int datelen;
|
||||
struct timeval now;
|
||||
static const char separator[] = "=============================================";
|
||||
int using_regex = 0;
|
||||
regex_t regex;
|
||||
|
||||
switch (cmd) {
|
||||
case CLI_INIT:
|
||||
e->command = "pjsip show scheduled_tasks";
|
||||
e->usage = "Usage: pjsip show scheduled_tasks\n"
|
||||
" Show all scheduled tasks\n";
|
||||
e->usage = "Usage: pjsip show scheduled_tasks [ like <pattern> ]\n"
|
||||
" Show scheduled pjsip tasks\n";
|
||||
return NULL;
|
||||
case CLI_GENERATE:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (a->argc != 3) {
|
||||
if (a->argc != 3 && a->argc != 5) {
|
||||
return CLI_SHOWUSAGE;
|
||||
}
|
||||
|
||||
if (a->argc == 5) {
|
||||
int regrc;
|
||||
if (!strcasecmp(a->argv[3], "like") == 0) {
|
||||
return CLI_SHOWUSAGE;
|
||||
}
|
||||
regrc = regcomp(®ex, a->argv[4], REG_EXTENDED | REG_ICASE | REG_NOSUB);
|
||||
if (regrc) {
|
||||
char err[256];
|
||||
regerror(regrc, ®ex, err, 256);
|
||||
ast_cli(a->fd, "PJSIP Scheduled Tasks: Error: %s\n", err);
|
||||
return CLI_FAILURE;
|
||||
}
|
||||
using_regex = 1;
|
||||
}
|
||||
|
||||
/* Get a sorted snapshot of the scheduled tasks */
|
||||
sorted_tasks = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
|
||||
ast_sip_sched_task_sort_fn, NULL);
|
||||
if (!sorted_tasks) {
|
||||
return CLI_SUCCESS;
|
||||
ast_cli(a->fd, "PJSIP Scheduled Tasks: Unable to allocate temporary container\n");
|
||||
return CLI_FAILURE;
|
||||
}
|
||||
if (ao2_container_dup(sorted_tasks, tasks, 0)) {
|
||||
ao2_ref(sorted_tasks, -1);
|
||||
return CLI_SUCCESS;
|
||||
ast_cli(a->fd, "PJSIP Scheduled Tasks: Unable to sort temporary container\n");
|
||||
return CLI_FAILURE;
|
||||
}
|
||||
|
||||
now = ast_tvnow();
|
||||
log_format = ast_logger_get_dateformat();
|
||||
|
||||
ast_localtime(&now, &tm, NULL);
|
||||
datelen = ast_strftime(queued, sizeof(queued), log_format, &tm);
|
||||
|
||||
ast_cli(a->fd, "PJSIP Scheduled Tasks:\n\n");
|
||||
|
||||
ast_cli(a->fd, "%1$-45s %2$-9s %3$-9s %4$-5s %6$-*5$s %7$-*5$s %8$-*5$s %9$7s\n",
|
||||
"Task Name", "Interval", "Times Run", "State",
|
||||
datelen, "Queued", "Last Started", "Next Start", "( secs)");
|
||||
|
||||
ast_cli(a->fd, "%1$-45.45s %2$-9.9s %3$-9.9s %4$-5.5s %6$-*5$.*5$s %7$-*5$.*5$s %9$-*8$.*8$s\n",
|
||||
separator, separator, separator, separator,
|
||||
datelen, separator, separator, datelen + 8, separator);
|
||||
ast_cli(a->fd,
|
||||
"<Task Name....................................> <Interval> <Times Run> <State>"
|
||||
" <Queued....> <Last Start> <Next Start.....secs>\n"
|
||||
"=============================================================================="
|
||||
"===================================================\n");
|
||||
|
||||
iter = ao2_iterator_init(sorted_tasks, AO2_ITERATOR_UNLINK);
|
||||
for (; (schtd = ao2_iterator_next(&iter)); ao2_ref(schtd, -1)) {
|
||||
|
@ -507,6 +562,11 @@ static char *cli_show_tasks(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
|
|||
|
||||
ao2_lock(schtd);
|
||||
|
||||
if (using_regex && regexec(®ex, schtd->name, 0, NULL, 0) == REG_NOMATCH) {
|
||||
ao2_unlock(schtd);
|
||||
continue;
|
||||
}
|
||||
|
||||
next_run_sec = ast_sip_sched_task_get_next_run(schtd) / 1000;
|
||||
if (next_run_sec < 0) {
|
||||
/* Scheduled task is now canceled */
|
||||
|
@ -516,37 +576,39 @@ static char *cli_show_tasks(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
|
|||
next = ast_tvadd(now, ast_tv(next_run_sec, 0));
|
||||
|
||||
ast_localtime(&schtd->when_queued, &tm, NULL);
|
||||
ast_strftime(queued, sizeof(queued), log_format, &tm);
|
||||
ast_strftime(queued, sizeof(queued), TIME_FORMAT, &tm);
|
||||
|
||||
if (ast_tvzero(schtd->last_start)) {
|
||||
strcpy(last_start, "not yet started");
|
||||
} else {
|
||||
ast_localtime(&schtd->last_start, &tm, NULL);
|
||||
ast_strftime(last_start, sizeof(last_start), log_format, &tm);
|
||||
}
|
||||
ast_localtime(&schtd->last_start, &tm, NULL);
|
||||
ast_strftime(last_start, sizeof(last_start), TIME_FORMAT, &tm);
|
||||
|
||||
ast_localtime(&next, &tm, NULL);
|
||||
ast_strftime(next_start, sizeof(next_start), log_format, &tm);
|
||||
ast_strftime(next_start, sizeof(next_start), TIME_FORMAT, &tm);
|
||||
|
||||
ast_cli(a->fd, "%1$-46.46s%2$9.3f %3$9d %4$-5s %6$-*5$s %7$-*5$s %8$-*5$s (%9$5d)\n",
|
||||
sprintf(times_run, "%d", schtd->run_count);
|
||||
|
||||
ast_cli(a->fd, "%-46.46s %9d %9s %-5s %-12s %-12s %-12s %8d\n",
|
||||
schtd->name,
|
||||
schtd->interval / 1000.0,
|
||||
schtd->run_count,
|
||||
schtd->interval / 1000,
|
||||
schtd->flags & AST_SIP_SCHED_TASK_ONESHOT ? "oneshot" : times_run,
|
||||
schtd->is_running ? "run" : "wait",
|
||||
datelen, queued, last_start,
|
||||
queued,
|
||||
(ast_tvzero(schtd->last_start) || (schtd->flags & AST_SIP_SCHED_TASK_ONESHOT) ? "" : last_start),
|
||||
next_start,
|
||||
next_run_sec);
|
||||
ao2_unlock(schtd);
|
||||
}
|
||||
if (using_regex) {
|
||||
regfree(®ex);
|
||||
}
|
||||
ao2_iterator_destroy(&iter);
|
||||
ast_cli(a->fd, "\nTotal Scheduled Tasks: %d\n\n", ao2_container_count(sorted_tasks));
|
||||
ao2_ref(sorted_tasks, -1);
|
||||
ast_cli(a->fd, "\n");
|
||||
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
|
||||
static struct ast_cli_entry cli_commands[] = {
|
||||
AST_CLI_DEFINE(cli_show_tasks, "Show all scheduled tasks"),
|
||||
AST_CLI_DEFINE(cli_show_tasks, "Show pjsip scheduled tasks"),
|
||||
};
|
||||
|
||||
int ast_sip_initialize_scheduler(void)
|
||||
|
|
Loading…
Reference in New Issue