mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-10-28 02:13:34 +08:00
Merge Nuttx r5554
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/binfmt/binfmt.h>
|
||||
|
||||
#include "binfmt_internal.h"
|
||||
@@ -74,7 +75,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 +87,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 +95,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 pid;
|
||||
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 */
|
||||
|
||||
pid = exec_module(bin);
|
||||
if (pid < 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 = schedule_unload(pid, bin);
|
||||
if (ret < 0)
|
||||
{
|
||||
bdbg("ERROR: Failed to schedul unload '%s'\n", filename);
|
||||
}
|
||||
|
||||
sched_unlock();
|
||||
return pid;
|
||||
#else
|
||||
struct binary_s bin;
|
||||
int ret;
|
||||
|
||||
@@ -119,7 +182,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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
@@ -97,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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
FAR const struct builtin_s *builtin;
|
||||
|
||||
return g_builtins[index].name;
|
||||
builtin = builtin_for_index(index);
|
||||
|
||||
if (builtin != NULL)
|
||||
{
|
||||
return builtin->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 *name;
|
||||
int i;
|
||||
|
||||
for (i = 0; g_builtins[i].name; i++)
|
||||
for (i = 0; (name = builtin_getname(i)); i++)
|
||||
{
|
||||
if (!strncmp(g_builtins[i].name, appname, NAME_MAX))
|
||||
if (!strncmp(name, appname, NAME_MAX))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user