Add logic to automatically unload module on exit; Several patches from Mike Smith
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5528 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
828c1c65c7
commit
956bded9c1
23
TODO
23
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/)
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
#
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue