summaryrefslogtreecommitdiffstats
path: root/vtysh
diff options
context:
space:
mode:
authorDavid Lamparter <equinox@diac24.net>2019-12-04 08:10:42 +0100
committerDavid Lamparter <equinox@opensourcerouting.org>2022-02-28 13:28:43 +0100
commit4c92dd90d3d15cff640de063ff14eec950402d25 (patch)
tree5808962f6d1a8e8d71d4960e53ab35e20af02d78 /vtysh
parentvtysh: receive file descriptors from daemons (diff)
downloadfrr-4c92dd90d3d15cff640de063ff14eec950402d25.tar.xz
frr-4c92dd90d3d15cff640de063ff14eec950402d25.zip
vtysh: use poll/callback-driven readline interface
Create a thread_master and funnel readline terminal I/O through it. This allows processing other input in parallel, e.g. log messages. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
Diffstat (limited to 'vtysh')
-rw-r--r--vtysh/vtysh.h1
-rw-r--r--vtysh/vtysh_main.c62
2 files changed, 45 insertions, 18 deletions
diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h
index 757b832a9..8fb85293e 100644
--- a/vtysh/vtysh.h
+++ b/vtysh/vtysh.h
@@ -73,6 +73,7 @@ extern enum vtysh_write_integrated vtysh_write_integrated;
extern char frr_config[];
extern char vtydir[];
+extern bool vtysh_loop_exited;
void vtysh_init_vty(void);
void vtysh_uninit(void);
diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c
index a4f27b61c..04eb47fee 100644
--- a/vtysh/vtysh_main.c
+++ b/vtysh/vtysh_main.c
@@ -84,9 +84,6 @@ static sigjmp_buf jmpbuf;
/* Flag for avoid recursive siglongjmp() call. */
static int jmpflag = 0;
-/* A static variable for holding the line. */
-static char *line_read;
-
/* Master of threads. */
struct thread_master *master;
@@ -208,23 +205,22 @@ struct option longopts[] = {
{"timestamp", no_argument, NULL, 't'},
{0}};
-/* Read a string, and return a pointer to it. Returns NULL on EOF. */
-static char *vtysh_rl_gets(void)
+bool vtysh_loop_exited;
+
+static void vtysh_rl_callback(char *line_read)
{
HIST_ENTRY *last;
- /* If the buffer has already been allocated, return the memory
- * to the free pool. */
- if (line_read) {
- free(line_read);
- line_read = NULL;
- }
- /* Get a line from the user. Change prompt according to node. XXX. */
- line_read = readline(vtysh_prompt());
+ rl_callback_handler_remove();
+
+ if (!line_read) {
+ vtysh_loop_exited = true;
+ return;
+ }
/* If the line has any text in it, save it on the history. But only if
* last command in history isn't the same one. */
- if (line_read && *line_read) {
+ if (*line_read) {
using_history();
last = previous_history();
if (!last || strcmp(last->line, line_read) != 0) {
@@ -233,7 +229,39 @@ static char *vtysh_rl_gets(void)
}
}
- return (line_read);
+ vtysh_execute(line_read);
+
+ if (!vtysh_loop_exited)
+ rl_callback_handler_install(vtysh_prompt(), vtysh_rl_callback);
+}
+
+static struct thread *vtysh_rl_read_thread;
+
+static void vtysh_rl_read(struct thread *thread)
+{
+ thread_add_read(master, vtysh_rl_read, NULL, STDIN_FILENO,
+ &vtysh_rl_read_thread);
+ rl_callback_read_char();
+}
+
+/* Read a string, and return a pointer to it. Returns NULL on EOF. */
+static void vtysh_rl_run(void)
+{
+ struct thread thread;
+
+ master = thread_master_create(NULL);
+
+ rl_callback_handler_install(vtysh_prompt(), vtysh_rl_callback);
+ thread_add_read(master, vtysh_rl_read, NULL, STDIN_FILENO,
+ &vtysh_rl_read_thread);
+
+ while (!vtysh_loop_exited && thread_fetch(master, &thread))
+ thread_call(&thread);
+
+ if (!vtysh_loop_exited)
+ rl_callback_handler_remove();
+
+ thread_master_free(master);
}
static void log_it(const char *line)
@@ -458,7 +486,6 @@ int main(int argc, char **argv, char **env)
}
/* Initialize user input buffer. */
- line_read = NULL;
setlinebuf(stdout);
/* Signal and others. */
@@ -730,8 +757,7 @@ int main(int argc, char **argv, char **env)
jmpflag = 1;
/* Main command loop. */
- while (vtysh_rl_gets())
- vtysh_execute(line_read);
+ vtysh_rl_run();
vtysh_uninit();