diff --git a/apps/builtin/Makefile b/apps/builtin/Makefile index d77054f41..f89532871 100644 --- a/apps/builtin/Makefile +++ b/apps/builtin/Makefile @@ -39,7 +39,7 @@ include $(APPDIR)/Make.defs # Source and object files ASRCS = -CSRCS = builtin.c exec_builtin.c +CSRCS = builtin.c builtin_list.c exec_builtin.c AOBJS = $(ASRCS:.S=$(OBJEXT)) COBJS = $(CSRCS:.c=$(OBJEXT)) diff --git a/apps/builtin/builtin.c b/apps/builtin/builtin.c index 7655a531d..d26f0a044 100644 --- a/apps/builtin/builtin.c +++ b/apps/builtin/builtin.c @@ -55,27 +55,8 @@ * Public Data ****************************************************************************/ -#undef EXTERN -#if defined(__cplusplus) -#define EXTERN extern "C" -extern "C" { -#else -#define EXTERN extern -#endif - -#include "builtin_proto.h" - -const struct builtin_s g_builtins[] = -{ -# include "builtin_list.h" - { NULL, 0, 0, 0 } -}; - -#undef EXTERN -#if defined(__cplusplus) -} -#endif - +extern const struct builtin_s g_builtins[]; +extern const int g_builtin_count; /**************************************************************************** * Private Data @@ -89,9 +70,11 @@ const struct builtin_s g_builtins[] = * Public Functions ****************************************************************************/ -int number_builtins(void) +FAR const struct builtin_s *builtin_for_index(int index) { - return sizeof(g_builtins)/sizeof(struct builtin_s) - 1; + if (index < g_builtin_count) + { + return &g_builtins[index]; + } + return NULL; } - - diff --git a/apps/builtin/exec_builtin.c b/apps/builtin/exec_builtin.c index 05648590d..d4431164c 100644 --- a/apps/builtin/exec_builtin.c +++ b/apps/builtin/exec_builtin.c @@ -142,8 +142,17 @@ static void bultin_semtake(FAR sem_t *sem) static int builtin_taskcreate(int index, FAR const char **argv) { + FAR const struct builtin_s *b; int ret; + b = builtin_for_index(index); + + if (b == NULL) + { + errno = ENOENT; + return ERROR; + } + /* Disable pre-emption. This means that although we start the builtin * application here, it will not actually run until pre-emption is * re-enabled below. @@ -153,8 +162,7 @@ static int builtin_taskcreate(int index, FAR const char **argv) /* Start the builtin application task */ - ret = TASK_CREATE(g_builtins[index].name, g_builtins[index].priority, - g_builtins[index].stacksize, g_builtins[index].main, + ret = TASK_CREATE(b->name, b->priority, b->stacksize, b->main, (argv) ? &argv[1] : (FAR const char **)NULL); /* If robin robin scheduling is enabled, then set the scheduling policy @@ -171,7 +179,7 @@ static int builtin_taskcreate(int index, FAR const char **argv) * new task cannot yet have changed from its initial value. */ - param.sched_priority = g_builtins[index].priority; + param.sched_priority = b->priority; (void)sched_setscheduler(ret, SCHED_RR, ¶m); } #endif @@ -293,8 +301,6 @@ static inline int builtin_startproxy(int index, FAR const char **argv, int errcode; int ret; - DEBUGASSERT(path); - svdbg("index=%d argv=%p redirfile=%s oflags=%04x\n", index, argv, redirfile, oflags); diff --git a/nuttx/TODO b/nuttx/TODO index 248d2dafa..91b4aebaa 100644 --- a/nuttx/TODO +++ b/nuttx/TODO @@ -6,7 +6,7 @@ standards, things that could be improved, and ideas for enhancements. nuttx/ - (10) Task/Scheduler (sched/) + (11) Task/Scheduler (sched/) (1) Memory Managment (mm/) (3) Signals (sched/, arch/) (2) pthreads (sched/) @@ -193,7 +193,7 @@ o Task/Scheduler (sched/) Priority: Low Title: IMPROVED TASK CONTROL BLOCK STRUCTURE - All task resources that are shared amongst threads have + Description: All task resources that are shared amongst threads have their own "break-away", reference-counted structure. The Task Control Block (TCB) of each thread holds a reference to each breakaway structure (see include/nuttx/sched.h). @@ -206,11 +206,26 @@ o Task/Scheduler (sched/) - File descriptors (struct filelist) - FILE streams (struct streamlist) - Sockets (struct socketlist) - Status: Open - Priority: Low. This is an enhancement. It would slight reduce + Status: Open + Priority: Low. This is an enhancement. It would slight reduce memory usage but would also increase coupling. These resources are nicely modular now. + Title: ISSUES WITH atexit() AND on_exit() + Description: These functions execute with the following bad properties: + + 1. They run with interrupts disabled, + 2. They run in supervisor mode (if applicable), and + 3. They do not obey any setup of PIC or address + environments. Do they need to? + + The fix for all of these issues it to have the callbacks + run on the caller's thread (as with signal handlers). + Status: Open + Priority: Medium Low. This is an important change to some less + important interfaces. For the average user, these + functions are just fine the way they are. + o Memory Managment (mm/) ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/nuttx/binfmt/Makefile b/nuttx/binfmt/Makefile index 49dcd3d32..2f692beb1 100644 --- a/nuttx/binfmt/Makefile +++ b/nuttx/binfmt/Makefile @@ -52,6 +52,10 @@ ifeq ($(CONFIG_BINFMT_EXEPATH),y) BINFMT_CSRCS += binfmt_exepath.c endif +ifeq ($(CONFIG_SCHED_HAVE_PARENT),y) +BINFMT_CSRCS += binfmt_schedunload.c +endif + # Symbol table source files BINFMT_CSRCS += symtab_findbyname.c symtab_findbyvalue.c diff --git a/nuttx/binfmt/binfmt_exec.c b/nuttx/binfmt/binfmt_exec.c index d878c8cc5..1cead4384 100644 --- a/nuttx/binfmt/binfmt_exec.c +++ b/nuttx/binfmt/binfmt_exec.c @@ -74,7 +74,9 @@ * * Description: * This is a convenience function that wraps load_ and exec_module into - * one call. + * one call. If CONFIG_SCHED_ONEXIT is also defined, this function will + * automatically call schedule_unload() to unload the module when task + * exits. * * Input Parameter: * filename - Fulll path to the binary to be loaded @@ -84,7 +86,7 @@ * * Returned Value: * This is an end-user function, so it follows the normal convention: - * Returns the PID of the exec'ed module. On failure, it.returns + * It returns the PID of the exec'ed module. On failure, it returns * -1 (ERROR) and sets errno appropriately. * ****************************************************************************/ @@ -92,6 +94,66 @@ int exec(FAR const char *filename, FAR const char **argv, FAR const struct symtab_s *exports, int nexports) { +#ifdef CONFIG_SCHED_ONEXIT + FAR struct binary_s *bin; + int errorcode; + int ret; + + /* Allocate the load information */ + + bin = (FAR struct binary_s *)kzalloc(sizeof(struct binary_s)); + if (!bin) + { + set_errno(ENOMEM); + return ERROR; + } + + /* Load the module into memory */ + + bin->filename = filename; + bin->exports = exports; + bin->nexports = nexports; + + ret = load_module(bin); + if (ret < 0) + { + bdbg("ERROR: Failed to load program '%s'\n", filename); + kfree(bin); + return ERROR; + } + + /* Disable pre-emption so that the executed module does + * not return until we get a chance to connect the on_exit + * handler. + */ + + sched_lock(); + + /* Then start the module */ + + ret = exec_module(bin); + if (ret < 0) + { + bdbg("ERROR: Failed to execute program '%s'\n", filename); + sched_unlock(); + unload_module(bin); + kfree(bin); + return ERROR; + } + + /* Set up to unload the module (and free the binary_s structure) + * when the task exists. + */ + + ret = schedul_unload(ret, bin); + if (ret < 0) + { + bdbg("ERROR: Failed to schedul unload '%s'\n", filename); + } + + sched_unlock(); + return ret; +#else struct binary_s bin; int ret; @@ -119,7 +181,10 @@ int exec(FAR const char *filename, FAR const char **argv, return ERROR; } + /* TODO: How does the module get unloaded in this case? */ + return ret; +#endif } #endif /* CONFIG_BINFMT_DISABLE */ diff --git a/nuttx/binfmt/builtin.c b/nuttx/binfmt/builtin.c index d36cb6326..d80d9f5d8 100644 --- a/nuttx/binfmt/builtin.c +++ b/nuttx/binfmt/builtin.c @@ -89,6 +89,7 @@ static struct binfmt_s g_builtin_binfmt = static int builtin_loadbinary(struct binary_s *binp) { FAR const char *filename; + FAR const struct builtin_s *b; int fd; int index; int ret; @@ -134,9 +135,10 @@ static int builtin_loadbinary(struct binary_s *binp) * the priority. That is a bug and needs to be fixed. */ - binp->entrypt = g_builtins[index].main; - binp->stacksize = g_builtins[index].stacksize; - binp->priority = g_builtins[index].priority; + b = builtin_for_index(index); + binp->entrypt = b->main; + binp->stacksize = b->stacksize; + binp->priority = b->priority; return OK; } diff --git a/nuttx/binfmt/libbuiltin/libbuiltin_getname.c b/nuttx/binfmt/libbuiltin/libbuiltin_getname.c index 01ac024f7..9da2bac29 100644 --- a/nuttx/binfmt/libbuiltin/libbuiltin_getname.c +++ b/nuttx/binfmt/libbuiltin/libbuiltin_getname.c @@ -83,10 +83,14 @@ FAR const char *builtin_getname(int index) { - if (index < 0 || index >= number_builtins()) - { - return NULL; - } + struct builtin_s *b; - return g_builtins[index].name; + b = builtin_for_index(index); + + if (b != NULL) + { + return b->name; + } + + return NULL; } diff --git a/nuttx/binfmt/libbuiltin/libbuiltin_isavail.c b/nuttx/binfmt/libbuiltin/libbuiltin_isavail.c index f99a4b81d..b1d55ff21 100644 --- a/nuttx/binfmt/libbuiltin/libbuiltin_isavail.c +++ b/nuttx/binfmt/libbuiltin/libbuiltin_isavail.c @@ -80,18 +80,19 @@ * Name: builtin_isavail * * Description: - * Return the index into the table of applications for the applicaiton with + * Return the index into the table of applications for the application with * the name 'appname'. * ****************************************************************************/ int builtin_isavail(FAR const char *appname) { + FAR const char *n; int i; - for (i = 0; g_builtins[i].name; i++) + for (i = 0; n = builtin_getname(i); i++) { - if (!strncmp(g_builtins[i].name, appname, NAME_MAX)) + if (!strncmp(n, appname, NAME_MAX)) { return i; } diff --git a/nuttx/configs/sim/nsh/defconfig b/nuttx/configs/sim/nsh/defconfig index 8dc5ddcce..c5eadb122 100644 --- a/nuttx/configs/sim/nsh/defconfig +++ b/nuttx/configs/sim/nsh/defconfig @@ -116,7 +116,7 @@ CONFIG_MSEC_PER_TICK=10 CONFIG_RR_INTERVAL=0 # CONFIG_SCHED_INSTRUMENTATION is not set CONFIG_TASK_NAME_SIZE=32 -# CONFIG_SCHED_HAVE_PARENT is not set +CONFIG_SCHED_HAVE_PARENT=y # CONFIG_JULIAN_TIME is not set CONFIG_START_YEAR=2008 CONFIG_START_MONTH=6 @@ -148,6 +148,7 @@ CONFIG_DISABLE_POLL=y CONFIG_SIG_SIGUSR1=1 CONFIG_SIG_SIGUSR2=2 CONFIG_SIG_SIGALARM=3 +CONFIG_SIG_SIGCHLD=4 CONFIG_SIG_SIGCONDTIMEDOUT=16 # diff --git a/nuttx/fs/binfs/fs_binfs.c b/nuttx/fs/binfs/fs_binfs.c index ed6326eba..56ea472af 100644 --- a/nuttx/fs/binfs/fs_binfs.c +++ b/nuttx/fs/binfs/fs_binfs.c @@ -222,7 +222,7 @@ static int binfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg) } else { - *ptr = g_builtins[(int)filep->f_priv].name; + *ptr = builtin_getname((int)filep->f_priv); ret = OK; } } @@ -287,13 +287,15 @@ static int binfs_opendir(struct inode *mountpt, const char *relpath, static int binfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir) { + FAR const char *name; unsigned int index; int ret; /* Have we reached the end of the directory */ index = dir->u.binfs.fb_index; - if (g_builtins[index].name == NULL) + name = builtin_getname(index); + if (name == NULL) { /* We signal the end of the directory by returning the * special error -ENOENT @@ -306,9 +308,9 @@ static int binfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir) { /* Save the filename and file type */ - fvdbg("Entry %d: \"%s\"\n", index, g_builtins[index].name); + fvdbg("Entry %d: \"%s\"\n", index, name); dir->fd_dir.d_type = DTYPE_FILE; - strncpy(dir->fd_dir.d_name, g_builtins[index].name, NAME_MAX+1); + strncpy(dir->fd_dir.d_name, name, NAME_MAX+1); /* The application list is terminated by an entry with a NULL name. * Therefore, there is at least one more entry in the list. diff --git a/nuttx/include/nuttx/binfmt/binfmt.h b/nuttx/include/nuttx/binfmt/binfmt.h index c6c7c874a..472ba0fc4 100644 --- a/nuttx/include/nuttx/binfmt/binfmt.h +++ b/nuttx/include/nuttx/binfmt/binfmt.h @@ -82,6 +82,18 @@ typedef FAR void (*binfmt_dtor_t)(void); struct symtab_s; struct binary_s { + /* 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. + */ + +#ifdef CONFIG_SCHED_HAVE_PARENT + FAR struct binary_s *flink; /* Supports a singly linked list */ + pid_t pid; /* Task ID of the child task */ +#endif + /* Information provided to the loader to load and bind a module */ FAR const char *filename; /* Full path to the binary to be loaded (See NOTE 1 above) */ @@ -222,19 +234,48 @@ int unload_module(FAR const struct binary_s *bin); * * Returned Value: * This is an end-user function, so it follows the normal convention: - * Returns the PID of the exec'ed module. On failure, it.returns + * Returns the PID of the exec'ed module. On failure, it returns * -1 (ERROR) and sets errno appropriately. * ****************************************************************************/ int exec_module(FAR const struct binary_s *bin); +/**************************************************************************** + * 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. + * + ****************************************************************************/ + +#ifdef CONFIG_SCHED_HAVE_PARENT +int schedule_unload(pid_t pid, FAR const struct binary_s *bin); +#endif + /**************************************************************************** * Name: exec * * Description: * This is a convenience function that wraps load_ and exec_module into - * one call. + * one call. If CONFIG_SCHED_ONEXIT is also defined, this function will + * automatically call schedule_unload() to unload the module when task + * exits. * * Input Parameter: * filename - Fulll path to the binary to be loaded @@ -244,7 +285,7 @@ int exec_module(FAR const struct binary_s *bin); * * Returned Value: * This is an end-user function, so it follows the normal convention: - * Returns the PID of the exec'ed module. On failure, it.returns + * It returns the PID of the exec'ed module. On failure, it returns * -1 (ERROR) and sets errno appropriately. * ****************************************************************************/ diff --git a/nuttx/include/nuttx/binfmt/builtin.h b/nuttx/include/nuttx/binfmt/builtin.h index 632f8944d..5921cc518 100644 --- a/nuttx/include/nuttx/binfmt/builtin.h +++ b/nuttx/include/nuttx/binfmt/builtin.h @@ -73,14 +73,6 @@ extern "C" { #define EXTERN extern #endif -/* The g_builtins[] array holds information about each builtin function. If - * support for builtin functions is enabled in the NuttX configuration, then - * this arrary (along with the number_builtins() function) must be provided - * by the application code. - */ - -EXTERN const struct builtin_s g_builtins[]; - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -128,24 +120,24 @@ FAR const char *builtin_getname(int index); * Data Set Access Functions Provided to Applications by binfmt/libbuiltin ****************************************************************************/ /**************************************************************************** - * Name: number_builtins + * Name: builtin_for_index * * Description: - * Returns the number of builtin functions in the g_builtins[] array. If - * support for builtin functions is enabled in the NuttX configuration, - * then this function (along with g_builtins[]) must be provided by the - * application code. + * Returns the builtin_s structure for the selected builtin. + * If support for builtin functions is enabled in the NuttX configuration, + * then this function must be provided by the application code. * * Input Parameter: - * None + * index, from 0 and on... * * Returned Value: - * The number of entries in the g_builtins[] array. This function does - * not return failures. + * Returns valid pointer pointing to the builtin_s structure if index is + * valid. + * Otherwise, NULL is returned. * ****************************************************************************/ -int number_builtins(void); +EXTERN FAR const struct builtin_s *builtin_for_index(int index); #undef EXTERN #if defined(__cplusplus) diff --git a/nuttx/sched/Kconfig b/nuttx/sched/Kconfig index 6d53a03aa..11d74b583 100644 --- a/nuttx/sched/Kconfig +++ b/nuttx/sched/Kconfig @@ -4,7 +4,7 @@ # config MSEC_PER_TICK - int "tick timer" + int "Milliseconds per system timer tick" default 10 ---help--- The default system timer is 100Hz or MSEC_PER_TICK=10. This setting @@ -12,7 +12,7 @@ config MSEC_PER_TICK system timer interrupts at some interrupt interval other than 10 msec. config RR_INTERVAL - int "round robin timeslice" + int "Round robin timeslice (MSEC)" default 0 ---help--- The round robin timeslice will be set this number of milliseconds; @@ -39,7 +39,7 @@ config TASK_NAME_SIZE disable. config SCHED_HAVE_PARENT - bool "Remember Parent" + bool "Support parent/child task relationships" default n ---help--- Remember the ID of the parent thread when a new child thread is @@ -56,15 +56,15 @@ config JULIAN_TIME Enables Julian time conversions config START_YEAR - int "start year" + int "Start year" default 2013 config START_MONTH - int "start month" + int "Start month" default 1 config START_DAY - int "start day" + int "Start day" default 1 config DEV_CONSOLE @@ -372,7 +372,7 @@ endif comment "Sizes of configurable things (0 disables)" config MAX_TASKS - int "Max tasks" + int "Max number of tasks" default 32 ---help--- The maximum number of simultaneously active tasks. This value must be @@ -386,33 +386,32 @@ config MAX_TASK_ARGS receive (i.e., maxmum value of 'argc') config NPTHREAD_KEYS - int "Number of pthread keys" + int "Maximum number of pthread keys" default 4 ---help--- The number of items of thread- specific data that can be retained config NFILE_DESCRIPTORS - int "Max file descriptors" + int "Maximum number of file descriptors per task" default 16 ---help--- - The maximum number of file - descriptors (one for each open) + The maximum number of file descriptors per task (one for each open) config NFILE_STREAMS - int "Max file streams" + int "Maximum number of FILE streams" default 16 ---help--- The maximum number of streams that can be fopen'ed config NAME_MAX - int "name max" + int "Maximum size of a file name" default 32 ---help--- The maximum size of a file name. config PREALLOC_MQ_MSGS - int "Pre-allocated messages" + int "Number of pre-allocated messages" default 32 ---help--- The number of pre-allocated message structures. The system manages @@ -426,21 +425,20 @@ config MQ_MAXMSGSIZE setting (does not include other message structure overhead. config MAX_WDOGPARMS - int "max watchdog parms" + int "Maximum number of watchdog parameters" default 4 ---help--- - Maximum number of parameters that - can be passed to a watchdog handler + Maximum number of parameters that can be passed to a watchdog handler config PREALLOC_WDOGS - int "Pre-allocated watchdogs" + int "Number of pre-allocated watchdog timers" default 32 ---help--- The number of pre-allocated watchdog structures. The system manages a pool of preallocated watchdog structures to minimize dynamic allocations config PREALLOC_TIMERS - int "Pre-allocated timers" + int "Number of pre-allocated POSIX timers" default 8 ---help--- The number of pre-allocated POSIX timer structures. The system manages a diff --git a/nuttx/tools/Makefile.export b/nuttx/tools/Makefile.export index 002cb526b..6dfe72bf9 100644 --- a/nuttx/tools/Makefile.export +++ b/nuttx/tools/Makefile.export @@ -37,14 +37,18 @@ include $(TOPDIR)/.config include $(EXPORTDIR)/Make.defs ifdef ARCHSCRIPT +# +# ARCHSCRIPT may contain a leading -T; it must not be followed by a space +# for this to work. +# ifeq ($(WINTOOL),y) -LDPATH = ${shell cygpath -u $(patsubst -T,,$(ARCHSCRIPT))} +LDPATH = $(shell cygpath -u $(patsubst -T%,%,$(ARCHSCRIPT))) else -LDPATH = $(patsubst -T,,$(ARCHSCRIPT)) +LDPATH = $(patsubst -T%,%,$(ARCHSCRIPT)) endif -LDNAME = ${shell basename ${LDPATH}} -LDDIR = ${shell dirname ${LDPATH}} +LDNAME = ${notdir ${LDPATH}} +LDDIR = ${dir ${LDPATH}} endif ARCHSUBDIR = "arch/$(CONFIG_ARCH)/src"