This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit fb74c0a15d34b3e207cf001d693ab5ac999c8ea8
Author: Marco Casaroli <[email protected]>
AuthorDate: Wed Oct 7 19:17:42 2026 +0200

    Documentation: Shared libraries are per task group.
    
    Describe the per task group registry: each task group loads its own copy
    of a library, constructors and destructors run once per task group, and
    a task group closes what it left open when it exits.  Kernel modules stay
    on one list for the system.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 Documentation/os/binfmt/fdpic.rst                  | 18 ++++++----
 .../binfmt/kernel_modules_vs_shared_libraries.rst  | 40 ++++++++++++++--------
 2 files changed, 37 insertions(+), 21 deletions(-)

diff --git a/Documentation/os/binfmt/fdpic.rst 
b/Documentation/os/binfmt/fdpic.rst
index d4e985b08c0..d10c71465ab 100644
--- a/Documentation/os/binfmt/fdpic.rst
+++ b/Documentation/os/binfmt/fdpic.rst
@@ -100,11 +100,13 @@ used as given, and a bare name is searched for along 
``LD_LIBRARY_PATH``,
 which needs ``CONFIG_LIBC_ENVPATH`` and is seeded from
 ``CONFIG_LDPATH_INITIAL``.
 
-A library lands in the module registry, which holds one instance per
-name, so its data is shared by everything that opens it.  A module
-started with ``exec()`` is different: that path loads a fresh copy each
-time, so two running instances of one module have separate data while
-sharing one copy of the text in flash.
+A library lands in the registry of the task group that loads it, which
+holds one instance per name, so its data is shared by everything in that
+task group that opens it.  Another task group gets an instance of its
+own, with its own data.  A module started with ``exec()`` loads a fresh
+copy each time, so two running instances of one module have separate
+data.  Executed in place, all instances share one copy of the text in
+flash.
 
 Comparison with NXFLAT and PIC ELF
 ==================================
@@ -427,8 +429,10 @@ storage.
 
 A library named in ``DT_NEEDED`` is constructed before the module that
 needs it, because the module's own relocation is what opens it, and
-destroyed after, at the last ``dlclose()``.  Since the library is one
-instance, its constructors run once however many modules name it.
+destroyed after, at its last ``dlclose()`` in the task group or when the
+task group exits.  The library is one instance per task group, so its
+constructors run once in each task group, however many of its modules
+name it.
 
 Destructors are walked from ``DT_FINI_ARRAY`` at unload, in
 ``libelf_uninit()``, and not from ``crt0``, so they run once whichever way
diff --git a/Documentation/os/binfmt/kernel_modules_vs_shared_libraries.rst 
b/Documentation/os/binfmt/kernel_modules_vs_shared_libraries.rst
index e945f98f09f..e7d42890717 100644
--- a/Documentation/os/binfmt/kernel_modules_vs_shared_libraries.rst
+++ b/Documentation/os/binfmt/kernel_modules_vs_shared_libraries.rst
@@ -97,7 +97,7 @@ implemented as a thin wrapper around the same module library 
that the kernel
 module support uses:
 
 * ``dlopen()`` loads the library, or takes an additional reference on it if
-  it is already loaded, and returns a handle to it. See
+  it is already loaded in the task group, and returns a handle to it. See
   `Opening a Library More Than Once`_.
 * ``dlclose()`` releases one reference. The library is unloaded, as
   ``rmmod()`` would, only when the last handle is closed.
@@ -139,12 +139,16 @@ FLAT build.
 Opening a Library More Than Once
 ================================
 
-In the FLAT and PROTECTED builds, ``dlopen()`` of a library that is already
+In the FLAT and PROTECTED builds, each task group has its own list of
+loaded libraries. ``dlopen()`` of a library that the task group already
 loaded does not load a second copy and does not fail. It returns a handle to
 the library that is already loaded and takes an additional reference on it.
 Each successful ``dlopen()`` must be matched by a ``dlclose()``; the library
 is unloaded only when the last handle is closed. Up to 255 handles may be
 outstanding on one library; beyond that ``dlopen()`` fails with ``EMFILE``.
+The libraries that a task group did not close are closed when it exits.
+In the PROTECTED build only ``exit()`` closes them, so a task group that
+ends in another way leaves them loaded.
 
 Some consequences worth keeping in mind:
 
@@ -152,27 +156,35 @@ Some consequences worth keeping in mind:
   ``dlopen()``. Two files with the same basename in different directories
   are treated as the same library, and the second ``dlopen()`` will return
   the first one.
-* There is only one instance of the library's ``.data`` and ``.bss``. Global
-  and static data are shared by every user of the library, and by every task
-  group in the system.
-* Constructors in ``.init_array`` run once, when the library is first loaded,
-  and destructors in ``.fini_array`` run once, when the last handle is
-  closed. They do not run per ``dlopen()``/``dlclose()`` pair.
+* Each task group that opens a library loads its own copy. Global and static
+  data are shared by the threads of one task group, not between task groups.
+  Only an FDPIC library executed in place from xipfs shares its ``.text``
+  between task groups.
+* Constructors in ``.init_array`` run once per task group, when the library
+  is first loaded in it, and destructors in ``.fini_array`` run once, when
+  its last handle in the task group is closed. They do not run per
+  ``dlopen()``/``dlclose()`` pair.
+* The libraries that a program loaded by ``exec()`` names in ``DT_NEEDED``
+  belong to its task group in the FLAT build, so ``dlopen()`` of one of them
+  returns the copy that the program uses.
 * Symbols obtained with ``dlsym()`` remain valid until the last handle is
   closed, not until the caller's own handle is closed.
 
-Kernel modules deliberately behave differently: ``insmod()`` fails with
-``EEXIST`` if a module of that name is already installed, and ``rmmod()``
-removes it immediately. A kernel module is a singleton and is not reference
-counted.
+Kernel modules deliberately behave differently: there is one list of them
+for the system, ``insmod()`` fails with ``EEXIST`` if a module of that name
+is already installed, and ``rmmod()`` removes it immediately. A kernel module
+is a singleton and is not reference counted. ``/proc/modules`` shows the
+kernel modules only.
 
 
 Better FLAT and PROTECTED Mode Shared Libraries
 ===============================================
 
+Each NuttX task group has its own copy of a library, ``.text`` included,
+except for an FDPIC library executed in place.
 A better implementation of shared libraries in the FLAT and PROTECTED builds
-would, however, have a separate copy of the ``.bss`` and ``.data`` region
-for each NuttX task group.
+would have a separate copy of only the ``.bss`` and ``.data`` region for each
+task group, and one ``.text`` for all of them.
 
 A task group is the moral equivalent of a Unix process.
 That is how a shared library would have to work in uClinux, for example.

Reply via email to