diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h index b183771e242..7d7d924e7f1 100644 --- a/include/nuttx/sched.h +++ b/include/nuttx/sched.h @@ -1033,6 +1033,26 @@ void nxtask_starthook(FAR struct task_tcb_s *tcb, starthook_t starthook, FAR void *arg); #endif +/******************************************************************************** + * Name: nxtask_startup + * + * Description: + * This function is the user-space, task startup function. It is called + * from up_task_start() in user-mode. + * + * Input Parameters: + * entrypt - The user-space address of the task entry point + * argc and argv - Standard arguments for the task entry point + * + * Returned Value: + * None. This function does not return. + * + ********************************************************************************/ + +#ifndef CONFIG_BUILD_KERNEL +void nxtask_startup(main_t entrypt, int argc, FAR char *argv[]); +#endif + /******************************************************************************** * Internal vfork support. The overall sequence is: * diff --git a/include/nuttx/userspace.h b/include/nuttx/userspace.h index 09ca6579a28..c535d6327bb 100644 --- a/include/nuttx/userspace.h +++ b/include/nuttx/userspace.h @@ -117,8 +117,7 @@ struct userspace_s /* Task/thread startup routines */ - CODE void (*task_startup)(main_t entrypt, int argc, FAR char *argv[]) - noreturn_function; + CODE void (*task_startup)(main_t entrypt, int argc, FAR char *argv[]); #ifndef CONFIG_DISABLE_PTHREAD CODE void (*pthread_startup)(pthread_startroutine_t entrypt, pthread_addr_t arg); @@ -152,27 +151,6 @@ extern "C" * Public Function Prototypes ****************************************************************************/ -/**************************************************************************** - * Name: nxtask_startup - * - * Description: - * This function is the user-space, task startup function. It is called - * from up_task_start() in user-mode. - * - * Input Parameters: - * entrypt - The user-space address of the task entry point - * argc and argv - Standard arguments for the task entry point - * - * Returned Value: - * None. This function does not return. - * - ****************************************************************************/ - -#ifndef __KERNEL__ -void nxtask_startup(main_t entrypt, int argc, FAR char *argv[]) - noreturn_function; -#endif - /**************************************************************************** * Name: pthread_startup * diff --git a/libs/libc/sched/Make.defs b/libs/libc/sched/Make.defs index c635f619c65..a143c68fef5 100644 --- a/libs/libc/sched/Make.defs +++ b/libs/libc/sched/Make.defs @@ -45,7 +45,7 @@ ifeq ($(CONFIG_SMP),y) CSRCS += sched_cpucount.c endif -ifeq ($(CONFIG_BUILD_PROTECTED),y) +ifneq ($(CONFIG_BUILD_KERNEL),y) CSRCS += task_startup.c endif diff --git a/libs/libc/sched/task_startup.c b/libs/libc/sched/task_startup.c index e9305558fa5..6c6f634ab47 100644 --- a/libs/libc/sched/task_startup.c +++ b/libs/libc/sched/task_startup.c @@ -39,12 +39,94 @@ #include +#include #include #include -#include +#ifndef CONFIG_BUILD_KERNEL -#if defined(CONFIG_BUILD_PROTECTED) && !defined(__KERNEL__) +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This type defines one entry in initialization array */ + +typedef CODE void (*initializer_t)(void); + +/**************************************************************************** + * External References + ****************************************************************************/ + +/* _sinit and _einit are symbols exported by the linker script that mark the + * beginning and the end of the C++ initialization section. + */ + +extern initializer_t _sinit; +extern initializer_t _einit; + +/* _stext and _etext are symbols exported by the linker script that mark the + * beginning and the end of text. + */ + +extern uintptr_t _stext; +extern uintptr_t _etext; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cxx_initialize + * + * Description: + * If C++ and C++ static constructors are supported, then this function + * must be provided by board-specific logic in order to perform + * initialization of the static C++ class instances. + * + * This function should then be called in the application-specific + * user_start logic in order to perform the C++ initialization. NOTE + * that no component of the core NuttX RTOS logic is involved; this + * function definition only provides the 'contract' between application + * specific C++ code and platform-specific toolchain support. + * + ****************************************************************************/ + +static void cxx_initialize(void) +{ +#ifdef CONFIG_HAVE_CXXINITIALIZE + static int inited = 0; + + if (inited == 0) + { + initializer_t *initp; + + sinfo("_sinit: %p _einit: %p _stext: %p _etext: %p\n", + &_sinit, &_einit, &_stext, &_etext); + + /* Visit each entry in the initialization table */ + + for (initp = &_sinit; initp != &_einit; initp++) + { + initializer_t initializer = *initp; + sinfo("initp: %p initializer: %p\n", initp, initializer); + + /* Make sure that the address is non-NULL and lies in the text + * region defined by the linker script. Some toolchains may put + * NULL values or counts in the initialization table. + */ + + if ((FAR void *)initializer >= (FAR void *)&_stext && + (FAR void *)initializer < (FAR void *)&_etext) + { + sinfo("Calling %p\n", initializer); + initializer(); + } + } + + inited = 1; + } +#endif +} /**************************************************************************** * Public Functions @@ -70,6 +152,12 @@ void nxtask_startup(main_t entrypt, int argc, FAR char *argv[]) { DEBUGASSERT(entrypt); + /* If C++ initialization for static constructors is supported, then do + * that first + */ + + cxx_initialize(); + /* Call the 'main' entry point passing argc and argv, calling exit() * if/when the task returns. */ @@ -77,4 +165,4 @@ void nxtask_startup(main_t entrypt, int argc, FAR char *argv[]) exit(entrypt(argc, argv)); } -#endif /* CONFIG_BUILD_PROTECTED && !__KERNEL__ */ +#endif /* !CONFIG_BUILD_KERNEL */ diff --git a/libs/libxx/Kconfig b/libs/libxx/Kconfig index f9eb934e4a3..1fd8004f343 100644 --- a/libs/libxx/Kconfig +++ b/libs/libxx/Kconfig @@ -22,6 +22,14 @@ config HAVE_CXX if HAVE_CXX +config HAVE_CXXINITIALIZE + bool "Have C++ initialization" + default n + ---help--- + The platform-specific logic includes support for initialization + of static C++ instances for this architecture and for the selected + toolchain (via up_cxxinitialize()). + config CXX_EXCEPTION bool diff --git a/sched/task/task_start.c b/sched/task/task_start.c index ccb3315529f..1ccace2ce84 100644 --- a/sched/task/task_start.c +++ b/sched/task/task_start.c @@ -89,7 +89,7 @@ void nxtask_start(void) { FAR struct task_tcb_s *tcb = (FAR struct task_tcb_s *)this_task(); - int exitcode; + int exitcode = EXIT_FAILURE; int argc; DEBUGASSERT((tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) != \ @@ -138,13 +138,14 @@ void nxtask_start(void) if ((tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_KERNEL) { up_task_start(tcb->cmn.entry.main, argc, tcb->argv); - exitcode = EXIT_FAILURE; /* Should not get here */ } else -#endif { exitcode = tcb->cmn.entry.main(argc, tcb->argv); } +#else + nxtask_startup(tcb->cmn.entry.main, argc, tcb->argv); +#endif /* Call exit() if/when the task returns */