binfmt/ and sched/group: Re-architect the way that loadable ELF or NXFLAT modules are unloaded. Memory resources must be recovered when the task loaded into memory exits. The originmal implementatino used the death-of-child SIGCHLD signal to perform the unload. There are several problems with this: It is overly complex, it requires that the parent task stay resident while the loaded task runs, and it has fatal logic flaws in the protected and kernel model builds because the user signal handler attempts to run in the kernel address space. This commit corrects with using a mindlessly simply BINFMT callback when the task exits.
This commit is contained in:
parent
3e814eb160
commit
20a86dfc1b
@ -28,9 +28,23 @@ config PATH_INITIAL
|
||||
The initial value of the PATH variable. This is the colon-separated
|
||||
list of absolute paths. E.g., "/bin:/usr/bin:/sbin"
|
||||
|
||||
config BINFMT_LOADABLE
|
||||
bool
|
||||
default n
|
||||
---help---
|
||||
Automatically selected if a loadable binary format is selected.
|
||||
|
||||
config PIC
|
||||
bool
|
||||
default n
|
||||
---help---
|
||||
Automatically selected if the binary format requires position
|
||||
independent operation.
|
||||
|
||||
config NXFLAT
|
||||
bool "Enable the NXFLAT Binary Format"
|
||||
default n
|
||||
select BINFMT_LOADABLE
|
||||
select PIC
|
||||
---help---
|
||||
Enable support for the NXFLAT binary format. Default: n
|
||||
@ -42,6 +56,7 @@ endif
|
||||
config ELF
|
||||
bool "Enable the ELF Binary Format"
|
||||
default n
|
||||
select BINFMT_LOADABLE
|
||||
select LIBC_ARCH_ELF
|
||||
---help---
|
||||
Enable support for the ELF binary format. Default: n
|
||||
@ -96,10 +111,6 @@ endif
|
||||
|
||||
endif
|
||||
|
||||
config PIC
|
||||
bool
|
||||
default n
|
||||
|
||||
config BINFMT_CONSTRUCTORS
|
||||
bool "C++ Static Constructor Support"
|
||||
default n
|
||||
|
@ -1,7 +1,8 @@
|
||||
############################################################################
|
||||
# nxflat/Makefile
|
||||
#
|
||||
# Copyright (C) 2007-2009, 2012-2016 Gregory Nutt. All rights reserved.
|
||||
# Copyright (C) 2007-2009, 2012-2016, 2018 Gregory Nutt. All rights
|
||||
# reserved.
|
||||
# Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
@ -52,8 +53,8 @@ ifeq ($(CONFIG_BINFMT_EXEPATH),y)
|
||||
BINFMT_CSRCS += binfmt_exepath.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SCHED_HAVE_PARENT),y)
|
||||
BINFMT_CSRCS += binfmt_schedunload.c
|
||||
ifeq ($(CONFIG_BINFMT_LOADABLE),y)
|
||||
BINFMT_CSRCS += binfmt_exit.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_LIBC_EXECFUNCS),y)
|
||||
|
@ -106,7 +106,7 @@ int dump_module(FAR const struct binary_s *bin);
|
||||
* argv - Argument list
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on sucess; a negater erro value on failure.
|
||||
* Zero (OK) on success; a negater errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
/****************************************************************************
|
||||
* binfmt/binfmt_exec.c
|
||||
*
|
||||
* Copyright (C) 2009, 2013-2014, 2017 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2009, 2013-2014, 2017-2018 Gregory Nutt. All rights
|
||||
* reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -44,6 +45,7 @@
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/sched.h>
|
||||
#include <nuttx/binfmt/binfmt.h>
|
||||
|
||||
#include "binfmt.h"
|
||||
@ -59,9 +61,8 @@
|
||||
*
|
||||
* Description:
|
||||
* This is a convenience function that wraps load_ and exec_module into
|
||||
* one call. If CONFIG_SCHED_ONEXIT and CONFIG_SCHED_HAVE_PARENT are
|
||||
* also defined, this function will automatically call schedule_unload()
|
||||
* to unload the module when task exits.
|
||||
* one call. If CONFIG_BINFMT_LOADABLE is defined, this function will
|
||||
* schedule to unload the module when task exits.
|
||||
*
|
||||
* This non-standard, NuttX function is similar to execv() and
|
||||
* posix_spawn() but differs in the following ways;
|
||||
@ -91,9 +92,9 @@
|
||||
* process cannot provide any meaning symbolic information for use in
|
||||
* linking a different process.
|
||||
*
|
||||
* NOTE: This function is flawed and useless without CONFIG_SCHED_ONEXIT
|
||||
* and CONFIG_SCHED_HAVE_PARENT because without those features there is
|
||||
* then no mechanism to unload the module once it exits.
|
||||
* NOTE: This function is flawed and useless without CONFIG_BINFMT_LOADABLE
|
||||
* because without that features there is then no mechanism to unload the
|
||||
* module once it exits.
|
||||
*
|
||||
* Input Parameters:
|
||||
* filename - The path to the program to be executed. If
|
||||
@ -173,20 +174,22 @@ int exec(FAR const char *filename, FAR char * const *argv,
|
||||
if (pid < 0)
|
||||
{
|
||||
errcode = -pid;
|
||||
berr("ERROR: Failed to execute program '%s': %d\n", filename, errcode);
|
||||
berr("ERROR: Failed to execute program '%s': %d\n",
|
||||
filename, errcode);
|
||||
goto errout_with_lock;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SCHED_ONEXIT) && defined(CONFIG_SCHED_HAVE_PARENT)
|
||||
#ifdef CONFIG_BINFMT_LOADABLE
|
||||
/* Set up to unload the module (and free the binary_s structure)
|
||||
* when the task exists.
|
||||
*/
|
||||
|
||||
ret = schedule_unload(pid, bin);
|
||||
ret = group_exitinfo(pid, bin);
|
||||
if (ret < 0)
|
||||
{
|
||||
berr("ERROR: Failed to schedule unload '%s': %d\n", filename, ret);
|
||||
}
|
||||
|
||||
#else
|
||||
/* Free the binary_s structure here */
|
||||
|
||||
|
@ -82,7 +82,7 @@
|
||||
* the new task's main function is called.
|
||||
*
|
||||
* Input Parameters:
|
||||
* loadinfo - Load state information
|
||||
* arg - Argument is instance of load state info structure cast to void *.
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 (OK) is returned on success and a negated errno is returned on
|
||||
|
96
binfmt/binfmt_exit.c
Normal file
96
binfmt/binfmt_exit.c
Normal file
@ -0,0 +1,96 @@
|
||||
/****************************************************************************
|
||||
* binfmt/binfmt_exit.c
|
||||
*
|
||||
* Copyright (C) 2013, 2016-2018 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 <sys/types.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/binfmt/binfmt.h>
|
||||
|
||||
#include "binfmt.h"
|
||||
|
||||
#ifdef CONFIG_BINFMT_LOADABLE
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: binfmt_exit
|
||||
*
|
||||
* Description:
|
||||
* This function may be called when a tasked loaded into RAM exits.
|
||||
* This function will unload the module when the task exits and reclaim
|
||||
* all resources used by the module.
|
||||
*
|
||||
* Input Parameters:
|
||||
* bin - This structure must have been allocated with kmm_malloc() and must
|
||||
* persist until the task unloads
|
||||
*
|
||||
* 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 binfmt_exit(FAR struct binary_s *bin)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(bin != NULL);
|
||||
|
||||
/* Unload the module */
|
||||
|
||||
ret = unload_module(bin);
|
||||
if (ret < 0)
|
||||
{
|
||||
berr("ERROR: unload_module() failed: %d\n", ret);
|
||||
}
|
||||
|
||||
/* Free the load structure */
|
||||
|
||||
kmm_free(bin);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BINFMT_LOADABLE */
|
@ -1,319 +0,0 @@
|
||||
/****************************************************************************
|
||||
* binfmt/binfmt_schedunload.c
|
||||
*
|
||||
* Copyright (C) 2013, 2016-2017 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/irq.h>
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/signal.h>
|
||||
#include <nuttx/binfmt/binfmt.h>
|
||||
|
||||
#include "binfmt.h"
|
||||
|
||||
#if !defined(CONFIG_BINFMT_DISABLE) && defined(CONFIG_SCHED_HAVE_PARENT)
|
||||
|
||||
/****************************************************************************
|
||||
* 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 kmm_malloc. 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 Parameters:
|
||||
* pid - The task ID of the child task
|
||||
* bin - This structure must have been allocated with kmm_malloc() 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 nxsig_procmask. Here we do it the quick'n'dirty way by just
|
||||
* disabling interrupts.
|
||||
*/
|
||||
|
||||
flags = enter_critical_section();
|
||||
bin->flink = g_unloadhead;
|
||||
g_unloadhead = bin;
|
||||
leave_critical_section(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 kmm_malloc. 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 Parameters:
|
||||
* 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 kmm_malloc() or friends and will also automatically
|
||||
* free the structure with kmm_free() when the task exists.
|
||||
*
|
||||
* Input Parameters:
|
||||
* 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)
|
||||
{
|
||||
berr("ERROR:Bad signal callback: signo=%d info=%p\n", signo, info);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the load information for this pid */
|
||||
|
||||
bin = unload_list_remove(info->si_pid);
|
||||
if (!bin)
|
||||
{
|
||||
berr("ERROR: Could not find load info for PID=%d\n", info->si_pid);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Unload the module */
|
||||
|
||||
ret = unload_module(bin);
|
||||
if (ret < 0)
|
||||
{
|
||||
berr("ERROR: unload_module() failed: %d\n", ret);
|
||||
}
|
||||
|
||||
/* Free the load structure */
|
||||
|
||||
kmm_free(bin);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: schedule_unload
|
||||
*
|
||||
* Description:
|
||||
* If CONFIG_SCHED_HAVE_PARENT is defined, this function may be called by
|
||||
* the parent of 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 kmm_malloc()
|
||||
* or friends. It will also automatically free the structure with kmm_free()
|
||||
* after unloading the module.
|
||||
*
|
||||
* Input Parameters:
|
||||
* pid - The task ID of the child task
|
||||
* bin - This structure must have been allocated with kmm_malloc() and must
|
||||
* persist until the task unloads
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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 set;
|
||||
irqstate_t flags;
|
||||
int ret;
|
||||
|
||||
/* Make sure that SIGCHLD is unmasked */
|
||||
|
||||
(void)sigemptyset(&set);
|
||||
(void)sigaddset(&set, SIGCHLD);
|
||||
ret = nxsig_procmask(SIG_UNBLOCK, &set, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
berr("ERROR: nxsig_procmask failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
|
||||
ret = -get_errno();
|
||||
berr("ERROR: sigaction failed: %d\n" , ret);
|
||||
|
||||
/* Emergency removal from the list */
|
||||
|
||||
flags = enter_critical_section();
|
||||
if (unload_list_remove(pid) != bin)
|
||||
{
|
||||
berr("ERROR: Failed to remove structure\n");
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_BINFMT_DISABLE && CONFIG_SCHED_HAVE_PARENT */
|
||||
|
@ -63,7 +63,7 @@
|
||||
* Execute C++ static constructors.
|
||||
*
|
||||
* Input Parameters:
|
||||
* loadinfo - Load state information
|
||||
* binp - Load state information
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 (OK) is returned on success and a negated errno is returned on
|
||||
|
@ -260,41 +260,13 @@ int unload_module(FAR struct binary_s *bin);
|
||||
|
||||
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 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 kmm_malloc()
|
||||
* or friends. It will also automatically free the structure with
|
||||
* kmm_free() after unloading the module.
|
||||
*
|
||||
* Input Parameters:
|
||||
* pid - The task ID of the child task
|
||||
* bin - This structure must have been allocated with kmm_malloc() and must
|
||||
* persist until the task unloads
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SCHED_HAVE_PARENT
|
||||
int schedule_unload(pid_t pid, FAR struct binary_s *bin);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: exec
|
||||
*
|
||||
* Description:
|
||||
* This is a convenience function that wraps load_ and exec_module into
|
||||
* one call. If CONFIG_SCHED_ONEXIT and CONFIG_SCHED_HAVE_PARENT are
|
||||
* also defined, this function will automatically call schedule_unload()
|
||||
* to unload the module when task exits.
|
||||
* one call. If CONFIG_BINFMT_LOADABLE is defined, this function will
|
||||
* schedule to unload the module when task exits.
|
||||
*
|
||||
* This non-standard, NuttX function is similar to execv() and
|
||||
* posix_spawn() but differs in the following ways;
|
||||
@ -316,7 +288,7 @@ int schedule_unload(pid_t pid, FAR struct binary_s *bin);
|
||||
* The interface is available in the FLAT build mode although it is not
|
||||
* really necessary in that case. It is currently used by some example
|
||||
* code under the apps/ that that generate their own symbol tables for
|
||||
* linking test programs. So althought it is not necessary, it can still
|
||||
* linking test programs. So although it is not necessary, it can still
|
||||
* be useful.
|
||||
*
|
||||
* The interface would be completely useless and will not be supported in
|
||||
@ -324,9 +296,9 @@ int schedule_unload(pid_t pid, FAR struct binary_s *bin);
|
||||
* process cannot provide any meaning symbolic information for use in
|
||||
* linking a different process.
|
||||
*
|
||||
* NOTE: This function is flawed and useless without CONFIG_SCHED_ONEXIT
|
||||
* and CONFIG_SCHED_HAVE_PARENT because without those features there is
|
||||
* then no mechanism to unload the module once it exits.
|
||||
* NOTE: This function is flawed and useless without CONFIG_BINFMT_LOADABLE
|
||||
* because without that features there is then no mechanism to unload the
|
||||
* module once it exits.
|
||||
*
|
||||
* Input Parameters:
|
||||
* filename - The path to the program to be executed. If
|
||||
@ -352,6 +324,29 @@ int schedule_unload(pid_t pid, FAR struct binary_s *bin);
|
||||
int exec(FAR const char *filename, FAR char * const *argv,
|
||||
FAR const struct symtab_s *exports, int nexports);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: binfmt_exit
|
||||
*
|
||||
* Description:
|
||||
* This function may be called when a tasked loaded into RAM exits.
|
||||
* This function will unload the module when the task exits and reclaim
|
||||
* all resources used by the module.
|
||||
*
|
||||
* Input Parameters:
|
||||
* bin - This structure must have been allocated with kmm_malloc() and must
|
||||
* persist until the task unloads
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_BINFMT_LOADABLE
|
||||
int binfmt_exit(FAR struct binary_s *bin);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: exepath_init
|
||||
*
|
||||
|
@ -421,6 +421,10 @@ struct dspace_s
|
||||
struct join_s; /* Forward reference */
|
||||
/* Defined in sched/pthread/pthread.h */
|
||||
#endif
|
||||
#ifdef CONFIG_BINFMT_LOADABLE
|
||||
struct binary_s; /* Forward reference */
|
||||
/* Defined in include/nuttx/binfmt/binfmt.h */
|
||||
#endif
|
||||
|
||||
struct task_group_s
|
||||
{
|
||||
@ -466,6 +470,12 @@ struct task_group_s
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BINFMT_LOADABLE
|
||||
/* Loadable module support ****************************************************/
|
||||
|
||||
FAR struct binary_s *tg_bininfo; /* Describes resources used by program */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SCHED_HAVE_PARENT
|
||||
/* Child exit status **********************************************************/
|
||||
|
||||
@ -866,6 +876,31 @@ FAR struct task_tcb_s *task_vforksetup(start_t retaddr);
|
||||
pid_t task_vforkstart(FAR struct task_tcb_s *child);
|
||||
void task_vforkabort(FAR struct task_tcb_s *child, int errcode);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: group_exitinfo
|
||||
*
|
||||
* Description:
|
||||
* This function may be called to when a task is loaded into memory. It
|
||||
* will setup the to automatically unload the module when the task exits.
|
||||
*
|
||||
* Input Parameters:
|
||||
* pid - The task ID of the newly loaded task
|
||||
* bininfo - This structure allocated with kmm_malloc(). This memory
|
||||
* persists until the task exits and will be used unloads
|
||||
* the module from memory.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_BINFMT_LOADABLE
|
||||
struct binary_s; /* Forward reference */
|
||||
int group_exitinfo(pid_t pid, FAR struct binary_s *bininfo);
|
||||
#endif
|
||||
|
||||
/********************************************************************************
|
||||
* Name: sched_resume_scheduler
|
||||
*
|
||||
|
@ -52,6 +52,10 @@ ifeq ($(CONFIG_ARCH_ADDRENV),y)
|
||||
CSRCS += group_addrenv.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BINFMT_LOADABLE),y)
|
||||
CSRCS += group_exitinfo.c
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_DISABLE_SIGNALS),y)
|
||||
CSRCS += group_signal.c
|
||||
endif
|
||||
|
107
sched/group/group_exitinfo.c
Normal file
107
sched/group/group_exitinfo.c
Normal file
@ -0,0 +1,107 @@
|
||||
/****************************************************************************
|
||||
* sched/group/group_exitinfo.c
|
||||
*
|
||||
* Copyright (C) 2018 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 <sys/types.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/sched.h>
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/binfmt/binfmt.h>
|
||||
|
||||
#include "sched/sched.h"
|
||||
#include "group/group.h"
|
||||
|
||||
#ifdef CONFIG_BINFMT_LOADABLE
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: group_exitinfo
|
||||
*
|
||||
* Description:
|
||||
* This function may be called to when a task is loaded into memory. It
|
||||
* will setup the to automatically unload the module when the task exits.
|
||||
*
|
||||
* Input Parameters:
|
||||
* pid - The task ID of the newly loaded task
|
||||
* bininfo - This structure allocated with kmm_malloc(). This memory
|
||||
* persists until the task exits and will be used unloads
|
||||
* the module from memory.
|
||||
*
|
||||
* 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 group_exitinfo(pid_t pid, FAR struct binary_s *bininfo)
|
||||
{
|
||||
FAR struct tcb_s *tcb;
|
||||
FAR struct task_group_s *group;
|
||||
irqstate_t flags;
|
||||
|
||||
DEBUGASSERT(bin != NULL);
|
||||
flags = spin_lock_irqsave();
|
||||
|
||||
/* Get the TCB associated with the PID */
|
||||
|
||||
tcb = sched_gettcb(pid);
|
||||
if (tcb == NULL)
|
||||
{
|
||||
spin_unlock_irqrestore(flags);
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
/* Get the group that this task belongs to */
|
||||
|
||||
group = tcb->group;
|
||||
DEBUGASSERT(group != NULL && group->tg_bininfo == NULL);
|
||||
|
||||
/* Save the binary info for use when the task exits */
|
||||
|
||||
group->tg_bininfo = bininfo;
|
||||
return OK;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BINFMT_LOADABLE */
|
@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
* sched/group/group_leave.c
|
||||
*
|
||||
* Copyright (C) 2013-2017 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2013-2018 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -49,6 +49,10 @@
|
||||
#include <nuttx/net/net.h>
|
||||
#include <nuttx/lib/lib.h>
|
||||
|
||||
#ifdef CONFIG_BINFMT_LOADABLE
|
||||
# include <nuttx/binfmt/binfmt.h>
|
||||
#endif
|
||||
|
||||
#include "environ/environ.h"
|
||||
#include "signal/signal.h"
|
||||
#include "pthread/pthread.h"
|
||||
@ -260,6 +264,19 @@ static inline void group_release(FAR struct task_group_s *group)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BINFMT_LOADABLE
|
||||
/* If the exiting task was loaded into RAM from a file, then we need to
|
||||
* lease all of the memory resource when the last thread exits the task
|
||||
* group.
|
||||
*/
|
||||
|
||||
if (group->tg_bininfo != NULL)
|
||||
{
|
||||
binfmt_exit(group->tg_bininfo);
|
||||
group->tg_bininfo = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SCHED_WAITPID) && !defined(CONFIG_SCHED_HAVE_PARENT)
|
||||
/* If there are threads waiting for this group to be freed, then we cannot
|
||||
* yet free the memory resources. Instead just mark the group deleted
|
||||
|
@ -239,7 +239,7 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
|
||||
|
||||
/* Then wait for the task to exit */
|
||||
|
||||
if (options & WNOHANG)
|
||||
if ((options & WNOHANG) != 0)
|
||||
{
|
||||
/* Don't wait if status is not available */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user