build_by_default: program_tests)
exes += exe
+exe = executable(
+ 'test_sigstate',
+ 'tests/helpers/test_sigstate.c',
+ include_directories : includes,
+ link_with : lib_common,
+ build_by_default: program_tests)
+exes += exe
+
exe = executable(
'test_tiocsti',
'tests/helpers/test_tiocsti.c',
TS_HELPER_PATHS="${ts_helpersdir}test_pathnames"
TS_HELPER_SCRIPT="${ts_helpersdir}test_script"
TS_HELPER_SIGRECEIVE="${ts_helpersdir}test_sigreceive"
+TS_HELPER_SIGSTATE="${ts_helpersdir}test_sigstate"
TS_HELPER_STRERROR="${ts_helpersdir}test_strerror"
TS_HELPER_STRUTILS="${ts_helpersdir}test_strutils"
TS_HELPER_SYSINFO="${ts_helpersdir}test_sysinfo"
--- /dev/null
+decode "0x00000000000044aa":
+INT
+ILL
+ABRT
+FPE
+SEGV
+TERM
+decode "0x0000000000003015":
+HUP
+QUIT
+TRAP
+PIPE
+ALRM
+decode "0x0000000000000200":
+USR1
+Pending (thread): INT ILL
+Pending (process): USR1
+Blocked: INT ILL ABRT FPE USR1 SEGV TERM
+Ignored: HUP QUIT TRAP PIPE ALRM
+Caught: ILL USR1
test_sigreceive_SOURCES = tests/helpers/test_sigreceive.c
test_sigreceive_LDADD = $(LDADD) libcommon.la
+check_PROGRAMS += test_sigstate
+test_sigstate_SOURCES = tests/helpers/test_sigstate.c
+test_sigstate_LDADD = $(LDADD) libcommon.la
+
check_PROGRAMS += test_tiocsti
test_tiocsti_SOURCES = tests/helpers/test_tiocsti.c
--- /dev/null
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * test_sigstate - ...
+ *
+ * Written by Masatake YAMATO <yamato@redhat.com>
+ */
+
+#include "c.h"
+
+#include <signal.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <err.h>
+
+#define _U_ __attribute__((__unused__))
+
+static enum {
+ HANDLER_NONE,
+ HANDLER_WRITE,
+ HANDLER_READ
+} handler_state = HANDLER_NONE;
+
+static int ERRNO;
+
+static void handler(int signum _U_)
+{
+ char c;
+
+ if (write(1, "USR1\n", 5) == -1) {
+ handler_state = HANDLER_WRITE;
+ goto out;
+ }
+
+ if (read(0, &c, 1) != -1)
+ _exit(0);
+ handler_state = HANDLER_READ;
+
+ out:
+ ERRNO = errno;
+}
+
+int main(int argc _U_, char **argv _U_)
+{
+ sigset_t block_set;
+
+ sigemptyset(&block_set);
+ sigaddset(&block_set, SIGINT);
+ sigaddset(&block_set, SIGILL);
+ sigaddset(&block_set, SIGABRT);
+ sigaddset(&block_set, SIGFPE);
+ sigaddset(&block_set, SIGSEGV);
+ sigaddset(&block_set, SIGTERM);
+
+ if (sigprocmask(SIG_SETMASK, &block_set, NULL) == -1)
+ err(EXIT_FAILURE, "failed to mask signals");
+
+ raise(SIGINT);
+ raise(SIGILL);
+
+#define sigignore(S) if (signal(S, SIG_IGN) == SIG_ERR) \
+ err(EXIT_FAILURE, "failed to make " #S "ignored")
+
+ sigignore(SIGHUP);
+ sigignore(SIGQUIT);
+ sigignore(SIGTRAP);
+ sigignore(SIGPIPE);
+ sigignore(SIGALRM);
+
+ signal(SIGBUS, SIG_DFL);
+ signal(SIGFPE, SIG_DFL);
+ signal(SIGSEGV, SIG_DFL);
+ signal(32, SIG_DFL);
+ signal(33, SIG_DFL);
+
+ if (signal(SIGUSR1, handler) == SIG_ERR)
+ err(EXIT_FAILURE, "failed to set a signal handler for SIGUSR1");
+ if (signal(SIGILL, handler) == SIG_ERR)
+ err(EXIT_FAILURE, "failed to set a signal handler for SIGILL");
+
+ printf("%d\n", getpid());
+ if (fflush(stdout) == EOF)
+ err(EXIT_FAILURE, "failed to flush stdout");
+
+ pause();
+ if (ERRNO == 0)
+ errx(EXIT_FAILURE, "caught an unexpected signal");
+ errno = ERRNO;
+ errx(EXIT_FAILURE, "failed in %s an ack from the command invoker",
+ handler_state == HANDLER_WRITE? "writing": "reading");
+
+ return 0; /* UNREACHABLE */
+}
--- /dev/null
+#!/bin/bash
+
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="decode functions"
+
+. "$TS_TOPDIR/functions.sh"
+ts_init "$*"
+
+ts_skip_qemu_user
+
+ts_check_test_command "$TS_CMD_KILL"
+ts_check_test_command "$TS_HELPER_SIGSTATE"
+
+. "$TS_SELF/kill_functions.sh"
+
+decode()
+{
+ echo decode "\"$1\":"
+ "$TS_CMD_KILL" -l "$1"
+}
+
+PID=
+ACK=
+{
+ for d in 0x00000000000044aa \
+ 0x0000000000003015 \
+ 0x0000000000000200; do
+ decode "$d"
+ done
+
+ coproc SIGSTATE { "$TS_HELPER_SIGSTATE" ; }
+ if read -u ${SIGSTATE[0]} PID; then
+ "$TS_CMD_KILL" -USR1 "$PID"
+ if read -u ${SIGSTATE[0]} ACK; then
+ # The taget process is in its signal handler for USR1.
+ # Sending one more USR1 is for making the signal pending state.
+ "$TS_CMD_KILL" -USR1 "$PID"
+ "$TS_CMD_KILL" -d "$PID" | {
+ if [[ $("$TS_CMD_KILL" --list=34) == RT0 ]]; then
+ # See man signal(7).
+ # The Linux kernel supports a range of 33 different real-time signals,
+ # numbered 32 to 64. However, the glibc POSIX threads implementation in‐
+ # ternally uses two (for NPTL) or three (for LinuxThreads) real-time sig‐
+ # nals (see pthreads(7)), and adjusts the value of SIGRTMIN suitably (to
+ # 34 or 35).
+ sed -e s/' 32 33'// -e s/' 34'//
+ else
+ cat
+ fi
+ }
+ fi
+ echo DONE >&"${SIGSTATE[1]}"
+ fi
+ wait ${SIGSTATE_PID}
+} > "$TS_OUTPUT" 2>&1
+
+ts_finalize