diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2013-01-17 18:32:13 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2013-01-17 18:32:13 +0000 |
commit | 68453d683cb221e509258d71bddf207a330a1656 (patch) | |
tree | 677aa6a3af5241be04684f2d02eb0e719234b68c | |
parent | d8d9cc8a96cdc2219af7bec8142e7633779fd685 (diff) | |
download | px4-nuttx-68453d683cb221e509258d71bddf207a330a1656.tar.gz px4-nuttx-68453d683cb221e509258d71bddf207a330a1656.tar.bz2 px4-nuttx-68453d683cb221e509258d71bddf207a330a1656.zip |
NSH will now run files from the file system; Add logic to unload and clean-up after running a task from a file system; Extensions to builtin apps from Mike Smith
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5529 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r-- | apps/ChangeLog.txt | 3 | ||||
-rw-r--r-- | apps/builtin/builtin_list.c | 79 | ||||
-rw-r--r-- | apps/examples/nsh/nsh_main.c | 38 | ||||
-rw-r--r-- | apps/nshlib/Kconfig | 11 | ||||
-rw-r--r-- | apps/nshlib/Makefile | 4 | ||||
-rw-r--r-- | apps/nshlib/nsh.h | 5 | ||||
-rw-r--r-- | apps/nshlib/nsh_builtin.c | 27 | ||||
-rw-r--r-- | apps/nshlib/nsh_fileapps.c | 298 | ||||
-rw-r--r-- | apps/nshlib/nsh_parse.c | 37 | ||||
-rw-r--r-- | nuttx/ChangeLog | 4 | ||||
-rw-r--r-- | nuttx/arch/arm/include/stm32/chip.h | 38 | ||||
-rw-r--r-- | nuttx/binfmt/binfmt_exec.c | 10 | ||||
-rw-r--r-- | nuttx/binfmt/binfmt_loadmodule.c | 4 | ||||
-rw-r--r-- | nuttx/binfmt/binfmt_schedunload.c | 333 | ||||
-rw-r--r-- | nuttx/binfmt/builtin.c | 4 | ||||
-rw-r--r-- | nuttx/binfmt/libbuiltin/libbuiltin_getname.c | 8 | ||||
-rw-r--r-- | nuttx/binfmt/libbuiltin/libbuiltin_isavail.c | 6 | ||||
-rw-r--r-- | nuttx/configs/sim/nsh/defconfig | 12 | ||||
-rw-r--r-- | nuttx/include/nuttx/binfmt/binfmt.h | 2 | ||||
-rw-r--r-- | nuttx/include/nuttx/binfmt/builtin.h | 30 | ||||
-rw-r--r-- | nuttx/libc/spawn/lib_ps.c | 2 | ||||
-rw-r--r-- | nuttx/tools/mkconfig.c | 2 |
22 files changed, 927 insertions, 30 deletions
diff --git a/apps/ChangeLog.txt b/apps/ChangeLog.txt index 14eb78950..ba8dec613 100644 --- a/apps/ChangeLog.txt +++ b/apps/ChangeLog.txt @@ -485,3 +485,6 @@ argument is now optional. Many files systems do not need a source and it is really stupid to have to enter a bogus source parameter. + * apps/nshlib/nsh_fileapp.c: Add the ability to execute a file + from a file system using posix_spawn(). + * apps/builtin/: Extensions from Mike Smith. diff --git a/apps/builtin/builtin_list.c b/apps/builtin/builtin_list.c new file mode 100644 index 000000000..a5556bf54 --- /dev/null +++ b/apps/builtin/builtin_list.c @@ -0,0 +1,79 @@ +/**************************************************************************** + * apps/builtin/builtin_list.c + * + * Copyright (C) 2011 Uros Platise. All rights reserved. + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Authors: Uros Platise <uros.platise@isotel.eu> + * Gregory Nutt <gnutt@nuttx.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <nuttx/binfmt/builtin.h> + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#include "builtin_proto.h" + +const struct builtin_s g_builtins[] = +{ +# include "builtin_list.h" + { NULL, 0, 0, 0 } +}; + +const int g_builtin_count = sizeof(g_builtins) / sizeof(g_builtins[0]); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + diff --git a/apps/examples/nsh/nsh_main.c b/apps/examples/nsh/nsh_main.c index 97792cb2a..d9bfc2018 100644 --- a/apps/examples/nsh/nsh_main.c +++ b/apps/examples/nsh/nsh_main.c @@ -46,6 +46,12 @@ #include <errno.h> #include <nuttx/arch.h> +#if defined(CONFIG_FS_BINFS) && (CONFIG_BUILTIN) +#include <nuttx/binfmt/builtin.h> +#endif +#if defined(CONFIG_LIBC_EXECFUNCS) && defined(CONFIG_EXECFUNCS_SYMTAB) +#include <nuttx/binfmt/symtab.h> +#endif #include <apps/nsh.h> @@ -75,6 +81,21 @@ * Public Data ****************************************************************************/ +/* If posix_spawn() is enabled as required for CONFIG_NSH_FILE_APPS, then + * a symbol table is needed by the internals of posix_spawn(). The symbol + * table is needed to support ELF and NXFLAT binaries to dynamically link to + * the base code. However, if only the BINFS file system is supported, then + * no Makefile is needed. + * + * This is a kludge to plug the missing file system in the case where BINFS + * is used. REVISIT: This will, of course, be in the way if you want to + * support ELF or NXFLAT binaries! + */ + +#if defined(CONFIG_LIBC_EXECFUNCS) && defined(CONFIG_EXECFUNCS_SYMTAB) +const struct symtab_s CONFIG_EXECFUNCS_SYMTAB[1]; +#endif + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -98,6 +119,23 @@ int nsh_main(int argc, char *argv[]) up_cxxinitialize(); #endif + /* Make sure that we are using our symbol take */ + +#if defined(CONFIG_LIBC_EXECFUNCS) && defined(CONFIG_EXECFUNCS_SYMTAB) + exec_setsymtab(CONFIG_EXECFUNCS_SYMTAB, 0); +#endif + + /* Register the BINFS file system */ + +#if defined(CONFIG_FS_BINFS) && (CONFIG_BUILTIN) + ret = builtin_initialize(); + if (ret < 0) + { + fprintf(stderr, "ERROR: builtin_initialize failed: %d\n", ret); + exitval = 1; + } +#endif + /* Initialize the NSH library */ nsh_initialize(); diff --git a/apps/nshlib/Kconfig b/apps/nshlib/Kconfig index e60e9c480..f6a5aa045 100644 --- a/apps/nshlib/Kconfig +++ b/apps/nshlib/Kconfig @@ -14,7 +14,7 @@ config NSH_LIBRARY if NSH_LIBRARY config NSH_BUILTIN_APPS bool "Enable built-in applications" - default y + default n depends on BUILTIN ---help--- Support external registered, "built-in" applications that can be @@ -22,6 +22,15 @@ config NSH_BUILTIN_APPS more information). This options requires support for builtin applications (BUILTIN). +config NSH_FILE_APPS + bool "Enable execution of program files" + default n + depends on LIBC_EXECFUNCS + ---help--- + Support execution of program files residing within a file + system. This options requires support for the posix_spawn() + interface (LIBC_EXECFUNCS). + menu "Disable Individual commands" config NSH_DISABLE_BASE64DEC diff --git a/apps/nshlib/Makefile b/apps/nshlib/Makefile index 5c5269685..948f43d52 100644 --- a/apps/nshlib/Makefile +++ b/apps/nshlib/Makefile @@ -47,6 +47,10 @@ ifeq ($(CONFIG_NSH_BUILTIN_APPS),y) CSRCS += nsh_builtin.c endif +ifeq ($(CONFIG_NSH_FILE_APPS),y) +CSRCS += nsh_fileapps.c +endif + ifeq ($(CONFIG_NSH_ROMFSETC),y) CSRCS += nsh_romfsetc.c endif diff --git a/apps/nshlib/nsh.h b/apps/nshlib/nsh.h index 253a803f8..64099a8df 100644 --- a/apps/nshlib/nsh.h +++ b/apps/nshlib/nsh.h @@ -495,6 +495,11 @@ int nsh_builtin(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, FAR char **argv, FAR const char *redirfile, int oflags); #endif +#ifdef CONFIG_NSH_FILE_APPS +int nsh_fileapp(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, + FAR char **argv, FAR const char *redirfile, int oflags); +#endif + /* Working directory support */ #if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON) diff --git a/apps/nshlib/nsh_builtin.c b/apps/nshlib/nsh_builtin.c index ba39e8dfe..2d23ca8d8 100644 --- a/apps/nshlib/nsh_builtin.c +++ b/apps/nshlib/nsh_builtin.c @@ -51,6 +51,7 @@ #endif #include <stdbool.h> +#include <signal.h> #include <errno.h> #include <string.h> @@ -129,20 +130,34 @@ int nsh_builtin(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, ret = exec_builtin(cmd, (FAR const char **)argv, redirfile, oflags); if (ret >= 0) { - /* 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. These really - * only works works with the following options: + /* The application was successfully started with pre-emption disabled. + * In the simplest cases, the application will not have run because the + * the scheduler is locked. but in the case were I/O redirected, a + * proxy task ran and, as result, so may have the application. + * + * If the application did not run and if the application was not + * backgrounded, then we need to wait here for the application to + * exit. This only works works with the following options: * * - CONFIG_NSH_DISABLEBG - Do not run commands in background * - CONFIG_SCHED_WAITPID - Required to run external commands in * foreground - * - * These concepts do not apply cleanly to the external applications. */ #ifdef CONFIG_SCHED_WAITPID + /* Check if the application is still running */ + + if (kill(ret, 0) < 0) + { + /* It is not running. In this case, we have no idea if the + * application ran successfully or not. Let's assume that is + * did. + */ + + return 0; + } + /* CONFIG_SCHED_WAITPID is selected, so we may run the command in * foreground unless we were specifically requested to run the command * in background (and running commands in background is enabled). diff --git a/apps/nshlib/nsh_fileapps.c b/apps/nshlib/nsh_fileapps.c new file mode 100644 index 000000000..7f9f58e53 --- /dev/null +++ b/apps/nshlib/nsh_fileapps.c @@ -0,0 +1,298 @@ +/**************************************************************************** + * apps/nshlib/nsh_fileapps.c + * + * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#ifdef CONFIG_SCHED_WAITPID +# include <sys/wait.h> +#endif + +#include <stdbool.h> +#include <signal.h> +#include <spawn.h> +#include <errno.h> +#include <string.h> + +#include "nsh.h" +#include "nsh_console.h" + +#ifdef CONFIG_NSH_FILE_APPS + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_fileapp + * + * Description: + * Attempt to execute the application task whose name is 'cmd' + * + * Returned Value: + * <0 If exec_builtin() 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 + * defined, this return value also indicates that the + * application returned successful status (EXIT_SUCCESS) + * 1 If CONFIG_SCHED_WAITPID is defined, then this return value + * indicates that the application task was spawned successfully + * but returned failure exit status. + * + ****************************************************************************/ + +int nsh_fileapp(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, + FAR char **argv, FAR const char *redirfile, int oflags) +{ + posix_spawn_file_actions_t file_actions; + posix_spawnattr_t attr; + pid_t pid; + int ret; + + /* Initialize the attributes file actions structure */ + + ret = posix_spawn_file_actions_init(&file_actions); + if (ret != 0) + { + /* posix_spawn_file_actions_init returns a positive errno value on + * failure. + */ + + nsh_output(vtbl, g_fmtcmdfailed, cmd, "posix_spawn_file_actions_init", + NSH_ERRNO_OF(ret)); + goto errout; + } + + ret = posix_spawnattr_init(&attr); + if (ret != 0) + { + /* posix_spawnattr_init returns a positive errno value on failure. */ + + nsh_output(vtbl, g_fmtcmdfailed, cmd, "posix_spawnattr_init", + NSH_ERRNO); + goto errout_with_actions; + } + + /* Handle re-direction of output */ + + if (redirfile) + { + ret = posix_spawn_file_actions_addopen(&file_actions, 1, redirfile, + oflags, 0644); + if (ret != 0) + { + /* posix_spawn_file_actions_addopen returns a positive errno + * value on failure. + */ + + nsh_output(vtbl, g_fmtcmdfailed, cmd, + "posix_spawn_file_actions_addopen", + NSH_ERRNO); + goto errout_with_attrs; + } + } + + /* Lock the scheduler to prevent the application from running until the + * waitpid() has been called. + */ + + sched_lock(); + + /* Execute the program. posix_spawnp returns a positive errno value on + * failure. + */ + + ret = posix_spawnp(&pid, cmd, &file_actions, &attr, &argv[1], NULL); + if (ret == OK) + { + /* The application was successfully started with pre-emption disabled. + * In the simplest cases, the application will not have run because the + * the scheduler is locked. but in the case were I/O redirected, a + * proxy task ran and, as result, so may have the application. + * + * If the application did not run and if the application was not + * backgrounded, then we need to wait here for the application to + * exit. This only works works with the following options: + * + * - CONFIG_NSH_DISABLEBG - Do not run commands in background + * - CONFIG_SCHED_WAITPID - Required to run external commands in + * foreground + */ + +#ifdef CONFIG_SCHED_WAITPID + /* Check if the application is still running */ + + if (kill(ret, 0) < 0) + { + /* It is not running. In this case, we have no idea if the + * application ran successfully or not. Let's assume that is + * did. + */ + + return 0; + } + + /* CONFIG_SCHED_WAITPID is selected, so we may run the command in + * foreground unless we were specifically requested to run the command + * in background (and running commands in background is enabled). + */ + +# ifndef CONFIG_NSH_DISABLEBG + if (vtbl->np.np_bg == false) +# endif /* CONFIG_NSH_DISABLEBG */ + { + 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(pid, &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. + */ + } + } +# ifndef CONFIG_NSH_DISABLEBG + else +# endif /* CONFIG_NSH_DISABLEBG */ +#endif /* CONFIG_SCHED_WAITPID */ + + /* We get here if either: + * + * - CONFIG_SCHED_WAITPID is not selected meaning that all commands + * have to be run in background, or + * - CONFIG_SCHED_WAITPID and CONFIG_NSH_DISABLEBG are both selected, but the + * user requested to run the command in background. + * + * NOTE that the case of a) CONFIG_SCHED_WAITPID is not selected and + * b) CONFIG_NSH_DISABLEBG selected cannot be supported. In that event, all + * commands will have to run in background. The waitpid() API must be + * available to support running the command in foreground. + */ + +#if !defined(CONFIG_SCHED_WAITPID) || !defined(CONFIG_NSH_DISABLEBG) + { + struct sched_param param; + sched_getparam(ret, ¶m); + nsh_output(vtbl, "%s [%d:%d]\n", cmd, ret, param.sched_priority); + + /* Backgrounded commands always 'succeed' as long as we can start + * them. + */ + + ret = OK; + } +#endif /* !CONFIG_SCHED_WAITPID || !CONFIG_NSH_DISABLEBG */ + } + + sched_unlock(); + + /* Free attibutes and file actions. Ignoring return values in the case + * of an error. + */ + +errout_with_actions: + (void)posix_spawn_file_actions_destroy(&file_actions); + +errout_with_attrs: + (void)posix_spawnattr_destroy(&attr); + +errout: + /* Most posix_spawn interfaces return a positive errno value on failure + * and do not set the errno variable. + */ + + if (ret > 0) + { + /* Set the errno value and return -1 */ + + set_errno(ret); + ret = ERROR; + } + else if (ret < 0) + { + /* Return -1 on failure. errno should have been set. */ + + ret = ERROR; + } + + return ret; +} + +#endif /* CONFIG_NSH_FILE_APPS */ diff --git a/apps/nshlib/nsh_parse.c b/apps/nshlib/nsh_parse.c index ef4125a63..f679d9b32 100644 --- a/apps/nshlib/nsh_parse.c +++ b/apps/nshlib/nsh_parse.c @@ -61,6 +61,7 @@ #ifdef CONFIG_NSH_BUILTIN_APPS # include <nuttx/binfmt/builtin.h> #endif + #include <apps/nsh.h> #include "nsh.h" @@ -1398,6 +1399,40 @@ int nsh_parse(FAR struct nsh_vtbl_s *vtbl, char *cmdline) nsh_output(vtbl, g_fmttoomanyargs, cmd); } + /* Does this command correspond to an application filename? + * nsh_fileapp() returns: + * + * -1 (ERROR) if the application task corresponding to 'argv[0]' could not + * be started (possibly because it doesn not exist). + * 0 (OK) if the application task corresponding to 'argv[0]' was + * and successfully started. If CONFIG_SCHED_WAITPID is + * defined, this return value also indicates that the + * application returned successful status (EXIT_SUCCESS) + * 1 If CONFIG_SCHED_WAITPID is defined, then this return value + * indicates that the application task was spawned successfully + * but returned failure exit status. + * + * Note the priority if not effected by nice-ness. + */ + +#ifdef CONFIG_NSH_FILE_APPS + ret = nsh_fileapp(vtbl, argv[0], argv, redirfile, oflags); + if (ret >= 0) + { + /* nsh_fileapp() returned 0 or 1. This means that the builtin + * command was successfully started (although it may not have ran + * successfully). So certainly it is not an NSH command. + */ + + return nsh_saveresult(vtbl, ret != OK); + } + + /* No, not a built in command (or, at least, we were unable to start a + * builtin command of that name). Treat it like an NSH command. + */ + +#endif + /* Does this command correspond to a builtin command? * nsh_builtin() returns: * @@ -1414,7 +1449,7 @@ int nsh_parse(FAR struct nsh_vtbl_s *vtbl, char *cmdline) * Note the priority if not effected by nice-ness. */ -#ifdef CONFIG_NSH_BUILTIN_APPS +#if defined(CONFIG_NSH_BUILTIN_APPS) && (!defined(CONFIG_NSH_FILE_APPS) || !defined(CONFIG_FS_BINFS)) ret = nsh_builtin(vtbl, argv[0], argv, redirfile, oflags); if (ret >= 0) { diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index 6bc66ec9d..1b0c5338b 100644 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -3967,4 +3967,8 @@ file system. * configs/sim/nsh: Convert to use kconfig-frontends configuration tool. + * binfmt/binfmt_schedunload.c: Add logic based on SIGCHLD to + automatically unload and clean-up after running a task that + was loaded into memory. + * binfmt/libbuiltin: Extensions from Mike Smith diff --git a/nuttx/arch/arm/include/stm32/chip.h b/nuttx/arch/arm/include/stm32/chip.h index d34c2eb4f..b7ec7dbba 100644 --- a/nuttx/arch/arm/include/stm32/chip.h +++ b/nuttx/arch/arm/include/stm32/chip.h @@ -183,9 +183,43 @@ # define STM32_NRNG 0 /* No random number generator (RNG) */ # define STM32_NDCMI 0 /* No digital camera interface (DCMI) */ +/* STM32 F103 Medium Density Family *************************************************/ +/* STM32F103RB is in the Medium-density performance line and is provided in 64 pin + * packages with 128K Flash, USB, CAN, 7 timers, 2 ADCs, 9 com. interfaces + */ + +#elif defined(CONFIG_ARCH_CHIP_STM32F103RBT6) +# define CONFIG_STM32_STM32F10XX 1 /* STM32F10xxx family */ +# undef CONFIG_STM32_LOWDENSITY /* STM32F100x, STM32F101x, STM32F102x and STM32F103x w/ 16/32 Kbytes */ +# define CONFIG_STM32_MEDIUMDENSITY 1 /* STM32F100x, STM32F101x, STM32F102x and STM32F103x w/ 64/128 Kbytes */ +# undef CONFIG_STM32_HIGHDENSITY /* STM32F100x, STM32F101x, and STM32F103x w/ 256/512 Kbytes */ +# undef CONFIG_STM32_VALUELINE /* STM32F100x */ +# undef CONFIG_STM32_CONNECTIVITYLINE /* STM32F105x and STM32F107x */ +# undef CONFIG_STM32_STM32F20XX /* STM32F205x and STM32F207x */ +# undef CONFIG_STM32_STM32F40XX /* STM32F405xx and STM32407xx families */ +# define STM32_NFSMC 0 /* FSMC */ +# define STM32_NATIM 1 /* One advanced timer TIM1 */ +# define STM32_NGTIM 3 /* General timers TIM2,3,4 */ +# define STM32_NBTIM 0 /* Two basic timers TIM6 and TIM7 */ +# define STM32_NDMA 1 /* DMA1 */ +# define STM32_NSPI 2 /* SPI1-2 */ +# define STM32_NI2S 0 /* No I2S (?) */ +# define STM32_NUSART 3 /* USART1-3 */ +# define STM32_NI2C 2 /* I2C1-2 */ +# define STM32_NCAN 1 /* bxCAN1 */ +# define STM32_NSDIO 0 /* No SDIO */ +# define STM32_NUSBOTG 0 /* No USB OTG FS/HS */ +# define STM32_NGPIO 51 /* GPIOA-E */ +# define STM32_NADC 2 /* ADC1-2 */ +# define STM32_NDAC 0 /* No DAC */ +# define STM32_NCRC 1 /* CRC */ +# define STM32_NTHERNET 0 /* No ethernet */ +# define STM32_NRNG 0 /* No random number generator (RNG) */ +# define STM32_NDCMI 0 /* No digital camera interface (DCMI) */ + /* STM32 F103 High Density Family ***************************************************/ -/* STM32F103RC, STM32F103RD, and STM32F103RE are all provided in 64 pin packages and differ - * only in the available FLASH and SRAM. +/* STM32F103RC, STM32F103RD, and STM32F103RE are all provided in 64 pin packages and + * differ only in the available FLASH and SRAM. */ #elif defined(CONFIG_ARCH_CHIP_STM32F103RET6) diff --git a/nuttx/binfmt/binfmt_exec.c b/nuttx/binfmt/binfmt_exec.c index 1cead4384..7f45fb841 100644 --- a/nuttx/binfmt/binfmt_exec.c +++ b/nuttx/binfmt/binfmt_exec.c @@ -43,6 +43,7 @@ #include <debug.h> #include <errno.h> +#include <nuttx/kmalloc.h> #include <nuttx/binfmt/binfmt.h> #include "binfmt_internal.h" @@ -97,6 +98,7 @@ int exec(FAR const char *filename, FAR const char **argv, #ifdef CONFIG_SCHED_ONEXIT FAR struct binary_s *bin; int errorcode; + int pid; int ret; /* Allocate the load information */ @@ -131,8 +133,8 @@ int exec(FAR const char *filename, FAR const char **argv, /* Then start the module */ - ret = exec_module(bin); - if (ret < 0) + pid = exec_module(bin); + if (pid < 0) { bdbg("ERROR: Failed to execute program '%s'\n", filename); sched_unlock(); @@ -145,14 +147,14 @@ int exec(FAR const char *filename, FAR const char **argv, * when the task exists. */ - ret = schedul_unload(ret, bin); + ret = schedule_unload(pid, bin); if (ret < 0) { bdbg("ERROR: Failed to schedul unload '%s'\n", filename); } sched_unlock(); - return ret; + return pid; #else struct binary_s bin; int ret; diff --git a/nuttx/binfmt/binfmt_loadmodule.c b/nuttx/binfmt/binfmt_loadmodule.c index 4f3dc6952..322ed2c48 100644 --- a/nuttx/binfmt/binfmt_loadmodule.c +++ b/nuttx/binfmt/binfmt_loadmodule.c @@ -84,6 +84,7 @@ static int load_default_priority(FAR struct binary_s *bin) { struct sched_param param; + int ret; /* Get the priority of this thread */ @@ -97,6 +98,7 @@ static int load_default_priority(FAR struct binary_s *bin) /* Save that as the priority of child thread */ bin->priority = param.sched_priority; + return ret; } /**************************************************************************** @@ -180,7 +182,7 @@ int load_module(FAR struct binary_s *bin) { /* Set the default priority of the new program. */ - ret = load_default_priority(bin) + ret = load_default_priority(bin); if (ret < 0) { /* The errno is already set in this case */ diff --git a/nuttx/binfmt/binfmt_schedunload.c b/nuttx/binfmt/binfmt_schedunload.c new file mode 100644 index 000000000..972d17963 --- /dev/null +++ b/nuttx/binfmt/binfmt_schedunload.c @@ -0,0 +1,333 @@ +/**************************************************************************** + * binfmt/binfmt_schedunload.c + * + * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sched.h> +#include <debug.h> +#include <errno.h> + +#include <nuttx/kmalloc.h> +#include <nuttx/binfmt/binfmt.h> + +#include "binfmt_internal.h" + +#if !defined(CONFIG_BINFMT_DISABLE) && defined(CONFIG_SCHED_HAVE_PARENT) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +FAR struct binary_s *g_unloadhead; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: unload_list_add + * + * Description: + * If CONFIG_SCHED_HAVE_PARENT is defined then schedul_unload() will + * manage instances of struct binary_s allocated with kmalloc. It + * will keep the binary data in a link list and when SIGCHLD is received + * (meaning that the task has exit'ed, schedul_unload() will find the + * data, unload the module, and free the structure. + * + * This function will add one structure to the linked list + * + * Input Parameter: + * pid - The task ID of the child task + * bin - This structure must have been allocated with kmalloc() and must + * persist until the task unloads + + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void unload_list_add(pid_t pid, FAR struct binary_s *bin) +{ + irqstate_t flags; + + /* Save the PID in the structure so that we recover it later */ + + bin->pid = pid; + + /* Disable deliver of any signals while we muck with the list. The graceful + * way to do this would be block delivery of SIGCHLD would be with + * sigprocmask. Here we do it the quick'n'dirty way by just disabling + * interrupts. + */ + + flags = irqsave(); + bin->flink = g_unloadhead; + g_unloadhead = bin; + irqrestore(flags); +} + +/**************************************************************************** + * Name: unload_list_remove + * + * Description: + * If CONFIG_SCHED_HAVE_PARENT is defined then schedul_unload() will + * manage instances of struct binary_s allocated with kmalloc. It + * will keep the binary data in a link list and when SIGCHLD is received + * (meaning that the task has exit'ed, schedul_unload() will find the + * data, unload the module, and free the structure. + * + * This function will remove one structure to the linked list + * + * Input Parameter: + * pid - The task ID of the child task + * + * Returned Value: + * On success, the load structure is returned. NULL is returned on + * failure. + * + ****************************************************************************/ + +static FAR struct binary_s *unload_list_remove(pid_t pid) +{ + FAR struct binary_s *curr; + FAR struct binary_s *prev; + + /* Note the asymmetry. We do not have to disable interrupts here because + * the main thread cannot run while we are in the interrupt handler. Here, + * it should be sufficient to disable pre-emption so that no other thread + * can run. + */ + + sched_lock(); + + /* Find the structure in the unload list with the matching PID */ + + for (prev = NULL, curr = g_unloadhead; + curr && (curr->pid != pid); + prev = curr, curr = curr->flink); + + /* Did we find it? It must be there. Hmmm.. we should probably ASSERT if + * we do not! + */ + + if (curr) + { + /* Was there another entry before this one? */ + + if (prev) + { + /* Yes.. remove the current entry from after the previous entry */ + + prev->flink = curr->flink; + } + else + { + /* No.. remove the current entry from the head of the list */ + + g_unloadhead = curr->flink; + } + + /* Nullify the forward link ... superstitious */ + + curr->flink = NULL; + } + + sched_unlock(); + return curr; +} + +/**************************************************************************** + * Name: unload_callback + * + * Description: + * If CONFIG_SCHED_HAVE_PARENT is defined, this function may be called to + * automatically unload the module when task exits. It assumes that + * bin was allocated with kmalloc() or friends and will also automatically + * free the structure with kfree() when the task exists. + * + * Input Parameter: + * pid - The ID of the task that just exited + * arg - A reference to the load structure cast to FAR void * + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void unload_callback(int signo, siginfo_t *info, void *ucontext) +{ + FAR struct binary_s *bin; + int ret; + + /* Sanity checking */ + + if (!info || signo != SIGCHLD) + { + blldbg("ERROR:Bad signal callback: signo=%d info=%p\n", signo, callback); + return; + } + + /* Get the load information for this pid */ + + bin = unload_list_remove(info->si_pid); + if (!bin) + { + blldbg("ERROR: Could not find load info for PID=%d\n", info->si_pid); + return; + } + + /* Unload the module */ + + ret = unload_module(bin); + if (ret < 0) + { + blldbg("ERROR: unload_module failed: %d\n", get_errno()); + } + + /* Free the load structure */ + + kfree(bin); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: schedule_unload + * + * Description: + * If CONFIG_SCHED_HAVE_PARENT is defined, this function may be called by + * the parent of the the newly created task to automatically unload the + * module when the task exits. This assumes that (1) the caller is the + * parent of the created task, (2) that bin was allocated with kmalloc() + * or friends. It will also automatically free the structure with kfree() + * after unloading the module. + * + * Input Parameter: + * pid - The task ID of the child task + * bin - This structure must have been allocated with kmalloc() and must + * persist until the task unloads + * + * Returned Value: + * This is an end-user function, so it follows the normal convention: + * It returns 0 (OK) if the callback was successfully scheduled. On + * failure, it returns -1 (ERROR) and sets errno appropriately. + * + * On failures, the 'bin' structure will not be deallocated and the + * module not not be unloaded. + * + ****************************************************************************/ + +int schedule_unload(pid_t pid, FAR struct binary_s *bin) +{ + struct sigaction act; + struct sigaction oact; + sigset_t sigset; + irqstate_t flags; + int errorcode; + int ret; + + /* Make sure that SIGCHLD is unmasked */ + + (void)sigemptyset(&sigset); + (void)sigaddset(&sigset, SIGCHLD); + ret = sigprocmask(SIG_UNBLOCK, &sigset, NULL); + if (ret != OK) + { + /* The errno value will get trashed by the following debug output */ + + errorcode = get_errno(); + bvdbg("ERROR: sigprocmask failed: %d\n", ret); + goto errout; + } + + /* Add the structure to the list. We want to do this *before* connecting + * the signal handler. This does, however, make error recovery more + * complex if sigaction() fails below because then we have to remove the + * unload structure for the list in an unexpected context. + */ + + unload_list_add(pid, bin); + + /* Register the SIGCHLD handler */ + + act.sa_sigaction = unload_callback; + act.sa_flags = SA_SIGINFO; + + (void)sigfillset(&act.sa_mask); + (void)sigdelset(&act.sa_mask, SIGCHLD); + + ret = sigaction(SIGCHLD, &act, &oact); + if (ret != OK) + { + /* The errno value will get trashed by the following debug output */ + + errorcode = get_errno(); + bvdbg("ERROR: sigaction failed: %d\n" , ret); + + /* Emergency removal from the list */ + + flags = irqsave(); + if (unload_list_remove(pid) != bin) + { + blldbg("ERROR: Failed to remove structure\n"); + } + + goto errout; + } + + return OK; + +errout: + set_errno(errorcode); + return ERROR; +} + +#endif /* !CONFIG_BINFMT_DISABLE && CONFIG_SCHED_HAVE_PARENT */ + diff --git a/nuttx/binfmt/builtin.c b/nuttx/binfmt/builtin.c index d80d9f5d8..e492f72e5 100644 --- a/nuttx/binfmt/builtin.c +++ b/nuttx/binfmt/builtin.c @@ -98,11 +98,11 @@ static int builtin_loadbinary(struct binary_s *binp) /* Open the binary file for reading (only) */ - fd = open(filename, O_RDONLY); + fd = open(binp->filename, O_RDONLY); if (fd < 0) { int errval = errno; - bdbg("ERROR: Failed to open binary %s: %d\n", filename, errval); + bdbg("ERROR: Failed to open binary %s: %d\n", binp->filename, errval); return -errval; } diff --git a/nuttx/binfmt/libbuiltin/libbuiltin_getname.c b/nuttx/binfmt/libbuiltin/libbuiltin_getname.c index 9da2bac29..d1e3958b3 100644 --- a/nuttx/binfmt/libbuiltin/libbuiltin_getname.c +++ b/nuttx/binfmt/libbuiltin/libbuiltin_getname.c @@ -83,13 +83,13 @@ FAR const char *builtin_getname(int index) { - struct builtin_s *b; + FAR const struct builtin_s *builtin; - b = builtin_for_index(index); + builtin = builtin_for_index(index); - if (b != NULL) + if (builtin != NULL) { - return b->name; + return builtin->name; } return NULL; diff --git a/nuttx/binfmt/libbuiltin/libbuiltin_isavail.c b/nuttx/binfmt/libbuiltin/libbuiltin_isavail.c index b1d55ff21..7a480c0f3 100644 --- a/nuttx/binfmt/libbuiltin/libbuiltin_isavail.c +++ b/nuttx/binfmt/libbuiltin/libbuiltin_isavail.c @@ -87,12 +87,12 @@ int builtin_isavail(FAR const char *appname) { - FAR const char *n; + FAR const char *name; int i; - for (i = 0; n = builtin_getname(i); i++) + for (i = 0; (name = builtin_getname(i)); i++) { - if (!strncmp(n, appname, NAME_MAX)) + if (!strncmp(name, appname, NAME_MAX)) { return i; } diff --git a/nuttx/configs/sim/nsh/defconfig b/nuttx/configs/sim/nsh/defconfig index c5eadb122..7b72ac303 100644 --- a/nuttx/configs/sim/nsh/defconfig +++ b/nuttx/configs/sim/nsh/defconfig @@ -130,7 +130,8 @@ CONFIG_SDCLONE_DISABLE=y # CONFIG_SCHED_WORKQUEUE is not set CONFIG_SCHED_WAITPID=y # CONFIG_SCHED_ATEXIT is not set -# CONFIG_SCHED_ONEXIT is not set +CONFIG_SCHED_ONEXIT=y +CONFIG_SCHED_ONEXIT_MAX=1 CONFIG_USER_ENTRYPOINT="nsh_main" CONFIG_DISABLE_OS_API=y # CONFIG_DISABLE_CLOCK is not set @@ -259,7 +260,8 @@ CONFIG_MM_REGIONS=1 # Binary Formats # # CONFIG_BINFMT_DISABLE is not set -# CONFIG_BINFMT_EXEPATH is not set +CONFIG_BINFMT_EXEPATH=y +CONFIG_PATH_INITIAL="/bin" # CONFIG_NXFLAT is not set # CONFIG_ELF is not set CONFIG_BUILTIN=y @@ -284,7 +286,10 @@ CONFIG_LIB_HOMEDIR="/" # CONFIG_EOL_IS_LF is not set # CONFIG_EOL_IS_BOTH_CRLF is not set CONFIG_EOL_IS_EITHER_CRLF=y -# CONFIG_LIBC_EXECFUNCS is not set +CONFIG_LIBC_EXECFUNCS=y +CONFIG_EXECFUNCS_SYMTAB="g_symtab" +CONFIG_EXECFUNCS_NSYMBOLS=0 +CONFIG_POSIX_SPAWN_STACKSIZE=1024 # CONFIG_LIBC_STRERROR is not set # CONFIG_LIBC_PERROR_STDOUT is not set CONFIG_ARCH_LOWPUTC=y @@ -410,6 +415,7 @@ CONFIG_EXAMPLES_NSH=y # CONFIG_NSH_LIBRARY=y CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILE_APPS=y # # Disable Individual commands diff --git a/nuttx/include/nuttx/binfmt/binfmt.h b/nuttx/include/nuttx/binfmt/binfmt.h index 472ba0fc4..590d88402 100644 --- a/nuttx/include/nuttx/binfmt/binfmt.h +++ b/nuttx/include/nuttx/binfmt/binfmt.h @@ -265,7 +265,7 @@ int exec_module(FAR const struct binary_s *bin); ****************************************************************************/ #ifdef CONFIG_SCHED_HAVE_PARENT -int schedule_unload(pid_t pid, FAR const struct binary_s *bin); +int schedule_unload(pid_t pid, FAR struct binary_s *bin); #endif /**************************************************************************** diff --git a/nuttx/include/nuttx/binfmt/builtin.h b/nuttx/include/nuttx/binfmt/builtin.h index 5921cc518..6ff565395 100644 --- a/nuttx/include/nuttx/binfmt/builtin.h +++ b/nuttx/include/nuttx/binfmt/builtin.h @@ -78,6 +78,36 @@ extern "C" { ****************************************************************************/ /**************************************************************************** + * Name: builtin_initialize + * + * Description: + * Builtin support is built unconditionally. However, it order to + * use this binary format, this function must be called during system + * format in order to register the builtin binary format. + * + * Returned Value: + * This is a NuttX internal function so it follows the convention that + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int builtin_initialize(void); + +/**************************************************************************** + * Name: builtin_uninitialize + * + * Description: + * Unregister the builtin binary loader + * + * Returned Value: + * None + * + ****************************************************************************/ + +void builtin_uninitialize(void); + +/**************************************************************************** * Utility Functions Provided to Applications by binfmt/libbuiltin ****************************************************************************/ /**************************************************************************** diff --git a/nuttx/libc/spawn/lib_ps.c b/nuttx/libc/spawn/lib_ps.c index 638b27f87..000f711a3 100644 --- a/nuttx/libc/spawn/lib_ps.c +++ b/nuttx/libc/spawn/lib_ps.c @@ -247,7 +247,7 @@ static int ps_exec(FAR pid_t *pidp, FAR const char *path, errout: sched_unlock(); - return OK; + return ret; } /**************************************************************************** diff --git a/nuttx/tools/mkconfig.c b/nuttx/tools/mkconfig.c index fe3e00491..d8d09df34 100644 --- a/nuttx/tools/mkconfig.c +++ b/nuttx/tools/mkconfig.c @@ -116,7 +116,7 @@ int main(int argc, char **argv, char **envp) printf(" * configured (at present, NXFLAT is the only supported binary.\n"); printf(" * format).\n"); printf(" */\n\n"); - printf("#if !defined(CONFIG_NXFLAT) && !defined(CONFIG_ELF)\n"); + printf("#if !defined(CONFIG_NXFLAT) && !defined(CONFIG_ELF) && !defined(CONFIG_BUILTIN)\n"); printf("# undef CONFIG_BINFMT_DISABLE\n"); printf("# define CONFIG_BINFMT_DISABLE 1\n"); printf("#endif\n\n"); |