diff --git a/doc/services/portability/posix.rst b/doc/services/portability/posix.rst index fb06cba1c75..83d8c78cbce 100644 --- a/doc/services/portability/posix.rst +++ b/doc/services/portability/posix.rst @@ -385,7 +385,8 @@ required for error and event handling. sigpending(), sigprocmask(), igsuspend(), - sigwait() + sigwait(), + strsignal(),yes .. csv-table:: POSIX_SPIN_LOCKS :header: API, Supported diff --git a/include/zephyr/posix/signal.h b/include/zephyr/posix/signal.h index 8c509954edd..0cfa5649b38 100644 --- a/include/zephyr/posix/signal.h +++ b/include/zephyr/posix/signal.h @@ -55,6 +55,7 @@ typedef struct { unsigned long sig[DIV_ROUND_UP(_NSIG, BITS_PER_LONG)]; } sigset_t; +char *strsignal(int signum); int sigemptyset(sigset_t *set); int sigfillset(sigset_t *set); int sigaddset(sigset_t *set, int signo); diff --git a/lib/posix/CMakeLists.txt b/lib/posix/CMakeLists.txt index ce5e809d04e..48bb598ef2d 100644 --- a/lib/posix/CMakeLists.txt +++ b/lib/posix/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +set(GEN_DIR ${ZEPHYR_BINARY_DIR}/include/generated) + zephyr_syscall_header( ${ZEPHYR_BASE}/include/zephyr/posix/time.h ) @@ -10,6 +12,20 @@ if(CONFIG_POSIX_API) zephyr_include_directories(${ZEPHYR_BASE}/include/zephyr/posix) endif() +if(CONFIG_POSIX_SIGNAL) + set(STRSIGNAL_TABLE_H ${GEN_DIR}/posix/strsignal_table.h) + + add_custom_command( + OUTPUT ${STRSIGNAL_TABLE_H} + COMMAND + ${PYTHON_EXECUTABLE} + ${ZEPHYR_BASE}/scripts/build/gen_strsignal_table.py + -i ${ZEPHYR_BASE}/include/zephyr/posix/signal.h + -o ${STRSIGNAL_TABLE_H} + DEPENDS ${ZEPHYR_BASE}/include/zephyr/posix/signal.h + ) +endif() + if(CONFIG_POSIX_API OR CONFIG_PTHREAD_IPC OR CONFIG_POSIX_CLOCK OR CONFIG_POSIX_MQUEUE OR CONFIG_POSIX_FS OR CONFIG_EVENTFD OR CONFIG_GETOPT) # This is a temporary workaround so that Newlib declares the appropriate @@ -29,7 +45,7 @@ zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK sleep.c) zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK timer.c) zephyr_library_sources_ifdef(CONFIG_POSIX_FS fs.c) zephyr_library_sources_ifdef(CONFIG_POSIX_MQUEUE mqueue.c) -zephyr_library_sources_ifdef(CONFIG_POSIX_SIGNAL signal.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_SIGNAL signal.c ${STRSIGNAL_TABLE_H}) zephyr_library_sources_ifdef(CONFIG_POSIX_UNAME uname.c) zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC _common.c) zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC barrier.c) diff --git a/lib/posix/Kconfig.signal b/lib/posix/Kconfig.signal index 3ff5b75e8e8..c51e68f1f36 100644 --- a/lib/posix/Kconfig.signal +++ b/lib/posix/Kconfig.signal @@ -16,4 +16,11 @@ config POSIX_RTSIG_MAX Define the maximum number of realtime signals (RTSIG_MAX). The range of realtime signals is [SIGRTMIN .. (SIGRTMIN+RTSIG_MAX)] +config POSIX_SIGNAL_STRING_DESC + bool "Use full description for the strsignal API" + default y + help + Use full description for the strsignal API. + Will use 256 bytes of ROM. + endif diff --git a/lib/posix/signal.c b/lib/posix/signal.c index 165d9aa9dbc..e1d7feab299 100644 --- a/lib/posix/signal.c +++ b/lib/posix/signal.c @@ -3,7 +3,10 @@ * * SPDX-License-Identifier: Apache-2.0 */ +#include "posix/strsignal_table.h" + #include +#include #include @@ -68,3 +71,28 @@ int sigismember(const sigset_t *set, int signo) return 1 & (set->sig[SIGNO_WORD_IDX(signo)] >> SIGNO_WORD_BIT(signo)); } + +char *strsignal(int signum) +{ + static char buf[sizeof("RT signal " STRINGIFY(SIGRTMAX))]; + + if (!signo_valid(signum)) { + errno = EINVAL; + return "Invalid signal"; + } + + if (signo_is_rt(signum)) { + snprintf(buf, sizeof(buf), "RT signal %d", signum - SIGRTMIN); + return buf; + } + + if (IS_ENABLED(CONFIG_POSIX_SIGNAL_STRING_DESC)) { + if (strsignal_list[signum] != NULL) { + return (char *)strsignal_list[signum]; + } + } + + snprintf(buf, sizeof(buf), "Signal %d", signum); + + return buf; +} diff --git a/scripts/build/gen_strsignal_table.py b/scripts/build/gen_strsignal_table.py new file mode 100755 index 00000000000..b60b23237dc --- /dev/null +++ b/scripts/build/gen_strsignal_table.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2023 Meta +# +# SPDX-License-Identifier: Apache-2.0 + +import argparse +import os +import re + + +def front_matter(): + return f''' +/* + * This file is generated by {__file__} + */ + +#include +''' + + +def gen_strsignal_table(input, output): + with open(input, 'r') as inf: + + highest_signo = 0 + symbols = [] + msgs = {} + + for line in inf.readlines(): + # Select items of the form below (note: SIGNO is numeric) + # #define SYMBOL SIGNO /**< MSG */ + pat = r'^#define[\s]+(SIG[A-Z_]*)[\s]+([1-9][0-9]*)[\s]+/\*\*<[\s]+(.*)[\s]+\*/[\s]*$' + match = re.match(pat, line) + + if not match: + continue + + symbol = match[1] + signo = int(match[2]) + msg = match[3] + + symbols.append(symbol) + msgs[symbol] = msg + + highest_signo = max(int(signo), highest_signo) + + try: + os.makedirs(os.path.dirname(output)) + except BaseException: + # directory already present + pass + + with open(output, 'w') as outf: + + print(front_matter(), file=outf) + + # Generate string table + print( + f'static const char *const strsignal_list[{highest_signo + 1}] = {{', file=outf) + for symbol in symbols: + print(f'\t[{symbol}] = "{msgs[symbol]}",', file=outf) + + print('};', file=outf) + + +def parse_args(): + parser = argparse.ArgumentParser(allow_abbrev=False) + parser.add_argument( + '-i', + '--input', + dest='input', + required=True, + help='input file (e.g. include/zephyr/posix/signal.h)') + parser.add_argument( + '-o', + '--output', + dest='output', + required=True, + help='output file (e.g. build/zephyr/misc/generated/lib/posix/strsignal_table.h)') + + args = parser.parse_args() + + return args + + +def main(): + args = parse_args() + gen_strsignal_table(args.input, args.output) + + +if __name__ == '__main__': + main() diff --git a/tests/posix/common/src/signal.c b/tests/posix/common/src/signal.c index 90fb001bc5b..79b78e5444e 100644 --- a/tests/posix/common/src/signal.c +++ b/tests/posix/common/src/signal.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -192,3 +193,26 @@ ZTEST(posix_apis, test_signal_ismember) zassert_equal(sigismember(&set, SIGKILL), 0, "%s not expected to be member", "SIGKILL"); zassert_equal(sigismember(&set, SIGTERM), 0, "%s not expected to be member", "SIGTERM"); } + +ZTEST(posix_apis, test_signal_strsignal) +{ + char buf[sizeof("RT signal " STRINGIFY(SIGRTMAX))] = {0}; + + zassert_mem_equal(strsignal(-1), "Invalid signal", sizeof("Invalid signal")); + zassert_mem_equal(strsignal(0), "Invalid signal", sizeof("Invalid signal")); + zassert_mem_equal(strsignal(_NSIG), "Invalid signal", sizeof("Invalid signal")); + + zassert_mem_equal(strsignal(30), "Signal 30", sizeof("Signal 30")); + snprintf(buf, sizeof(buf), "RT signal %d", SIGRTMIN - SIGRTMIN); + zassert_mem_equal(strsignal(SIGRTMIN), buf, strlen(buf)); + snprintf(buf, sizeof(buf), "RT signal %d", SIGRTMAX - SIGRTMIN); + zassert_mem_equal(strsignal(SIGRTMAX), buf, strlen(buf)); + +#ifdef CONFIG_POSIX_SIGNAL_STRING_DESC + zassert_mem_equal(strsignal(SIGHUP), "Hangup", sizeof("Hangup")); + zassert_mem_equal(strsignal(SIGSYS), "Bad system call", sizeof("Bad system call")); +#else + zassert_mem_equal(strsignal(SIGHUP), "Signal 1", sizeof("Signal 1")); + zassert_mem_equal(strsignal(SIGSYS), "Signal 31", sizeof("Signal 31")); +#endif +} diff --git a/tests/posix/common/testcase.yaml b/tests/posix/common/testcase.yaml index 899bb8910bc..e4b30e45ea6 100644 --- a/tests/posix/common/testcase.yaml +++ b/tests/posix/common/testcase.yaml @@ -80,3 +80,6 @@ tests: - CONFIG_SPIN_VALIDATE=n integration_platforms: - mps2_an385 + portability.posix.common.signal.strsignal_no_desc: + extra_configs: + - CONFIG_POSIX_SIGNAL_STRING_DESC=n diff --git a/tests/posix/headers/src/signal_h.c b/tests/posix/headers/src/signal_h.c index 5a78c0ec0a7..852cddf3df0 100644 --- a/tests/posix/headers/src/signal_h.c +++ b/tests/posix/headers/src/signal_h.c @@ -163,6 +163,7 @@ ZTEST(posix_headers, test_signal_h) zassert_not_null(sigaddset); zassert_not_null(sigdelset); zassert_not_null(sigismember); + zassert_not_null(strsignal); #endif /* CONFIG_POSIX_SIGNAL */ if (IS_ENABLED(CONFIG_POSIX_API)) {