diff --git a/doc/services/portability/posix.rst b/doc/services/portability/posix.rst index fb06cba1c75056..83d8c78cbcec03 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 d441e44fbc16c5..8b1bc33b7feca3 100644 --- a/include/zephyr/posix/signal.h +++ b/include/zephyr/posix/signal.h @@ -56,6 +56,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 ce5e809d04edc3..48bb598ef2d503 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 6da322073574d0..1f8e61fc9b2413 100644 --- a/lib/posix/Kconfig.signal +++ b/lib/posix/Kconfig.signal @@ -15,4 +15,11 @@ config POSIX_SIGNAL_NSIG help Define the maximum number of signal. +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 7eb889c3726441..a3d22b208b32b2 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 @@ -69,3 +72,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 00000000000000..b60b23237dc639 --- /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 75eeb537998d86..c206dc1882d2c9 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 + 1), "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 899bb8910bce19..8e2d75d5883cd2 100644 --- a/tests/posix/common/testcase.yaml +++ b/tests/posix/common/testcase.yaml @@ -80,3 +80,9 @@ tests: - CONFIG_SPIN_VALIDATE=n integration_platforms: - mps2_an385 + portability.posix.common.strsignal_no_desc: + extra_configs: + - CONFIG_POSIX_SIGNAL_STRING_DESC=n + portability.posix.common.strsignal_rtsig_gt_99: + extra_configs: + - CONFIG_POSIX_SIGNAL_NSIG=200 diff --git a/tests/posix/headers/src/signal_h.c b/tests/posix/headers/src/signal_h.c index f2a0c15b73c197..a320fac31af6e5 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)) {