[Asterisk-code-review] pjsip_scheduler.c: Add type ONESHOT and enhance cli show command (asterisk[18])

Kevin Harwell asteriskteam at digium.com
Mon Nov 9 16:39:11 CST 2020


Kevin Harwell has submitted this change. ( https://gerrit.asterisk.org/c/asterisk/+/15131 )

Change subject: pjsip_scheduler.c: Add type ONESHOT and enhance cli show command
......................................................................

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
---
M include/asterisk/res_pjsip.h
M res/res_pjsip/pjsip_scheduler.c
2 files changed, 167 insertions(+), 59 deletions(-)

Approvals:
  Kevin Harwell: Looks good to me, but someone else must approve; Approved for Submit
  Benjamin Keith Ford: Looks good to me, but someone else must approve
  George Joseph: Looks good to me, approved



diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index 07edcec..5e3e439 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -1785,6 +1785,12 @@
 	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.
 	 */
 	AST_SIP_SCHED_TASK_DATA_NOT_AO2 = (0 << 1),
@@ -1906,6 +1912,26 @@
 	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
  *
@@ -1921,6 +1947,26 @@
 	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
  *
diff --git a/res/res_pjsip/pjsip_scheduler.c b/res/res_pjsip/pjsip_scheduler.c
index bbf666f..ac53379 100644
--- a/res/res_pjsip/pjsip_scheduler.c
+++ b/res/res_pjsip/pjsip_scheduler.c
@@ -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 @@
 	 * 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 @@
 	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,14 +248,64 @@
 	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 @@
 		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_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 @@
 	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 @@
 #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(&regex, a->argv[4], REG_EXTENDED | REG_ICASE | REG_NOSUB);
+		if (regrc) {
+			char err[256];
+			regerror(regrc, &regex, 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 @@
 
 		ao2_lock(schtd);
 
+		if (using_regex && regexec(&regex, 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 @@
 		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(&regex);
+	}
 	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)

-- 
To view, visit https://gerrit.asterisk.org/c/asterisk/+/15131
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: 18
Gerrit-Change-Id: Ie718ca9fd30490b8a167bedf6b0b06d619dc52f3
Gerrit-Change-Number: 15131
Gerrit-PatchSet: 3
Gerrit-Owner: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Benjamin Keith Ford <bford at digium.com>
Gerrit-Reviewer: Friendly Automation
Gerrit-Reviewer: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Kevin Harwell <kharwell at digium.com>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20201109/6129c458/attachment-0001.html>


More information about the asterisk-code-review mailing list