sched/arch/libc: make task_fork() optional

task_fork() is a NuttX extension, not POSIX, and a configuration that does
not call it has no reason to carry it.  Add CONFIG_TASK_FORK to leave it out.

It depends on ARCH_HAVE_TASK_FORK and defaults to y, so it is enabled exactly
where fork() existed before the split and no configuration loses the primitive
by upgrading.  ARCH_HAVE_TASK_FORK keeps its meaning -- the architecture *can*
clone the calling task -- and the new symbol says whether this build wants it.
Everything that provides task_fork() moves to the new symbol:  the declaration
in sched.h, up_task_fork() in arch.h, the two .csv entries that generate the
system call stub and proxy, the syscall_lookup.h table entry, the architecture
entry points, and the build rules for the files that hold them.

FORK_IS_TASK_FORK now depends on TASK_FORK rather than ARCH_HAVE_TASK_FORK.
Aliasing fork() to a task_fork() that was not built would not link.

vfork() and fork() are untouched; each is still selected on its own, and
task_fork.c, lib_fork.c and the architecture's fork file are still built when
any one of the three is present.

Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marco Casaroli 2026-07-30 11:03:54 +02:00
parent ca8287e690
commit 9b787d42b2
32 changed files with 70 additions and 46 deletions

View file

@ -42,7 +42,7 @@ There are now three distinct primitives:
* - ``task_fork()``
- child shares memory, private stack copy
- runs concurrently
- ``CONFIG_ARCH_HAVE_TASK_FORK`` -- exactly where ``fork()`` existed
- ``CONFIG_TASK_FORK`` -- on by default exactly where ``fork()`` existed
before
``task_fork()`` is the old behaviour under an honest name. Nothing was lost.
@ -122,6 +122,13 @@ Configuration symbols
Inherits exactly the ``select`` lines that ``ARCH_HAVE_FORK`` used to have,
so no configuration that had ``fork()`` loses the machinery.
``CONFIG_TASK_FORK``
Provide ``task_fork()``. Defaults to ``y`` wherever
``ARCH_HAVE_TASK_FORK`` is selected, so no configuration that had ``fork()``
loses the primitive. Turn it off to leave a NuttX extension out of a build
that does not call it; the architecture entry point, the system call and the
libc stub go with it. ``vfork()`` and ``fork()`` are unaffected.
``CONFIG_ARCH_HAVE_VFORK``
Hidden. The architecture can implement POSIX ``vfork()``.

View file

@ -435,10 +435,10 @@ Functions
under the name ``fork()`` before these three interfaces were separated, and
it is preserved here under an honest name so that nothing is lost.
NOTE: available where ``CONFIG_ARCH_HAVE_TASK_FORK`` is selected, which
is exactly the set of configurations that had ``fork()`` before the
split. New code should prefer :c:func:`pthread_create`, which is the
same memory relationship spelled clearly, or :c:func:`posix_spawn`;
NOTE: available where ``CONFIG_TASK_FORK`` is enabled, which defaults to
the set of configurations that had ``fork()`` before the split, and can
be turned off. New code should prefer :c:func:`pthread_create`, which
is the same memory relationship spelled clearly, or :c:func:`posix_spawn`;
``task_fork()`` exists to give the historical behaviour a truthful name,
not to recommend it.

View file

@ -534,10 +534,27 @@ config ARCH_HAVE_FORK
Where this is not selected fork() is not provided at all, and code
that calls it fails to build -- see FORK_IS_TASK_FORK.
config TASK_FORK
bool "Provide task_fork()"
default y
depends on ARCH_HAVE_TASK_FORK
---help---
Provide task_fork(), which clones the calling task: the child shares
the parent's .data/.bss/heap, runs on a private copy of the parent's
stack, and runs concurrently with the parent. This is the historical
NuttX fork() behaviour under its own name. It is not POSIX, and it is
neither fork() nor vfork().
Disable this to leave it out where nothing calls it. The saving is
small -- the architecture's entry point, the system call and the libc
stub -- but the primitive is a NuttX extension, so a configuration
that does not want it need not carry it. vfork() and fork() are
unaffected; each is selected on its own.
config FORK_IS_TASK_FORK
bool "Provide fork() as an alias for task_fork() (legacy)"
default n
depends on ARCH_HAVE_TASK_FORK && !ARCH_HAVE_FORK
depends on TASK_FORK && !ARCH_HAVE_FORK
---help---
Provide fork() on configurations that cannot implement POSIX fork()
semantics, by aliasing it to task_fork().

