nuttx/Documentation/os/scheduling/kernel_threads_vs_pthreads.rst
Vinicius May f6ecf80ebb Documentation: brand new layout for NuttX documentation.
The documentation grew one page at a time, so the tree follows the
history of who wrote what and not the shape of NuttX. Scheduling is
spread over three places, a driver page can sit above the subsystem
that owns it, and the front page lists everything at the same level.
That is a lot to face when all you want to know is where the scheduler
lives.

This change files every page under the code it describes. It is a move,
not a rewrite: outside the ten pages named below, every page keeps the
text that is already in master, and no page's text is deleted.

What it does:

* Groups the table of contents into nine chapters.
* Moves the OS subsystems under os/: scheduling, memory, drivers,
  filesystem, networking, IPC, interrupts, libs, time.
* Renames the platform pages to the names the source tree uses, and
  derives their tags from the tree instead of by hand.
* Splits guides/ by subject.
* Adds Documentation/redirects.py, with a rule for every page that left
  its old path, so old URLs keep working. The redirect page also carries
  a link's #anchor across to the new page.

Ten pages have text that is new or rewritten. Nine of them are the
landing page of a chapter, which has to exist for the new structure:

    index                  the front page
    os/index               OS Design
    os/scheduling/index    Scheduling
    os/interrupts/index    Interrupts
    os/ipc/index           IPC
    os/time/index          Time and timers
    about/index            About
    developing/index       Developing NuttX
    ReleaseNotes/index     Release notes

The tenth is os/libs/libbuiltin, the only page here with technical
content: libs/libbuiltin/ had no page at all. Five SVG diagrams come
with these pages, hand-written XML with no editor metadata.

Nothing outside Documentation/ is touched.

How it was checked:

* Sphinx builds with -W: no warnings, and no document left outside a
  toctree.
* A script, offered in the PR, proves the narrow claim this rests on.
  For every page outside the ten named above it erases what a move
  touches -- link target, path, tag line, toctree block, table border --
  from the whole old text and the whole new text, and requires the two
  to be byte for byte identical. It also requires every sentence of a
  deleted page to turn up somewhere, and every page that left its old
  path to have a redirect, from a URL that existed, to where its content
  went. It exits non-zero and names the page if any of that is not true,
  and it tests added pages too, so forgetting to declare one cannot make
  it pass.
* An independent audit checked 133 factual claims on these ten pages
  against the tree, one shell command per claim: 130 confirmed, 1
  refuted and fixed here, 2 not checkable.
* tools/checkpatch.sh is clean over the range.

The diff is large because moving a page changes every link that points
to it. Most of it is pure renames, and board pages that gained one tag
line.

Assisted-by: Claude:claude-opus-5
2026-10-08 01:40:54 +08:00

191 lines
7.4 KiB
ReStructuredText

