This is an automated email from the ASF dual-hosted git repository.
xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git
The following commit(s) were added to refs/heads/master by this push:
new 72018699a examples/fdpicxip, testing/fs/xipfs: Each task group has its
own library.
72018699a is described below
commit 72018699a3fe59df30eb6952fce175df23aee553
Author: Marco Casaroli <[email protected]>
AuthorDate: Wed Oct 7 19:17:30 2026 +0200
examples/fdpicxip, testing/fs/xipfs: Each task group has its own library.
The NuttX change "libs/libc/elf: Keep a module registry per task group"
gives each task group its own list of loaded ELF objects. A library that
a module names in DT_NEEDED is now loaded once per task group, not once
for the system. Two instances of a module thus have two copies of the
library data. The library text in xipfs is still shared, and is pinned
once per instance.
Change the C++ test to check this:
* The library is pinned twice while both instances run.
* The library destructor runs once per instance.
* Each destructor sees only the adds of its own instance.
Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Marco Casaroli <[email protected]>
---
examples/fdpicxip/fdpicxip_main.c | 6 ++--
examples/fdpicxip/modules/cxxuser/cxxuser.cpp | 15 ++++------
examples/fdpicxip/modules/libcounter/libcounter.c | 8 ++----
examples/fdpicxip/modules/libshape/libshape.cpp | 8 ++----
examples/fdpicxip/modules/user/user.c | 9 ++----
testing/fs/xipfs/xipfs_main.c | 34 +++++++++++------------
6 files changed, 33 insertions(+), 47 deletions(-)
diff --git a/examples/fdpicxip/fdpicxip_main.c
b/examples/fdpicxip/fdpicxip_main.c
index 9041fe534..b945fb388 100644
--- a/examples/fdpicxip/fdpicxip_main.c
+++ b/examples/fdpicxip/fdpicxip_main.c
@@ -123,10 +123,8 @@ static int extent_info_path(FAR const char *path,
*
* Stages a library and a module that needs it, then runs two instances.
* Both share one mapped copy of each object's code, executed in place from
- * flash. Each instance gets its own copy of the module's data, because
- * exec() loads the module afresh; the library is opened with dlopen() and
- * so there is one of it, data included. The totals therefore interleave,
- * and each instance checks only that its own adds all landed.
+ * flash. Each instance is a task group with its own copy of the data of
+ * the module and of the library, so each total holds its own adds only.
****************************************************************************/
static int stage_blob(FAR const char *path, FAR const unsigned char *data,
diff --git a/examples/fdpicxip/modules/cxxuser/cxxuser.cpp
b/examples/fdpicxip/modules/cxxuser/cxxuser.cpp
index f788e1174..e8a524787 100644
--- a/examples/fdpicxip/modules/cxxuser/cxxuser.cpp
+++ b/examples/fdpicxip/modules/cxxuser/cxxuser.cpp
@@ -28,12 +28,10 @@
* - constructors ran, in both objects. Neither magic can be right by
* accident: an unconstructed global is zero.
* - the library's constructors ran before this module's, which is the
- * ordering DT_NEEDED implies and the loader has to honour. They ran
- * once, for the one library, not once per instance.
- * - the library is one object shared by both instances. DT_NEEDED is
- * loaded with dlopen(), which returns what is already in the module
- * registry, so the totals interleave rather than each reaching seed*3.
- * Each instance can still see every add it made.
+ * ordering DT_NEEDED implies and the loader has to honour.
+ * - each instance has its own library data. A DT_NEEDED library belongs
+ * to the task group that loads it, so each total reaches seed*3. Only
+ * the library text is shared.
*/
#include <fcntl.h>
@@ -191,10 +189,7 @@ extern "C" int main(int argc, char *argv[])
usleep(100000);
}
- /* The other instance is adding to the same library at the same time, so
- * the total is not this instance's alone. What must hold is that every
- * add this instance made landed in it.
- */
+ /* Every add this instance made must be in the total */
if (shape_total() < seed * 3)
{
diff --git a/examples/fdpicxip/modules/libcounter/libcounter.c
b/examples/fdpicxip/modules/libcounter/libcounter.c
index ccf2a9cde..e44bb69b1 100644
--- a/examples/fdpicxip/modules/libcounter/libcounter.c
+++ b/examples/fdpicxip/modules/libcounter/libcounter.c
@@ -23,11 +23,9 @@
/* A shared library with its own state.
*
* g_calls is the interesting part: it lives in the library's writable
- * segment, and there is one of it. A library named in DT_NEEDED is opened
- * with dlopen(), which hands back the instance already in the module
- * registry, so every task that names this library counts into the same
- * g_calls. The library's code, meanwhile, is mapped once and executed in
- * place.
+ * segment. Each task group that names this library in DT_NEEDED loads its
+ * own instance, so each has its own g_calls. The library's code is mapped
+ * once and executed in place.
*/
/****************************************************************************
diff --git a/examples/fdpicxip/modules/libshape/libshape.cpp
b/examples/fdpicxip/modules/libshape/libshape.cpp
index a40df451e..63adb15f6 100644
--- a/examples/fdpicxip/modules/libshape/libshape.cpp
+++ b/examples/fdpicxip/modules/libshape/libshape.cpp
@@ -30,11 +30,9 @@
* demo checks for a magic rather than just printing a total: the failure
* this is here to catch does not announce itself.
*
- * m_total is the second half: it lives in the library's writable segment,
- * of which there is one. A library named in DT_NEEDED is opened with
- * dlopen(), which returns the object already in the module registry, so
- * two tasks naming this library share its data as well as its
- * flash-resident code, and m_total ends up counting both of them.
+ * m_total is the second half: it lives in the library's writable segment.
+ * Each task group that names this library loads its own instance, so each
+ * has its own m_total. Only the flash-resident code is shared.
*/
#include <nuttx/compiler.h>
diff --git a/examples/fdpicxip/modules/user/user.c
b/examples/fdpicxip/modules/user/user.c
index 7f8faf7b1..2a26df1e9 100644
--- a/examples/fdpicxip/modules/user/user.c
+++ b/examples/fdpicxip/modules/user/user.c
@@ -20,12 +20,9 @@
*
****************************************************************************/
-/* Uses libcounter.so. Two instances run concurrently, and there is one
- * library between them: DT_NEEDED is loaded with dlopen(), which returns
- * the object already in the registry rather than a second copy of it, so
- * the totals interleave and the final one counts both instances' bumps.
- * What each instance can assert on its own is that every bump it made
- * landed somewhere it can still see.
+/* Uses libcounter.so. Two instances run concurrently. Each instance is a
+ * task group with its own copy of the library data, so its total counts
+ * its own bumps. The library text is shared.
*
* libcounter is also a *leaf* library -- it calls nothing outside itself,
* so it has no PLT and therefore no DT_PLTGOT. The loader has to fall back
diff --git a/testing/fs/xipfs/xipfs_main.c b/testing/fs/xipfs/xipfs_main.c
index 3e98bc075..904cf3dad 100644
--- a/testing/fs/xipfs/xipfs_main.c
+++ b/testing/fs/xipfs/xipfs_main.c
@@ -2371,14 +2371,13 @@ static void test_fdpic(void)
usleep(150000);
- /* One library, so one pin. Both instances name it in DT_NEEDED, the
- * loader opens it with dlopen(), and the second open takes a reference to
- * what the first loaded rather than loading it again.
+ /* Each instance is a task group with its own registry, so each loads
+ * the library: one pin per instance on the one flash copy.
*/
ret = extent_info(PATH("libshape.so"), &info);
- CHECK("one flash copy of the library, pinned once for both instances",
- ret == 0 && info.pincount == 1, "wrong pin count");
+ CHECK("one flash copy of the library, pinned once per instance",
+ ret == 0 && info.pincount == 2, "wrong pin count");
/* Wait for both, but do not read the exit status from waitpid().
*
@@ -2426,23 +2425,20 @@ static void test_fdpic(void)
(fails & USER_FAIL_LIB_CTOR) == 0, "global left as .bss");
CHECK("the library was constructed before the module needing it",
(fails & USER_FAIL_ORDER) == 0, "wrong DT_NEEDED order");
- CHECK("every add an instance makes lands in the one shared library",
+ CHECK("every add an instance makes lands in its library",
(fails & USER_FAIL_SHARED) == 0, "an instance lost its own adds");
/* Destructors run on unload, which happens as each task is reaped --
* after waitpid() has already returned.
*
- * The library is one object, so its destructor runs once, when the last
- * instance holding it goes. Both instances handed it a marker path and
- * the second one to do so won, which is why this looks for exactly one
- * file rather than for a particular one. What it holds is the total of
- * both instances' adds: three each of one and two.
+ * Each instance has its own copy of the library data, so each destructor
+ * writes its own marker with only its own adds: three of its seed.
*/
usleep(200000);
found = 0;
- total = -1;
+ total = 0;
for (i = 0; i < 2; i++)
{
@@ -2450,14 +2446,18 @@ static void test_fdpic(void)
if (ret >= 0)
{
found++;
- total = ret;
+ }
+
+ if (ret == 3 * (i + 1))
+ {
+ total++;
}
}
- CHECK("the library's destructor ran once, at the last close",
- found == 1, "marker missing or written twice");
- CHECK("it ran with the state both instances had built up",
- total == 3 * (1 + 2), "wrong total");
+ CHECK("the library's destructor ran once per instance",
+ found == 2, "marker missing");
+ CHECK("each ran with the state of its own instance only",
+ total == 2, "wrong total");
ret = extent_info(PATH("libshape.so"), &info);
CHECK("the library's pins return to zero once both instances are gone",