Skip to content

posix: signal: APIs implementation #60083

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jul 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions doc/services/portability/posix.rst
Original file line number Diff line number Diff line change
Expand Up @@ -376,16 +376,17 @@ required for error and event handling.
pause(),
raise(),
sigaction(),
igaddset(),
sigdelset(),
sigemptyset(),
sigfillset(),
igismember(),
sigaddset(),yes
sigdelset(),yes
sigemptyset(),yes
sigfillset(),yes
sigismember(),yes
signal(),
sigpending(),
sigprocmask(),
igsuspend(),
sigwait()
sigwait(),
strsignal(),yes

.. csv-table:: POSIX_SPIN_LOCKS
:header: API, Supported
Expand Down
51 changes: 51 additions & 0 deletions include/zephyr/posix/signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,57 @@
extern "C" {
#endif

#ifdef CONFIG_POSIX_SIGNAL
#define SIGHUP 1 /**< Hangup */
#define SIGINT 2 /**< Interrupt */
#define SIGQUIT 3 /**< Quit */
#define SIGILL 4 /**< Illegal instruction */
#define SIGTRAP 5 /**< Trace/breakpoint trap */
#define SIGABRT 6 /**< Aborted */
#define SIGBUS 7 /**< Bus error */
#define SIGFPE 8 /**< Arithmetic exception */
#define SIGKILL 9 /**< Killed */
#define SIGUSR1 10 /**< User-defined signal 1 */
#define SIGSEGV 11 /**< Invalid memory reference */
#define SIGUSR2 12 /**< User-defined signal 2 */
#define SIGPIPE 13 /**< Broken pipe */
#define SIGALRM 14 /**< Alarm clock */
#define SIGTERM 15 /**< Terminated */
/* 16 not used */
#define SIGCHLD 17 /**< Child status changed */
#define SIGCONT 18 /**< Continued */
#define SIGSTOP 19 /**< Stop executing */
#define SIGTSTP 20 /**< Stopped */
#define SIGTTIN 21 /**< Stopped (read) */
#define SIGTTOU 22 /**< Stopped (write) */
#define SIGURG 23 /**< Urgent I/O condition */
#define SIGXCPU 24 /**< CPU time limit exceeded */
#define SIGXFSZ 25 /**< File size limit exceeded */
#define SIGVTALRM 26 /**< Virtual timer expired */
#define SIGPROF 27 /**< Profiling timer expired */
/* 28 not used */
#define SIGPOLL 29 /**< Pollable event occurred */
/* 30 not used */
#define SIGSYS 31 /**< Bad system call */

#define SIGRTMIN 32
#define SIGRTMAX (SIGRTMIN + CONFIG_POSIX_RTSIG_MAX)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you should define RTSIG_MAX to be CONFIG_POSIX_RTSIG_MAX in <limits.h> and that it must be at least 8.

https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this Kconfig will make the implementation of limits.h a bit easier, but I think limits.h can probably be in another PR

Copy link
Member

@cfriedt cfriedt Jul 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that sounds like it's getting close to sysconf(). There is another PR in draft for that, so I can add RTSIG_MAX separately.

#define _NSIG (SIGRTMAX + 1)

BUILD_ASSERT(CONFIG_POSIX_RTSIG_MAX >= 0);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

POSIX says 8; that could get checked here or Kconfig, or just stick a note in Kconfig indicating what will make the system POSIX compliant.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added Kconfig.limits to specify the default limit to be posix compliant, but user can freely changes this Kconfig to be anything >= 0, let me know what you think about this approach

These Kconfigs serve as direct translation when we implement limits.h in the future

cc @cfriedt

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds perfect -- tell people how to make POSIX compliant systems, but also allow them to reduce resources if desired.


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);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set, int signo);
#endif /* CONFIG_POSIX_SIGNAL */

#ifndef SIGEV_NONE
#define SIGEV_NONE 1
#endif
Expand Down
17 changes: 17 additions & 0 deletions lib/posix/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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
)
Expand All @@ -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
Expand All @@ -29,6 +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 ${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)
Expand Down
2 changes: 2 additions & 0 deletions lib/posix/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,12 @@ source "lib/posix/Kconfig.fnmatch"
source "lib/posix/Kconfig.fs"
source "lib/posix/Kconfig.getopt"
source "lib/posix/Kconfig.key"
source "lib/posix/Kconfig.limits"
source "lib/posix/Kconfig.mqueue"
source "lib/posix/Kconfig.mutex"
source "lib/posix/Kconfig.pthread"
source "lib/posix/Kconfig.semaphore"
source "lib/posix/Kconfig.signal"
source "lib/posix/Kconfig.spinlock"
source "lib/posix/Kconfig.timer"
source "lib/posix/Kconfig.uname"
13 changes: 13 additions & 0 deletions lib/posix/Kconfig.limits
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright (c) 2023 Meta
#
# SPDX-License-Identifier: Apache-2.0

if POSIX_SIGNAL
config POSIX_LIMITS_RTSIG_MAX
int "_POSIX_RTSIG_MAX value in limits.h"
default 8
help
Define the _POSIX_RTSIG_MAX value in limits.h.
IEEE 1003.1 defines this to be 8.

endif
26 changes: 26 additions & 0 deletions lib/posix/Kconfig.signal
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright (c) 2023 Meta
#
# SPDX-License-Identifier: Apache-2.0

config POSIX_SIGNAL
bool "Support for POSIX signal APIs"
default y if POSIX_API
help
Enable support for POSIX signal APIs.

if POSIX_SIGNAL
config POSIX_RTSIG_MAX
int "Maximum number of realtime signals"
default 31
help
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
101 changes: 101 additions & 0 deletions lib/posix/signal.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright (c) 2023 Meta
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "posix/strsignal_table.h"

#include <errno.h>
#include <stdio.h>

#include <zephyr/posix/signal.h>

#define SIGNO_WORD_IDX(_signo) (signo / BITS_PER_LONG)
#define SIGNO_WORD_BIT(_signo) (signo & BIT_MASK(LOG2(BITS_PER_LONG)))

BUILD_ASSERT(CONFIG_POSIX_LIMITS_RTSIG_MAX >= 0);
BUILD_ASSERT(CONFIG_POSIX_RTSIG_MAX >= CONFIG_POSIX_LIMITS_RTSIG_MAX);

static inline bool signo_valid(int signo)
{
return ((signo > 0) && (signo < _NSIG));
}

static inline bool signo_is_rt(int signo)
{
return ((signo >= SIGRTMIN) && (signo <= SIGRTMAX));
}

int sigemptyset(sigset_t *set)
{
*set = (sigset_t){0};
return 0;
}

int sigfillset(sigset_t *set)
{
for (int i = 0; i < ARRAY_SIZE(set->sig); i++) {
set->sig[i] = -1;
}

return 0;
}

int sigaddset(sigset_t *set, int signo)
{
if (!signo_valid(signo)) {
errno = EINVAL;
return -1;
}

WRITE_BIT(set->sig[SIGNO_WORD_IDX(signo)], SIGNO_WORD_BIT(signo), 1);

return 0;
}

int sigdelset(sigset_t *set, int signo)
{
if (!signo_valid(signo)) {
errno = EINVAL;
return -1;
}

WRITE_BIT(set->sig[SIGNO_WORD_IDX(signo)], SIGNO_WORD_BIT(signo), 0);

return 0;
}

int sigismember(const sigset_t *set, int signo)
{
if (!signo_valid(signo)) {
errno = EINVAL;
return -1;
}

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;
}
92 changes: 92 additions & 0 deletions scripts/build/gen_strsignal_table.py
Original file line number Diff line number Diff line change
@@ -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 <zephyr/posix/signal.h>
'''


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()
16 changes: 9 additions & 7 deletions scripts/checkpatch.pl
Original file line number Diff line number Diff line change
Expand Up @@ -4150,13 +4150,15 @@ sub process {

# check for new typedefs, only function parameters and sparse annotations
# make sense.
if ($line =~ /\btypedef\s/ &&
$line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ &&
$line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ &&
$line !~ /\b$typeTypedefs\b/ &&
$line !~ /\b__bitwise\b/) {
WARN("NEW_TYPEDEFS",
"do not add new typedefs\n" . $herecurr);
if ($realfile =~ /\/include\/zephyr\/posix\/*.h/) {
if ($line =~ /\btypedef\s/ &&
$line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ &&
$line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ &&
$line !~ /\b$typeTypedefs\b/ &&
$line !~ /\b__bitwise\b/) {
WARN("NEW_TYPEDEFS",
"do not add new typedefs\n" . $herecurr);
}
}

# * goes on variable not on type
Expand Down
2 changes: 2 additions & 0 deletions tests/posix/common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(posix_common)

FILE(GLOB app_sources src/*.c)
zephyr_include_directories(${ZEPHYR_BASE}/lib/posix)

target_sources(app PRIVATE ${app_sources})
Loading