.. _kernel-threads-vs-pthreads:
===========================
Kernel Threads vs. Pthreads
===========================
Why Can't Kernel Threads Have pthreads?
=======================================
Kernel threads are special "tasks" that reside within the OS.
They are similar to application tasks, so why can't they have pthreads
like application tasks?
The FLAT build
==============
In the FLAT build, kernel threads are, in fact, identical to application
threads except that:
1. They follow some slightly different syntax, AND
2. Can only use OS internal interfaces, never application interfaces.
Since they are otherwise identical, there is really no technical reason
why pthreads could not be supported.
The real reasons in this case is:
1. It is inappropriate, AND
2. It is incompatible with the PROTECTED and KERNEL builds where pthreads
cannot be supported.
Why inappropriate? Because..
pthread Interfaces Are User Interfaces
--------------------------------------
In all Unix systems, pthread interface support is not provided
by the operating system but rather by the user-facing C library.
The role of the OS is only to provide some low level hooks needed by
C library implementation of pthread interfaces.
But all of the implementation is in the C library and only for use
by applications.
That is not the current situation in NuttX.
Currently pthread support is deeply entangled in the OS.
This is problem that must be fixed someday and must not exploited as some
permanent feature of the OS. It is not.
It will go away some day when NuttX becomes a mature Unix-family system.
As user facing interfaces, pthread interfaces include some behaviors that
are not appropriate within the OS.
Inappropriate behaviors include modification of the ``errno`` value and
cancellation points. Those are user-only features.
While pthread interfaces do not, in general, modify the errno setting
they do create cancellation points which is not desirable within the OS.
PROTECTED and KERNEL Builds
---------------------------
The PROTECTED and KERNEL builds differ from the FLAT build in that they
segregate the memory into two regions:
A privileged kernel address space and unprivileged, user address space(s).
The primary difference is that the PROTECTED build uses a physical address
space and different regions of the physical address space have different
properties. This is usually accomplished using a Memory Protection Unit (MPU).
There is one protected kernel address space and one unprotected
user address space.
The KERNEL build, on the other hand, uses a Memory Management Unit (MMU)
to create a virtual address space in which there is still a separate
protected kernel address space, but many user address spaces for user
programs. These are usually called processes.
This is the familiar build model that you find with high-end Unix-like
systems such as Linux.
See Memory Configurations for additional information.
Address Spaces, Memory Allocators, and User Mode
------------------------------------------------
What would happen if you tried to create a pthread in the PROTECTED or KERNEL
build? The effect of these address space differences become very pronounced.
pthreads are, by their very definition, user-space threads.
That means that the OS will attempt to create a user-space environment
for the pthread: The thread's stack and other resources.
And when the pthread is started, it will be started in user mode,
not kernel mode.
It would require a significant change to the OS to alter that behavior
and that is not under consideration (because the change is also inappropriate).
Entry points
------------
Because the application space and the kernel space are separately built
and separately linked in the PROTECTED and KERNEL builds.
No application addresses are known by the kernel and no kernel addresses
are known by the application (applications interface via system call traps,
not C function calls). So what address would the kernel thread provide
for the pthread entry point? A known kernel space address?
Of course, the system would crash with a memory fault immediately
if a protected address were executed in user mode.
Mutexes
-------
Okay, so there are no kernel pthreads. But could other pthread resources
be usable in the kernel. The short answer is no.
Consider mutexes, for example. By definition, a mutex can only be used within
threads of the current process (or task groups as they are often called
in NuttX). They have no meaning outside of the task group.
Since the kernel thread "task group" can have no pthreads,
how could these mutexes be used under the proper standard definition
of what a mutex must be?
This is true of all pthread interfaces: None of the pthread interfaces were
intended from inter-process communications; only for inter-pthread
communications within the same process (task group).
Roadmap
=======
As alluded to before about the appropriateness of pthread in the OS.
There is a roadmap for these kinds of features.
That roadmap is to continue to conform strictly to the standard OS definitions
of <Opengroup.org>_ and to continue to evolve as a fully compliant,
very standard, tiny Unix-like operating system.
1. Part of this is getting all user interfaces out of the OS.
2. Another part is migrating all pthread support out of operating system
and into the user-facing C library.
3. An additional objective on the roadmap is to streamline the kernel threads
and to disconnect them from task groups.
Kernel threads should not be part of any task group.
In regard to this last point, the following is taken from Apache NuttX
Issue 1108: "Remove streams from Kernel Threads".
No Streams in Kernel Threads
----------------------------
Kernel threads are not permitted to use the C library buffer I/O, "stream",
interfaces. Those are interfaces like ``fopen()``, ``fread()``, ``fwrite()``,
``fclose()``, etc.
Those are strictly for use by user applications.
This is because these functions modify errno variables and create
cancellation points and perhaps other things that are undesirable
within the OS.
The thread create logic is largely the same for both kernel threads
and for application threads: They both allocate a large buffer
from the user memory pool for the stream ``FILE`` array.
Since kernel threads this is a waste of memory since the kernel threads
should not be using streams.
Remove Kernel Thread Stream Allocation
--------------------------------------
The proposal is to:
1. Verify that there is no use of streams within the OS,
2. Remove the stream allocation for kernel threads,
3. Assure that there are proper checks in place so that there are
no uses of the ``NULL`` stream array pointer.
For the most part, the OS is clean, there are essentially no use
of streams within the OS.
There are, however, a few violations of this that will need to be fixed;
``fopen()`` is called in some of the ``lc3850`` code.
Remove the File Descriptor Array Too
------------------------------------
A second phase would be to remove the file descriptor array from kernel
threads. File descriptors are, again, only for use by applications;
within the OS, file access is done using the struct file (aka, ``FILE``),
structure directly.
However, I suspect that there are many hidden uses of file descriptors
in the system.
For one, ``file_open()`` which opens the detached file, is not fully
implemented; it cheats and uses file descriptors.
So let's consider removal of the file descriptor allocation
as a second step after the stream allocations have been removed.