diff options
author | David Lamparter <equinox@diac24.net> | 2019-12-04 08:10:42 +0100 |
---|---|---|
committer | David Lamparter <equinox@opensourcerouting.org> | 2022-02-28 13:28:43 +0100 |
commit | 4c92dd90d3d15cff640de063ff14eec950402d25 (patch) | |
tree | 5808962f6d1a8e8d71d4960e53ab35e20af02d78 /vtysh | |
parent | vtysh: receive file descriptors from daemons (diff) | |
download | frr-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.h | 1 | ||||
-rw-r--r-- | vtysh/vtysh_main.c | 62 |
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(); |