From d72dd985c192dea3532657bd1674d2253afc8385 Mon Sep 17 00:00:00 2001 From: patacongo Date: Thu, 14 Aug 2008 23:37:12 +0000 Subject: [PATCH] Fix reentrancy problems for serial git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@821 42af7a65-404d-4744-a932-0658087f49c3 --- examples/nsh/nsh.h | 30 +++++------ examples/nsh/nsh_main.c | 59 +++++++++++++++++--- examples/nsh/nsh_serial.c | 108 ++++++++++++++++++++++++++++++++----- examples/nsh/nsh_telnetd.c | 10 ++-- 4 files changed, 166 insertions(+), 41 deletions(-) diff --git a/examples/nsh/nsh.h b/examples/nsh/nsh.h index 0cc47274ab..ff6df6b24e 100644 --- a/examples/nsh/nsh.h +++ b/examples/nsh/nsh.h @@ -115,27 +115,27 @@ extern const char g_fmtcmdoutofmemory[]; /* Message handler */ -extern int nsh_parse(FAR void *handle, char *cmdline); +extern int nsh_parse(FAR void *handle, char *cmdline); /* I/O interfaces */ -#ifdef CONFIG_EXAMPLES_NSH_TELNET - -extern int nsh_telnetmain(void); -extern int nsh_telnetout(FAR void *handle, const char *fmt, ...); - -# define nsh_main() nsh_telnetmain() -# define nsh_output(handle, ...) nsh_telnetout(handle, __VA_ARGS__) +extern int nsh_main(void); +extern int nsh_output(FAR void *handle, const char *fmt, ...); +extern FAR char *nsh_linebuffer(FAR void *handle); +#ifndef CONFIG_EXAMPLES_NSH_TELNET /* Not yet supported on telnetd interface */ +extern FAR void *nsh_clone(FAR void *handle); +extern void nsh_addref(FAR void *handle); +extern void nsh_release(FAR void *handle); +extern void *nsh_redirect(int fd); +extern void nsh_restore(void *direct); #else - -extern int nsh_serialmain(void); - -# define nsh_main() nsh_serialmain() -# define nsh_output(handle, ...) printf(__VA_ARGS__) - +# define nsh_clone(handle) (handle) +# define nsh_addref(handle) +# define nsh_release(handle); +# define nsh_redirect(fd) (NULL); +# define nsh_restore(direct) #endif -extern char *nsh_linebuffer(FAR void *handle); /* Shell command handlers */ diff --git a/examples/nsh/nsh_main.c b/examples/nsh/nsh_main.c index 785062bc56..cf20141cb2 100644 --- a/examples/nsh/nsh_main.c +++ b/examples/nsh/nsh_main.c @@ -256,6 +256,7 @@ static int nsh_execute(int argc, char *argv[]) } handler(handle, argc, &argv[2]); + nsh_release(handle); return OK; } @@ -361,16 +362,15 @@ int nsh_parse(FAR void *handle, char *cmdline) * in the "background" * argv[1]: This is string version of the handle needed to execute * the command (under telnetd). It is a string because - * binary values cannot be provided via char *argv[] + * binary values cannot be provided via char *argv[]. NOTE + * that this value is filled in later. * argv[2]: The command name. This is argv[0] when the arguments * are, finally, received by the command handler * argv[3]: The beginning of argument (up to NSH_MAX_ARGUMENTS) * argv[argc]: NULL terminating pointer */ - sprintf(strhandle, "%p\n", handle); argv[0] = "nsh_execute"; - argv[1] = strhandle; argv[2] = cmd; for (argc = 3; argc < NSH_MAX_ARGUMENTS+4; argc++) { @@ -400,8 +400,25 @@ int nsh_parse(FAR void *handle, char *cmdline) { struct sched_param param; int priority; + void *bkghandle; - /* Get the execution priority of this task */ + /* Get a cloned copy of the handle with reference count=1. + * after the command has been processed, the nsh_release() call + * at the end of nsh_execute() will destroy the clone. + */ + + bkghandle = nsh_clone(handle); + + /* Place a string copy of the cloned handle in the argument list */ + + sprintf(strhandle, "%p\n", bkghandle); + argv[1] = strhandle; + + /* Handle redirection of output via a file descriptor */ + + /* (void)nsh_redirect(bkghandle); */ + + /* Get the execution priority of this task */ ret = sched_getparam(0, ¶m); if (ret != 0) @@ -455,17 +472,43 @@ int nsh_parse(FAR void *handle, char *cmdline) } else { + /* void *save; */ + + /* Increment the reference count on the handle. This reference count will + * be decremented at the end of nsh_execute() and exists only for compatibility + * with the background command logic. + */ + + nsh_addref(handle); + + /* Place a string copy of the original handle in the argument list */ + + sprintf(strhandle, "%p\n", handle); + argv[1] = strhandle; + + /* Handle redirection of output via a file descriptor */ + /* save = nsh_redirect(fd); */ + + /* Then execute the command in "foreground" -- i.e., while the user waits + * for the next prompt. + */ + ret = nsh_execute(argc, argv); + if (ret < 0) + { + return ERROR; + } + + /* Restore the original output */ + + /* nsh_undirect(save); */ } /* Return success if the command succeeded (or at least, starting of the * command task succeeded). */ - if (ret == 0) - { - return OK; - } + return OK; } return ERROR; diff --git a/examples/nsh/nsh_serial.c b/examples/nsh/nsh_serial.c index 5052109d2c..fee6532666 100644 --- a/examples/nsh/nsh_serial.c +++ b/examples/nsh/nsh_serial.c @@ -43,6 +43,7 @@ #include #include #include +#include #include "nsh.h" @@ -54,13 +55,10 @@ * Private Types ****************************************************************************/ -struct cmdmap_s +struct serial_s { - const char *cmd; /* Name of the command */ - cmd_t handler; /* Function that handles the command */ - ubyte minargs; /* Minimum number of arguments (including command) */ - ubyte maxargs; /* Maximum number of arguments (including command) */ - const char *usage; /* Usage instructions for 'help' command */ + int ss_refs; /* Reference counts on the intance */ + char ss_line[CONFIG_EXAMPLES_NSH_LINELEN]; }; /**************************************************************************** @@ -71,8 +69,6 @@ struct cmdmap_s * Private Data ****************************************************************************/ -static char g_line[CONFIG_EXAMPLES_NSH_LINELEN]; - /**************************************************************************** * Public Data ****************************************************************************/ @@ -81,6 +77,20 @@ static char g_line[CONFIG_EXAMPLES_NSH_LINELEN]; * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: nsh_allocstruct + ****************************************************************************/ + +static inline FAR struct serial_s *nsh_allocstruct(void) +{ + struct serial_s *pstate = (struct serial_s *)malloc(sizeof(struct serial_s)); + if (pstate) + { + pstate->ss_refs = 1; + } + return pstate; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -89,8 +99,10 @@ static char g_line[CONFIG_EXAMPLES_NSH_LINELEN]; * Name: nsh_main ****************************************************************************/ -int nsh_serialmain(void) +int nsh_main(void) { + FAR struct serial_s *pstate = nsh_allocstruct(); + printf("NuttShell (NSH)\n"); fflush(stdout); @@ -103,16 +115,36 @@ int nsh_serialmain(void) /* Get the next line of input */ - if (fgets(g_line, CONFIG_EXAMPLES_NSH_LINELEN, stdin)) + if (fgets(pstate->ss_line, CONFIG_EXAMPLES_NSH_LINELEN, stdin)) { /* Parse process the command */ - (void)nsh_parse(NULL, g_line); + (void)nsh_parse(pstate, pstate->ss_line); fflush(stdout); } } } +/**************************************************************************** + * Name: nsh_output + * + * Description: + * Print a string to stdout. + * + ****************************************************************************/ + +int nsh_output(FAR void *handle, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = vfprintf(stdout, fmt, ap); + va_end(ap); + + return ret; +} + /**************************************************************************** * Name: nsh_linebuffer * @@ -121,9 +153,59 @@ int nsh_serialmain(void) * ****************************************************************************/ -extern char *nsh_linebuffer(FAR void *handle) +FAR char *nsh_linebuffer(FAR void *handle) { - return g_line; + FAR struct serial_s *pstate = (FAR struct serial_s *)handle; + return pstate->ss_line; +} + +/**************************************************************************** + * Name: nsh_clone + * + * Description: + * Make an independent copy of the handle + * + ****************************************************************************/ + +FAR void *nsh_clone(FAR void *handle) +{ + return nsh_allocstruct(); +} + +/**************************************************************************** + * Name: nsh_addref + * + * Description: + * Increment the reference count on the handle. + * + ****************************************************************************/ + +void nsh_addref(FAR void *handle) +{ + FAR struct serial_s *pstate = (FAR struct serial_s *)handle; + pstate->ss_refs++; +} + +/**************************************************************************** + * Name: nsh_release + * + * Description: + * Decrement the reference count on the handle, releasing it when the count + * decrements to zero. + * + ****************************************************************************/ + +void nsh_release(FAR void *handle) +{ + FAR struct serial_s *pstate = (FAR struct serial_s *)handle; + if (pstate->ss_refs > 1) + { + pstate->ss_refs--; + } + else + { + free(handle); + } } /**************************************************************************** diff --git a/examples/nsh/nsh_telnetd.c b/examples/nsh/nsh_telnetd.c index 0dbf6b18bb..3f1c1374d7 100644 --- a/examples/nsh/nsh_telnetd.c +++ b/examples/nsh/nsh_telnetd.c @@ -401,7 +401,7 @@ static void *nsh_connection(void *arg) ****************************************************************************/ /**************************************************************************** - * Name: nsh_telnetmain + * Name: nsh_main * * Description: * This is the main processing thread for telnetd. It never returns @@ -409,7 +409,7 @@ static void *nsh_connection(void *arg) * ****************************************************************************/ -int nsh_telnetmain(void) +int nsh_main(void) { struct in_addr addr; #if defined(CONFIG_EXAMPLES_NSH_DHCPC) || defined(CONFIG_EXAMPLES_NSH_NOMAC) @@ -492,7 +492,7 @@ int nsh_telnetmain(void) } /**************************************************************************** - * Name: nsh_telnetout + * Name: nsh_output * * Description: * Print a string to the remote shell window. @@ -503,7 +503,7 @@ int nsh_telnetmain(void) * ****************************************************************************/ -int nsh_telnetout(FAR void *handle, const char *fmt, ...) +int nsh_output(FAR void *handle, const char *fmt, ...) { struct telnetd_s *pstate = (struct telnetd_s *)handle; int nbytes = pstate->tn_sndlen; @@ -558,7 +558,7 @@ int nsh_telnetout(FAR void *handle, const char *fmt, ...) * ****************************************************************************/ -extern char *nsh_linebuffer(FAR void *handle) +FAR char *nsh_linebuffer(FAR void *handle) { struct telnetd_s *pstate = (struct telnetd_s *)handle; return pstate->tn_cmd;