Fix reentrancy problems for serial

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@821 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2008-08-14 23:37:12 +00:00
parent 7c18bfddad
commit d72dd985c1
4 changed files with 166 additions and 41 deletions

View File

@ -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 */

View File

@ -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, &param);
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;

View File

@ -43,6 +43,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#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);
}
}
/****************************************************************************

View File

@ -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;