View file

@ -78,7 +78,7 @@
*
****************************************************************************/
#ifdef CONFIG_ARCH_HAVE_TASK_FORK
#ifdef CONFIG_TASK_FORK
.globl up_task_fork
#ifdef __ghs__
.type up_task_fork, $function

View file

@ -39,7 +39,7 @@
* Public Symbols
****************************************************************************/
#ifdef CONFIG_ARCH_HAVE_TASK_FORK
#ifdef CONFIG_TASK_FORK
PUBLIC up_task_fork
#endif
#ifdef CONFIG_ARCH_HAVE_VFORK
@ -100,7 +100,7 @@
THUMB
#ifdef CONFIG_ARCH_HAVE_TASK_FORK
#ifdef CONFIG_TASK_FORK
up_task_fork:
movs r2, #FORK_TYPE_TASK
b arm_fork_common

View file

@ -84,7 +84,7 @@
*
****************************************************************************/
#ifdef CONFIG_ARCH_HAVE_TASK_FORK
#ifdef CONFIG_TASK_FORK
GTEXT(up_task_fork)
SECTION_FUNC(text, up_task_fork)
mov x1, #FORK_TYPE_TASK

View file

@ -93,7 +93,7 @@
.set micromips
#endif
#ifdef CONFIG_ARCH_HAVE_TASK_FORK
#ifdef CONFIG_TASK_FORK
.globl up_task_fork
.type up_task_fork, function
.ent up_task_fork

View file

