Add logic to automatically unload module on exit; Several patches from Mike Smith

git-svn-id: http://svn.code.sf.net/p/nuttx/code/trunk@5528 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2013-01-17 14:43:55 +00:00
parent caeef71797
commit e9d0885500
15 changed files with 214 additions and 96 deletions

View File

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

View File

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

View File

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

View File

@ -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/)
^^^^^^^^^^^^^^^^^^^^^^

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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