This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 64d8249895 sched/addrenv, binfmt: Always allocate address environment
from heap
64d8249895 is described below
commit 64d8249895260a67d5406ead123f04b456c1bd47
Author: Ville Juven <[email protected]>
AuthorDate: Thu Apr 13 11:48:06 2023 +0300
sched/addrenv, binfmt: Always allocate address environment from heap
Instead of using a volatile storage for the address environment in the
binfmt / loadinfo structures, always allocate the address environment
from kheap.
This serves two purposes:
- If the task creation fails, any kernel thread that depends on the
address environment created during task creation will not lose their
mappings (because they hold a reference to it)
- The current address environment variable (g_addrenv) will NEVER contain
a stale / incorrect value
- Releasing the address environment is simplified as any pointer given
to addrenv_drop() can be assumed to be heap memory
- Makes the kludge function addrenv_clear_current irrelevant, as the
system will NEVER have invalid mappings any more
---
binfmt/binfmt_execmodule.c | 6 +--
binfmt/elf.c | 6 +--
binfmt/libelf/libelf_addrenv.c | 40 ++++++++-------
include/nuttx/addrenv.h | 30 ++----------
include/nuttx/binfmt/binfmt.h | 4 +-
include/nuttx/binfmt/elf.h | 4 +-
sched/addrenv/addrenv.c | 107 +++++------------------------------------
sched/task/task_init.c | 13 ++---
8 files changed, 50 insertions(+), 160 deletions(-)
diff --git a/binfmt/binfmt_execmodule.c b/binfmt/binfmt_execmodule.c
index cb38e56d6d..bf6fbdc37f 100644
--- a/binfmt/binfmt_execmodule.c
+++ b/binfmt/binfmt_execmodule.c
@@ -117,7 +117,7 @@ int exec_module(FAR struct binary_s *binp,
{
FAR struct task_tcb_s *tcb;
#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
- FAR struct arch_addrenv_s *addrenv = &binp->addrenv.addrenv;
+ FAR struct arch_addrenv_s *addrenv = &binp->addrenv->addrenv;
FAR void *vheap;
#endif
FAR void *stackaddr = NULL;
@@ -165,7 +165,7 @@ int exec_module(FAR struct binary_s *binp,
#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
/* Instantiate the address environment containing the user heap */
- ret = addrenv_select(&binp->addrenv);
+ ret = addrenv_select(binp->addrenv);
if (ret < 0)
{
berr("ERROR: addrenv_select() failed: %d\n", ret);
@@ -242,7 +242,7 @@ int exec_module(FAR struct binary_s *binp,
#ifdef CONFIG_ARCH_ADDRENV
/* Attach the address environment to the new task */
- ret = addrenv_attach((FAR struct tcb_s *)tcb, &binp->addrenv);
+ ret = addrenv_attach((FAR struct tcb_s *)tcb, binp->addrenv);
if (ret < 0)
{
berr("ERROR: addrenv_attach() failed: %d\n", ret);
diff --git a/binfmt/elf.c b/binfmt/elf.c
index 1b20eaef35..08f778632c 100644
--- a/binfmt/elf.c
+++ b/binfmt/elf.c
@@ -271,11 +271,7 @@ static int elf_loadbinary(FAR struct binary_s *binp,
* needed when the module is executed.
*/
- up_addrenv_clone(&loadinfo.addrenv.addrenv, &binp->addrenv.addrenv);
-
- /* Take a reference to the address environment, so it won't get freed */
-
- addrenv_take(&binp->addrenv);
+ binp->addrenv = loadinfo.addrenv;
#else
binp->alloc[0] = (FAR void *)loadinfo.textalloc;
diff --git a/binfmt/libelf/libelf_addrenv.c b/binfmt/libelf/libelf_addrenv.c
index e3ff9dede0..b437ca3c2b 100644
--- a/binfmt/libelf/libelf_addrenv.c
+++ b/binfmt/libelf/libelf_addrenv.c
@@ -84,24 +84,30 @@ int elf_addrenv_alloc(FAR struct elf_loadinfo_s *loadinfo,
size_t textsize,
size_t datasize, size_t heapsize)
{
#ifdef CONFIG_ARCH_ADDRENV
- FAR struct arch_addrenv_s *addrenv = &loadinfo->addrenv.addrenv;
+ FAR struct arch_addrenv_s *addrenv;
FAR void *vtext;
FAR void *vdata;
int ret;
/* Create an address environment for the new ELF task */
+ loadinfo->addrenv = addrenv_allocate();
+ if (!loadinfo->addrenv)
+ {
+ return -ENOMEM;
+ }
+
+ /* Start creating the address environment sections */
+
+ addrenv = &loadinfo->addrenv->addrenv;
+
ret = up_addrenv_create(textsize, datasize, heapsize, addrenv);
if (ret < 0)
{
berr("ERROR: up_addrenv_create failed: %d\n", ret);
- return ret;
+ goto errout_with_addrenv;
}
- /* Take a reference to the address environment, so it won't get freed */
-
- addrenv_take(&loadinfo->addrenv);
-
/* Get the virtual address associated with the start of the address
* environment. This is the base address that we will need to use to
* access the ELF image (but only if the address environment has been
@@ -112,19 +118,24 @@ int elf_addrenv_alloc(FAR struct elf_loadinfo_s
*loadinfo, size_t textsize,
if (ret < 0)
{
berr("ERROR: up_addrenv_vtext failed: %d\n", ret);
- return ret;
+ goto errout_with_addrenv;
}
ret = up_addrenv_vdata(addrenv, textsize, &vdata);
if (ret < 0)
{
berr("ERROR: up_addrenv_vdata failed: %d\n", ret);
- return ret;
+ goto errout_with_addrenv;
}
loadinfo->textalloc = (uintptr_t)vtext;
loadinfo->dataalloc = (uintptr_t)vdata;
+
return OK;
+
+errout_with_addrenv:
+ addrenv_drop(loadinfo->addrenv, false);
+ return ret;
#else
/* Allocate memory to hold the ELF image */
@@ -177,7 +188,7 @@ int elf_addrenv_select(FAR struct elf_loadinfo_s *loadinfo)
/* Instantiate the new address environment */
- ret = addrenv_select(&loadinfo->addrenv);
+ ret = addrenv_select(loadinfo->addrenv);
if (ret < 0)
{
berr("ERROR: addrenv_select failed: %d\n", ret);
@@ -186,7 +197,7 @@ int elf_addrenv_select(FAR struct elf_loadinfo_s *loadinfo)
/* Allow write access to .text */
- ret = up_addrenv_mprot(&loadinfo->addrenv.addrenv, loadinfo->textalloc,
+ ret = up_addrenv_mprot(&loadinfo->addrenv->addrenv, loadinfo->textalloc,
loadinfo->textsize, ELF_TEXT_WRE);
if (ret < 0)
{
@@ -219,7 +230,7 @@ int elf_addrenv_restore(FAR struct elf_loadinfo_s *loadinfo)
/* Remove write access to .text */
- ret = up_addrenv_mprot(&loadinfo->addrenv.addrenv, loadinfo->textalloc,
+ ret = up_addrenv_mprot(&loadinfo->addrenv->addrenv, loadinfo->textalloc,
loadinfo->textsize, ELF_TEXT_WRD);
if (ret < 0)
{
@@ -261,15 +272,10 @@ int elf_addrenv_restore(FAR struct elf_loadinfo_s
*loadinfo)
void elf_addrenv_free(FAR struct elf_loadinfo_s *loadinfo)
{
#ifdef CONFIG_ARCH_ADDRENV
- int ret;
/* Free the address environment */
- ret = up_addrenv_destroy(&loadinfo->addrenv.addrenv);
- if (ret < 0)
- {
- berr("ERROR: up_addrenv_destroy failed: %d\n", ret);
- }
+ addrenv_drop(loadinfo->addrenv, false);
#else
if (loadinfo->textalloc != 0)
diff --git a/include/nuttx/addrenv.h b/include/nuttx/addrenv.h
index c2416ff548..afac66accc 100644
--- a/include/nuttx/addrenv.h
+++ b/include/nuttx/addrenv.h
@@ -297,35 +297,14 @@ struct addrenv_reserve_s
* Allocate an address environment for a new process.
*
* Input Parameters:
- * tcb - The tcb of the newly created task.
- * ttype - The type of the task.
- *
- * 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 addrenv_allocate(FAR struct tcb_s *tcb, uint8_t ttype);
-
-/****************************************************************************
- * Name: addrenv_free
- *
- * Description:
- * Free an address environment for a process.
- *
- * Input Parameters:
- * tcb - The tcb of the task.
+ * None
*
* 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.
+ * Pointer to the new address environment, or NULL if out of memory.
*
****************************************************************************/
-int addrenv_free(FAR struct tcb_s *tcb);
+FAR struct addrenv_s *addrenv_allocate(void);
/****************************************************************************
* Name: addrenv_switch
@@ -364,8 +343,7 @@ int addrenv_switch(FAR struct tcb_s *tcb);
*
****************************************************************************/
-int addrenv_attach(FAR struct tcb_s *tcb,
- FAR const struct addrenv_s *addrenv);
+int addrenv_attach(FAR struct tcb_s *tcb, FAR struct addrenv_s *addrenv);
/****************************************************************************
* Name: addrenv_join
diff --git a/include/nuttx/binfmt/binfmt.h b/include/nuttx/binfmt/binfmt.h
index 80f80c8e62..6a1cac2589 100644
--- a/include/nuttx/binfmt/binfmt.h
+++ b/include/nuttx/binfmt/binfmt.h
@@ -82,11 +82,11 @@ struct binary_s
#ifdef CONFIG_ARCH_ADDRENV
/* Address environment.
*
- * addrenv - This is the handle created by up_addrenv_create() that can be
+ * addrenv - This is the handle created by addrenv_allocate() that can be
* used to manage the tasks address space.
*/
- addrenv_t addrenv; /* Address environment */
+ FAR addrenv_t *addrenv; /* Address environment */
#endif
size_t mapsize; /* Size of the mapped address region
(needed for munmap) */
diff --git a/include/nuttx/binfmt/elf.h b/include/nuttx/binfmt/elf.h
index 8370ec8832..4fa595c106 100644
--- a/include/nuttx/binfmt/elf.h
+++ b/include/nuttx/binfmt/elf.h
@@ -117,12 +117,12 @@ struct elf_loadinfo_s
/* Address environment.
*
- * addrenv - This is the handle created by up_addrenv_create() that can be
+ * addrenv - This is the handle created by addrenv_allocate() that can be
* used to manage the tasks address space.
*/
#ifdef CONFIG_ARCH_ADDRENV
- addrenv_t addrenv; /* Address environment */
+ FAR addrenv_t *addrenv; /* Address environment */
#endif
uint16_t symtabidx; /* Symbol table section index */
diff --git a/sched/addrenv/addrenv.c b/sched/addrenv/addrenv.c
index cfbcca5506..286512ab03 100644
--- a/sched/addrenv/addrenv.c
+++ b/sched/addrenv/addrenv.c
@@ -86,35 +86,6 @@ static void addrenv_destroy(FAR void *arg)
kmm_free(addrenv);
}
-/****************************************************************************
- * Name: addrenv_clear_current
- *
- * Description:
- * Clear the current addrenv from g_addrenv, if it matches the input.
- *
- * Input Parameters:
- * addrenv - Pointer to the addrenv to free.
- *
- * Returned Value:
- * None.
- *
- ****************************************************************************/
-
-static void addrenv_clear_current(FAR const addrenv_t *addrenv)
-{
- int i;
-
- /* Mark no address environment */
-
- for (i = 0; i < CONFIG_SMP_NCPUS; i++)
- {
- if (addrenv == g_addrenv[i])
- {
- g_addrenv[i] = NULL;
- }
- }
-}
-
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -237,62 +208,26 @@ int addrenv_switch(FAR struct tcb_s *tcb)
* Allocate an address environment for a new process.
*
* Input Parameters:
- * tcb - The tcb of the newly created task.
- * ttype - The type of the task.
+ * None
*
* 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.
+ * Pointer to the new address environment, or NULL if out of memory.
*
****************************************************************************/
-int addrenv_allocate(FAR struct tcb_s *tcb, uint8_t ttype)
+FAR struct addrenv_s *addrenv_allocate(void)
{
- int ret = OK;
+ FAR struct addrenv_s *addrenv;
- if ((ttype & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_KERNEL)
+ addrenv = (FAR struct addrenv_s *)kmm_zalloc(sizeof(struct addrenv_s));
+ if (addrenv)
{
- tcb->addrenv_own = NULL;
- }
- else
- {
- tcb->addrenv_own = (FAR struct addrenv_s *)
- kmm_zalloc(sizeof(struct addrenv_s));
- if (tcb->addrenv_own == NULL)
- {
- ret = -ENOMEM;
- }
- }
+ /* Take reference so this won't get freed */
- return ret;
-}
-
-/****************************************************************************
- * Name: addrenv_free
- *
- * Description:
- * Free an address environment for a process.
- *
- * Input Parameters:
- * tcb - The tcb of the task.
- *
- * 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 addrenv_free(FAR struct tcb_s *tcb)
-{
- if (tcb->addrenv_own != NULL)
- {
- kmm_free(tcb->addrenv_own);
- tcb->addrenv_own = NULL;
+ addrenv->refs = 1;
}
- return OK;
+ return addrenv;
}
/****************************************************************************
@@ -313,24 +248,12 @@ int addrenv_free(FAR struct tcb_s *tcb)
*
****************************************************************************/
-int addrenv_attach(FAR struct tcb_s *tcb,
- FAR const struct addrenv_s *addrenv)
+int addrenv_attach(FAR struct tcb_s *tcb, FAR struct addrenv_s *addrenv)
{
- int ret;
-
- /* Clone the address environment for us */
-
- ret = up_addrenv_clone(&addrenv->addrenv, &tcb->addrenv_own->addrenv);
- if (ret < 0)
- {
- berr("ERROR: up_addrenv_clone failed: %d\n", ret);
- return ret;
- }
-
/* Attach the address environment */
+ tcb->addrenv_own = addrenv;
tcb->addrenv_curr = tcb->addrenv_own;
- tcb->addrenv_own->refs = 1;
return OK;
}
@@ -452,14 +375,6 @@ int addrenv_restore(void)
{
FAR struct tcb_s *tcb = this_task();
addrenv_give(tcb->addrenv_curr);
-
- if (tcb->addrenv_own == NULL)
- {
- /* Kernel thread, clear g_addrenv, as it is not valid any more */
-
- addrenv_clear_current(tcb->addrenv_curr);
- }
-
tcb->addrenv_curr = tcb->addrenv_own;
return addrenv_switch(tcb);
}
diff --git a/sched/task/task_init.c b/sched/task/task_init.c
index 95b0927cc0..06ef5691b5 100644
--- a/sched/task/task_init.c
+++ b/sched/task/task_init.c
@@ -97,12 +97,11 @@ int nxtask_init(FAR struct task_tcb_s *tcb, const char
*name, int priority,
#endif
#ifdef CONFIG_ARCH_ADDRENV
- /* Allocate address environment for the task */
+ /* Kernel threads do not own any address environment */
- ret = addrenv_allocate(&tcb->cmn, tcb->cmn.flags);
- if (ret < 0)
+ if ((ttype & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_KERNEL)
{
- return ret;
+ tcb->cmn.addrenv_own = NULL;
}
#endif
@@ -111,7 +110,7 @@ int nxtask_init(FAR struct task_tcb_s *tcb, const char
*name, int priority,
ret = group_allocate(tcb, tcb->cmn.flags);
if (ret < 0)
{
- goto errout_with_addrenv;
+ return ret;
}
/* Duplicate the parent tasks environment */
@@ -201,10 +200,6 @@ errout_with_group:
group_leave(&tcb->cmn);
-errout_with_addrenv:
-#ifdef CONFIG_ARCH_ADDRENV
- addrenv_free(&tcb->cmn);
-#endif
return ret;
}