@ -86,7 +86,7 @@ if(CONFIG_STACK_COLORATION)
list(APPEND SRCS riscv_checkstack.c)
endif()
if(CONFIG_ARCH_HAVE_TASK_FORK
if(CONFIG_TASK_FORK
OR CONFIG_ARCH_HAVE_VFORK
OR CONFIG_ARCH_HAVE_FORK)
list(APPEND SRCS fork.S riscv_fork.c)

View file

@ -86,7 +86,7 @@ ifeq ($(CONFIG_STACK_COLORATION),y)
CMN_CSRCS += riscv_checkstack.c
endif
ifneq ($(CONFIG_ARCH_HAVE_TASK_FORK)$(CONFIG_ARCH_HAVE_VFORK)$(CONFIG_ARCH_HAVE_FORK),)
ifneq ($(CONFIG_TASK_FORK)$(CONFIG_ARCH_HAVE_VFORK)$(CONFIG_ARCH_HAVE_FORK),)
CMN_ASRCS += fork.S
CMN_CSRCS += riscv_fork.c
endif

View file

@ -39,7 +39,7 @@
.file "fork.S"
.globl riscv_fork
#ifdef CONFIG_ARCH_HAVE_TASK_FORK
#ifdef CONFIG_TASK_FORK
.globl up_task_fork
#endif
#ifdef CONFIG_ARCH_HAVE_VFORK
@ -89,7 +89,7 @@
*
****************************************************************************/
#ifdef CONFIG_ARCH_HAVE_TASK_FORK
#ifdef CONFIG_TASK_FORK
.type up_task_fork, function
up_task_fork:

View file

@ -41,7 +41,7 @@
#include "sched/sched.h"
#if defined(CONFIG_ARCH_HAVE_TASK_FORK) || defined(CONFIG_ARCH_HAVE_VFORK) || \
#if defined(CONFIG_TASK_FORK) || defined(CONFIG_ARCH_HAVE_VFORK) || \
defined(CONFIG_ARCH_HAVE_FORK)
/****************************************************************************
@ -351,5 +351,5 @@ pid_t riscv_fork(const struct fork_s *context, int type)
}
#endif /* CONFIG_LIB_SYSCALL */
#endif /* CONFIG_ARCH_HAVE_TASK_FORK || CONFIG_ARCH_HAVE_VFORK ||
#endif /* CONFIG_TASK_FORK || CONFIG_ARCH_HAVE_VFORK ||
* CONFIG_ARCH_HAVE_FORK */

View file

@ -95,7 +95,7 @@ ifeq ($(CONFIG_SCHED_BACKTRACE),y)
CSRCS += sim_backtrace.c
endif
ifneq ($(CONFIG_ARCH_HAVE_TASK_FORK)$(CONFIG_ARCH_HAVE_VFORK)$(CONFIG_ARCH_HAVE_FORK),)
ifneq ($(CONFIG_TASK_FORK)$(CONFIG_ARCH_HAVE_VFORK)$(CONFIG_ARCH_HAVE_FORK),)
CSRCS += sim_fork.c
endif

View file

@ -82,7 +82,7 @@ if(CONFIG_SCHED_BACKTRACE)
list(APPEND SRCS sim_backtrace.c)
endif()
if(CONFIG_ARCH_HAVE_TASK_FORK
if(CONFIG_TASK_FORK
OR CONFIG_ARCH_HAVE_VFORK
OR CONFIG_ARCH_HAVE_FORK)
list(APPEND SRCS sim_fork.c)

View file

@ -190,7 +190,7 @@ static pid_t sim_fork_internal(const xcpt_reg_t *context, int type)
*
****************************************************************************/
#ifdef CONFIG_ARCH_HAVE_TASK_FORK
#ifdef CONFIG_TASK_FORK
pid_t sim_task_fork(const xcpt_reg_t *context)
{
return sim_fork_internal(context, FORK_TYPE_TASK);

View file

@ -99,7 +99,7 @@
.text
#ifdef CONFIG_ARCH_HAVE_TASK_FORK
#ifdef CONFIG_TASK_FORK
.globl up_task_fork
.type up_task_fork, @function
up_task_fork:
@ -114,7 +114,7 @@ up_task_fork:
add sp, sp, #XCPTCONTEXT_SIZE
bx lr
.size up_task_fork, . - up_task_fork
#endif /* CONFIG_ARCH_HAVE_TASK_FORK */
#endif /* CONFIG_TASK_FORK */
#ifdef CONFIG_ARCH_HAVE_VFORK
.globl up_vfork

View file

@ -110,7 +110,7 @@
.text
.align 4
#ifdef CONFIG_ARCH_HAVE_TASK_FORK
#ifdef CONFIG_TASK_FORK
.globl SYMBOL(up_task_fork)
SYMBOL(up_task_fork):
@ -132,7 +132,7 @@ SYMBOL(up_task_fork):
ldp x29, x30, [sp] /* restore FP/LR register */
ret
#endif /* CONFIG_ARCH_HAVE_TASK_FORK */
#endif /* CONFIG_TASK_FORK */
#ifdef CONFIG_ARCH_HAVE_VFORK
.globl SYMBOL(up_vfork)

View file

@ -107,7 +107,7 @@
.text
#ifdef CONFIG_ARCH_HAVE_TASK_FORK
#ifdef CONFIG_TASK_FORK
.globl SYMBOL(up_task_fork)
#ifdef __ELF__
.type SYMBOL(up_task_fork), @function
@ -127,7 +127,7 @@ SYMBOL(up_task_fork):
#ifdef __ELF__
.size SYMBOL(up_task_fork), . - SYMBOL(up_task_fork)
#endif
#endif /* CONFIG_ARCH_HAVE_TASK_FORK */
#endif /* CONFIG_TASK_FORK */
#ifdef CONFIG_ARCH_HAVE_VFORK
.globl SYMBOL(up_vfork)

View file

@ -107,7 +107,7 @@
.text
#ifdef CONFIG_ARCH_HAVE_TASK_FORK
#ifdef CONFIG_TASK_FORK
.globl SYMBOL(up_task_fork)
#ifdef __ELF__
.type SYMBOL(up_task_fork), @function
@ -132,7 +132,7 @@ SYMBOL(up_task_fork):
#ifdef __ELF__
.size SYMBOL(up_task_fork), . - SYMBOL(up_task_fork)
#endif
#endif /* CONFIG_ARCH_HAVE_TASK_FORK */
#endif /* CONFIG_TASK_FORK */
#ifdef CONFIG_ARCH_HAVE_VFORK
.globl SYMBOL(up_vfork)

View file

@ -34,7 +34,7 @@ set(SRCS
x86_64_tcbinfo.c
x86_64_tlb.c)
if(CONFIG_ARCH_HAVE_TASK_FORK
if(CONFIG_TASK_FORK
OR CONFIG_ARCH_HAVE_VFORK
OR CONFIG_ARCH_HAVE_FORK)
list(APPEND SRCS x86_64_fork.c fork.S)

View file

@ -29,7 +29,7 @@ CMN_CSRCS += x86_64_getintstack.c x86_64_initialize.c x86_64_nputs.c
CMN_CSRCS += x86_64_modifyreg8.c x86_64_modifyreg16.c x86_64_modifyreg32.c
CMN_CSRCS += x86_64_switchcontext.c x86_64_tlb.c
ifneq ($(CONFIG_ARCH_HAVE_TASK_FORK)$(CONFIG_ARCH_HAVE_VFORK)$(CONFIG_ARCH_HAVE_FORK),)
ifneq ($(CONFIG_TASK_FORK)$(CONFIG_ARCH_HAVE_VFORK)$(CONFIG_ARCH_HAVE_FORK),)
CMN_CSRCS += x86_64_fork.c
CMN_ASRCS += fork.S
endif

View file

@ -95,7 +95,7 @@
* | ......... |
*/
#ifdef CONFIG_ARCH_HAVE_TASK_FORK
#ifdef CONFIG_TASK_FORK
.globl up_task_fork
.type up_task_fork, @function

View file

@ -265,7 +265,7 @@ extern initializer_t _einit[];
*
****************************************************************************/
#ifdef CONFIG_ARCH_HAVE_TASK_FORK
#ifdef CONFIG_TASK_FORK
pid_t up_task_fork(void);
#endif

View file

@ -239,7 +239,7 @@ int task_restart(pid_t pid);
* posix_spawn().
*/
#ifdef CONFIG_ARCH_HAVE_TASK_FORK
#ifdef CONFIG_TASK_FORK
pid_t task_fork(void);
#endif

View file

@ -112,7 +112,7 @@ SYSCALL_LOOKUP(nxsem_wait_slow, 1)
/* The following can be individually enabled */
#ifdef CONFIG_ARCH_HAVE_TASK_FORK
#ifdef CONFIG_TASK_FORK
SYSCALL_LOOKUP(up_task_fork, 0)
#endif

View file

@ -326,7 +326,7 @@
"swprintf","wchar.h","","int","FAR wchar_t *","size_t","FAR const wchar_t *","..."
"sysconf","unistd.h","","long","int"
"syslog","syslog.h","","void","int","FAR const IPTR char *","..."
"task_fork","sched.h","!defined(CONFIG_BUILD_KERNEL) && defined(CONFIG_ARCH_HAVE_TASK_FORK)","pid_t"
"task_fork","sched.h","!defined(CONFIG_BUILD_KERNEL) && defined(CONFIG_TASK_FORK)","pid_t"
"task_testcancel","sched.h","defined(CONFIG_CANCELLATION_POINTS)","void"
"task_tls_alloc","nuttx/tls.h","!defined(CONFIG_BUILD_KERNEL) && CONFIG_TLS_TASK_NELEM > 0","int","tls_dtor_t"
"task_tls_get_value","nuttx/tls.h","CONFIG_TLS_TASK_NELEM > 0","uintptr_t","int"

Can't render this file because it has a wrong number of fields in line 3.

View file

@ -102,7 +102,7 @@ if(NOT CONFIG_DISABLE_MOUNTPOINTS)
list(APPEND SRCS lib_truncate.c lib_posix_fallocate.c)
endif()
if(CONFIG_ARCH_HAVE_TASK_FORK
if(CONFIG_TASK_FORK
OR CONFIG_ARCH_HAVE_VFORK
OR CONFIG_ARCH_HAVE_FORK)
list(APPEND SRCS lib_fork.c)

View file

@ -53,7 +53,7 @@ ifneq ($(CONFIG_DISABLE_MOUNTPOINTS),y)
CSRCS += lib_truncate.c lib_posix_fallocate.c
endif
ifneq ($(CONFIG_ARCH_HAVE_TASK_FORK)$(CONFIG_ARCH_HAVE_VFORK)$(CONFIG_ARCH_HAVE_FORK),)
ifneq ($(CONFIG_TASK_FORK)$(CONFIG_ARCH_HAVE_VFORK)$(CONFIG_ARCH_HAVE_FORK),)
CSRCS += lib_fork.c
endif

View file

@ -35,7 +35,7 @@
#include <errno.h>
#include <nuttx/debug.h>
#if defined(CONFIG_ARCH_HAVE_TASK_FORK) || defined(CONFIG_ARCH_HAVE_VFORK) || \
#if defined(CONFIG_TASK_FORK) || defined(CONFIG_ARCH_HAVE_VFORK) || \
defined(CONFIG_ARCH_HAVE_FORK)
/****************************************************************************
@ -154,7 +154,7 @@ static void atfork_parent(void)
*
****************************************************************************/
#ifdef CONFIG_ARCH_HAVE_TASK_FORK
#ifdef CONFIG_TASK_FORK
pid_t task_fork(void)
{
pid_t pid;
@ -177,7 +177,7 @@ pid_t task_fork(void)
return pid;
}
#endif /* CONFIG_ARCH_HAVE_TASK_FORK */
#endif /* CONFIG_TASK_FORK */
/****************************************************************************
* Name: vfork
@ -280,5 +280,5 @@ pid_t fork(void)
}
#endif
#endif /* CONFIG_ARCH_HAVE_TASK_FORK || CONFIG_ARCH_HAVE_VFORK ||
#endif /* CONFIG_TASK_FORK || CONFIG_ARCH_HAVE_VFORK ||
* CONFIG_ARCH_HAVE_FORK */

View file

@ -46,7 +46,7 @@ if(CONFIG_SCHED_HAVE_PARENT)
list(APPEND SRCS task_getppid.c task_reparent.c)
endif()
if(CONFIG_ARCH_HAVE_TASK_FORK
if(CONFIG_TASK_FORK
OR CONFIG_ARCH_HAVE_VFORK
OR CONFIG_ARCH_HAVE_FORK)
list(APPEND SRCS task_fork.c)

View file

@ -30,7 +30,7 @@ ifeq ($(CONFIG_SCHED_HAVE_PARENT),y)
CSRCS += task_getppid.c task_reparent.c
endif
ifneq ($(CONFIG_ARCH_HAVE_TASK_FORK)$(CONFIG_ARCH_HAVE_VFORK)$(CONFIG_ARCH_HAVE_FORK),)
ifneq ($(CONFIG_TASK_FORK)$(CONFIG_ARCH_HAVE_VFORK)$(CONFIG_ARCH_HAVE_FORK),)
CSRCS += task_fork.c
endif

View file

@ -49,7 +49,7 @@
* built if the architecture can provide any one of them.
*/
#if defined(CONFIG_ARCH_HAVE_TASK_FORK) || defined(CONFIG_ARCH_HAVE_VFORK) || \
#if defined(CONFIG_TASK_FORK) || defined(CONFIG_ARCH_HAVE_VFORK) || \
defined(CONFIG_ARCH_HAVE_FORK)
/****************************************************************************
@ -649,5 +649,5 @@ void nxtask_abort_fork(FAR struct tcb_s *child, int errcode)
set_errno(errcode);
}
#endif /* CONFIG_ARCH_HAVE_TASK_FORK || CONFIG_ARCH_HAVE_VFORK ||
#endif /* CONFIG_TASK_FORK || CONFIG_ARCH_HAVE_VFORK ||
* CONFIG_ARCH_HAVE_FORK */

View file

@ -199,7 +199,7 @@
"unlink","unistd.h","!defined(CONFIG_DISABLE_MOUNTPOINT)","int","FAR const char *"
"unsetenv","stdlib.h","!defined(CONFIG_DISABLE_ENVIRON)","int","FAR const char *"
"up_fork","nuttx/arch.h","defined(CONFIG_ARCH_HAVE_FORK)","pid_t"
"up_task_fork","nuttx/arch.h","defined(CONFIG_ARCH_HAVE_TASK_FORK)","pid_t"
"up_task_fork","nuttx/arch.h","defined(CONFIG_TASK_FORK)","pid_t"
"up_vfork","nuttx/arch.h","defined(CONFIG_ARCH_HAVE_VFORK)","pid_t"
"utimens","sys/stat.h","","int","FAR const char *","const struct timespec [2]|FAR const struct timespec *"
"wait","sys/wait.h","defined(CONFIG_SCHED_WAITPID) && defined(CONFIG_SCHED_HAVE_PARENT)","pid_t","FAR int *"

Can't render this file because it has a wrong number of fields in line 2.