libc: Implement quick_exit and at_quick_exit

Defined by c11:
https://en.cppreference.com/w/c/program/quick_exit
https://en.cppreference.com/w/c/program/at_quick_exit

Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
This commit is contained in:
Xiang Xiao 2023-01-21 00:23:16 +08:00 committed by Petro Karashchenko
parent d7ee492fc4
commit bcd1ebf260
5 changed files with 118 additions and 6 deletions

View File

@ -51,8 +51,10 @@ namespace std
// Process exit functions // Process exit functions
using ::exit; using ::exit;
using ::quick_exit;
using ::abort; using ::abort;
using ::atexit; using ::atexit;
using ::at_quick_exit;
using ::on_exit; using ::on_exit;
#ifndef __KERNEL__ #ifndef __KERNEL__

View File

@ -26,6 +26,7 @@
****************************************************************************/ ****************************************************************************/
#include <nuttx/config.h> #include <nuttx/config.h>
#include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
/**************************************************************************** /****************************************************************************
@ -44,6 +45,7 @@ enum atexit_type_e
{ {
ATTYPE_NONE, ATTYPE_NONE,
ATTYPE_ATEXIT, ATTYPE_ATEXIT,
ATTYPE_ATQUICKEXIT,
ATTYPE_ONEXIT, ATTYPE_ONEXIT,
ATTYPE_CXA ATTYPE_CXA
}; };
@ -106,10 +108,10 @@ int atexit_register(int type, CODE void (*func)(void), FAR void *arg,
* *
****************************************************************************/ ****************************************************************************/
void atexit_call_exitfuncs(int status); void atexit_call_exitfuncs(int status, bool quick);
#else #else
# define atexit_register(type, func, arg, dso) (0) # define atexit_register(type, func, arg, dso) (0)
# define atexit_call_exitfuncs(status) # define atexit_call_exitfuncs(status, quick)
#endif /* CONFIG_LIBC_MAX_EXITFUNS */ #endif /* CONFIG_LIBC_MAX_EXITFUNS */
#if defined(__cplusplus) #if defined(__cplusplus)

View File

@ -166,8 +166,10 @@ int unsetenv(FAR const char *name);
/* Process exit functions */ /* Process exit functions */
void exit(int status) noreturn_function; void exit(int status) noreturn_function;
void quick_exit(int status) noreturn_function;
void abort(void) noreturn_function; void abort(void) noreturn_function;
int atexit(CODE void (*func)(void)); int atexit(CODE void (*func)(void));
int at_quick_exit(CODE void (*func)(void));
int on_exit(CODE void (*func)(int, FAR void *), FAR void *arg); int on_exit(CODE void (*func)(int, FAR void *), FAR void *arg);
/* _Exit() is a stdlib.h equivalent to the unistd.h _exit() function */ /* _Exit() is a stdlib.h equivalent to the unistd.h _exit() function */

View File

@ -50,7 +50,7 @@
* *
****************************************************************************/ ****************************************************************************/
static FAR struct atexit_list_s * get_exitfuncs(void) static FAR struct atexit_list_s *get_exitfuncs(void)
{ {
FAR struct task_info_s *info; FAR struct task_info_s *info;
@ -105,7 +105,7 @@ int atexit_register(int type, CODE void (*func)(void), FAR void *arg,
return ret; return ret;
} }
void atexit_call_exitfuncs(int status) void atexit_call_exitfuncs(int status, bool quick)
{ {
FAR struct atexit_list_s *aehead; FAR struct atexit_list_s *aehead;
CODE void (*func)(void); CODE void (*func)(void);
@ -134,9 +134,14 @@ void atexit_call_exitfuncs(int status)
continue; continue;
} }
if (quick != (type == ATTYPE_ATQUICKEXIT))
{
continue;
}
/* Call the atexit/on_exit/cxa_atexit() function */ /* Call the atexit/on_exit/cxa_atexit() function */
if (type == ATTYPE_ATEXIT) if (type == ATTYPE_ATEXIT || type == ATTYPE_ATQUICKEXIT)
{ {
(*func)(); (*func)();
} }
@ -181,3 +186,23 @@ int atexit(CODE void (*func)(void))
{ {
return atexit_register(ATTYPE_ATEXIT, func, NULL, NULL); return atexit_register(ATTYPE_ATEXIT, func, NULL, NULL);
} }
/****************************************************************************
* Name: at_quick_exit
*
* Description:
* Registers the function pointed to by func to be called on quick
* program termination (via quick_exit).
*
* Input Parameters:
* func - A pointer to the function to be called when the task exits.
*
* Returned Value:
* Zero on success. Non-zero on failure.
*
****************************************************************************/
int at_quick_exit(CODE void (*func)(void))
{
return atexit_register(ATTYPE_ATQUICKEXIT, func, NULL, NULL);
}

View File

@ -46,11 +46,47 @@ FAR void *__dso_handle = &__dso_handle;
* Public Functions * Public Functions
****************************************************************************/ ****************************************************************************/
/****************************************************************************
* Name: exit
*
* Description:
* The exit() function causes normal process termination and the
* least significant byte of status (i.e., status & 0xFF) is
* returned to the parent (see wait(2)).
*
* All functions registered with atexit(3) and on_exit(3) are
* called, in the reverse order of their registration. (It is
* possible for one of these functions to use atexit(3) or
* on_exit(3) to register an additional function to be executed
* during exit processing; the new registration is added to the
* front of the list of functions that remain to be called.) If one
* of these functions does not return (e.g., it calls _exit(2), or
* kills itself with a signal), then none of the remaining functions
* is called, and further exit processing (in particular, flushing
* of stdio(3) streams) is abandoned. If a function has been
* registered multiple times using atexit(3) or on_exit(3), then it
* is called as many times as it was registered.
*
* All open stdio(3) streams are flushed and closed. Files created
* by tmpfile(3) are removed.
*
* The C standard specifies two constants, EXIT_SUCCESS and
* EXIT_FAILURE, that may be passed to exit() to indicate successful
* or unsuccessful termination, respectively.
*
* Input Parameters:
* status - Exit status code
*
* Returned Value:
* Does not return.
*
****************************************************************************/
void exit(int status) void exit(int status)
{ {
/* Run the registered exit functions */ /* Run the registered exit functions */
atexit_call_exitfuncs(status); atexit_call_exitfuncs(status, false);
/* Flush all streams */ /* Flush all streams */
@ -61,6 +97,51 @@ void exit(int status)
_exit(status); _exit(status);
} }
/****************************************************************************
* Name: quick_exit
*
* Description:
* The quick_exit() function exits the program quickly calling any cleanup
* functions registered with at_quick_exit(3) but not any C++ destructors
* or cleanup code registered with atexit(3). The stdio(3) file buffers
* are not flushed.
*
* Input Parameters:
* status - Exit status code
*
* Returned Value:
* Does not return.
*
****************************************************************************/
void quick_exit(int status)
{
/* Run the registered exit functions */
atexit_call_exitfuncs(status, true);
/* Then perform the exit */
_exit(status);
}
/****************************************************************************
* Name: _Exit
*
* Description:
* The _Exit() functions shall not call functions registered with atexit()
* nor any registered signal handlers. Open streams shall not be flushed.
* Whether open streams are closed (without flushing) is implementation
* defined.
*
* Input Parameters:
* status - Exit status code
*
* Returned Value:
* Does not return.
*
****************************************************************************/
void _Exit(int status) void _Exit(int status)
{ {
_exit(status); _exit(status);