From f29332dabb08e793f12bfaaf49d851052f3d8bb0 Mon Sep 17 00:00:00 2001 From: patacongo Date: Sat, 28 Jul 2012 18:38:13 +0000 Subject: Lock the scheduler when starting NSH builtin applications to eliminate race conditions git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4988 42af7a65-404d-4744-a932-0658087f49c3 --- apps/nshlib/nsh_apps.c | 93 +++++++++++++++++++++++++++++++++---------------- apps/nshlib/nsh_parse.c | 6 ++-- 2 files changed, 67 insertions(+), 32 deletions(-) (limited to 'apps/nshlib') diff --git a/apps/nshlib/nsh_apps.c b/apps/nshlib/nsh_apps.c index eb019f57b..e335c2e2c 100644 --- a/apps/nshlib/nsh_apps.c +++ b/apps/nshlib/nsh_apps.c @@ -90,7 +90,9 @@ * Attempt to execute the application task whose name is 'cmd' * * Returned Value: - * -1 (ERRROR) if the application task corresponding to 'cmd' could not + * <0 If exec_namedapp() fails, then the negated errno value + * is returned. + * -1 (ERROR) if the application task corresponding to 'cmd' could not * be started (possibly because it doesn not exist). * 0 (OK) if the application task corresponding to 'cmd' was * and successfully started. If CONFIG_SCHED_WAITPID is @@ -107,45 +109,76 @@ int nsh_execapp(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, { int ret = OK; - /* Try to find command within pre-built application list. */ + /* Lock the scheduler to prevent the application from running until the + * waitpid() has been called. + */ + + sched_lock(); + + /* Try to find and execute the command within the list of builtin + * applications. + */ ret = exec_namedapp(cmd, (FAR const char **)argv); - if (ret < 0) + if (ret >= 0) { - return -errno; - } + /* The application was successfully started (but still blocked because the + * scheduler is locked). If the application was not backgrounded, then we + * need to wait here for the application to exit. + */ #ifdef CONFIG_SCHED_WAITPID - if (vtbl->np.np_bg == false) - { - int rc = 0; - - waitpid(ret, &rc, 0); - - /* We can't return the exact status (nsh has nowhere to put it) - * so just pass back zero/nonzero in a fashion that doesn't look - * like an error. - */ + if (vtbl->np.np_bg == false) + { + int rc = 0; + + /* Wait for the application to exit. Since we have locked the + * scheduler above, we know that the application has not yet + * started and there is no possibility that it has already exited. + * The scheduler will be unlocked while waitpid is waiting and the + * application will be able to run. + */ + + ret = waitpid(ret, &rc, 0); + if (ret >= 0) + { + /* We can't return the exact status (nsh has nowhere to put it) + * so just pass back zero/nonzero in a fashion that doesn't look + * like an error. + */ + + ret = (rc == 0) ? OK : 1; + + /* TODO: Set the environment variable '?' to a string corresponding + * to WEXITSTATUS(rc) so that $? will expand to the exit status of + * the most recently executed task. + */ + } + } + else +#endif + { + struct sched_param param; + sched_getparam(0, ¶m); + nsh_output(vtbl, "%s [%d:%d]\n", cmd, ret, param.sched_priority); - ret = (rc == 0) ? OK : 1; + /* Backgrounded commands always 'succeed' as long as we can start + * them. + */ - /* TODO: Set the environment variable '?' to a string corresponding - * to WEXITSTATUS(rc) so that $? will expand to the exit status of - * the most recently executed task. - */ + ret = OK; + } } - else -#endif - { - struct sched_param param; - sched_getparam(0, ¶m); - nsh_output(vtbl, "%s [%d:%d]\n", cmd, ret, param.sched_priority); - /* Backgrounded commands always 'succeed' as long as we can start - * them. - */ + sched_unlock(); - ret = OK; + /* If exec_namedapp() or waitpid() failed, then return the negated errno + * value. + */ + + if (ret < 0) + { + return -errno; } return ret; diff --git a/apps/nshlib/nsh_parse.c b/apps/nshlib/nsh_parse.c index 64850eb62..93171abf7 100644 --- a/apps/nshlib/nsh_parse.c +++ b/apps/nshlib/nsh_parse.c @@ -492,6 +492,8 @@ static int cmd_exit(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) * Exectue the command in argv[0] * * Returned Value: + * <0 If exec_namedapp() fails, then the negated errno value + * is returned. * -1 (ERRROR) if the command was unsuccessful * 0 (OK) if the command was successful * 1 if an application task was spawned successfully, but @@ -521,8 +523,8 @@ static int nsh_execute(FAR struct nsh_vtbl_s *vtbl, int argc, char *argv[]) #ifdef CONFIG_NSH_BUILTIN_APPS ret = nsh_execapp(vtbl, cmd, argv); - /* The pre-built application was successfully started -- return OK - * or 1 if it returned a non-zero exit status. + /* If the built-in application was successfully started, return OK + * or 1 (if the application returned a non-zero exit status). */ if (ret >= 0) -- cgit v1.2.3