From 13e9291b51b2298b1e3ac856311e0c06e9509a8c Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Mon, 25 Mar 2013 23:39:44 +0400 Subject: [PATCH] zdtm: add a test case for pending signals Signed-off-by: Andrey Vagin Signed-off-by: Pavel Emelyanov --- test/zdtm/live/static/Makefile | 3 + test/zdtm/live/static/sigpending.c | 232 +++++++++++++++++++++++++++++ 2 files changed, 235 insertions(+) create mode 100644 test/zdtm/live/static/sigpending.c diff --git a/test/zdtm/live/static/Makefile b/test/zdtm/live/static/Makefile index 398d2a9e2..e6c71c309 100644 --- a/test/zdtm/live/static/Makefile +++ b/test/zdtm/live/static/Makefile @@ -89,6 +89,7 @@ TST_NOFILE = \ cow00 \ child_opened_proc \ posix_timers \ + sigpending \ # jobctl00 \ TST_FILE = \ @@ -220,6 +221,7 @@ unlink_largefile: override CFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURC inotify_system_nodel: override CFLAGS += -DNODEL pthread00: override LDLIBS += -pthread pthread01: override LDLIBS += -pthread +sigpending: override LDLIBS += -pthread shm: override CFLAGS += -DNEW_IPC_NS msgque: override CFLAGS += -DNEW_IPC_NS sem: override CFLAGS += -DNEW_IPC_NS @@ -227,6 +229,7 @@ posix_timers: override LDLIBS += -lrt socket-tcp6: override CFLAGS += -D ZDTM_IPV6 socket-tcpbuf6: override CFLAGS += -D ZDTM_IPV6 socket_listen6: override CFLAGS += -D ZDTM_IPV6 +sigpending: override LDLIBS += -lrt $(LIB): force $(MAKE) -C $(LIBDIR) diff --git a/test/zdtm/live/static/sigpending.c b/test/zdtm/live/static/sigpending.c new file mode 100644 index 000000000..040c39b0c --- /dev/null +++ b/test/zdtm/live/static/sigpending.c @@ -0,0 +1,232 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include "zdtmtst.h" + +const char *test_doc = "Check pending signals"; +const char *test_author = "Andrew Vagin "; + +static pid_t child; +static int numsig; + +#define TESTSIG (SIGRTMAX) +#define THREADSIG (SIGRTMIN) +static siginfo_t share_infos[2]; +static siginfo_t self_infos[64]; /* self */ +static siginfo_t thread_infos[3]; /* thread */ +static int share_nr; +static int self_nr; +static int thread_nr; + +#ifndef offsetof +# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +static pthread_mutex_t exit_lock; +static pthread_mutex_t init_lock; + +static void sig_handler(int signal, siginfo_t *info, void *data) +{ + uint32_t crc; + + test_msg("signo=%d si_code=%x\n", signal, info->si_code); + + switch (signal) { + case SIGCHLD: + if ((info->si_code & CLD_EXITED) && + (info->si_pid == child) && + (info->si_status == 5)) + numsig++; + else { + fail("Wrong siginfo"); + exit(1); + } + return; + } + + if (TESTSIG == signal || THREADSIG == signal) { + siginfo_t *src; + + if (signal == TESTSIG) { + src = &share_infos[share_nr]; + share_nr++; + } else if (getpid() == syscall(SYS_gettid)) { + src = &self_infos[self_nr]; + self_nr++; + } else { + src = &thread_infos[thread_nr]; + thread_nr++; + } + + crc = ~0; + if (datachk((uint8_t *) &info->_sifields, + sizeof(siginfo_t) - offsetof(siginfo_t, _sifields), &crc)) { + fail("CRC mismatch\n"); + return; + } + + if (memcmp(info, src, sizeof(siginfo_t))) { + fail("Source and received info are differ\n"); + return; + } + + numsig++; + return; + } + + err("Unexpected signal"); + exit(1); +} + +static int thread_id; + +static void *thread_fn(void *args) +{ + sigset_t blockmask; + struct sigaction act; + + sigfillset(&blockmask); + sigdelset(&blockmask, SIGTERM); + + if (sigprocmask(SIG_BLOCK, &blockmask, NULL) == -1) { + err("sigprocmask"); + return NULL; + } + + thread_id = syscall(SYS_gettid); + + act.sa_flags = SA_SIGINFO | SA_RESTART; + act.sa_sigaction = sig_handler; + sigemptyset(&act.sa_mask); + + sigaddset(&act.sa_mask, TESTSIG); + sigaddset(&act.sa_mask, THREADSIG); + if (sigaction(TESTSIG, &act, NULL)) { + err("sigaction() failed\n"); + return NULL; + } + + pthread_mutex_unlock(&init_lock); + pthread_mutex_lock(&exit_lock); + + if (sigprocmask(SIG_UNBLOCK, &blockmask, NULL) == -1) { + err("sigprocmask"); + return NULL; + } + + return NULL; +} + +static int sent_sigs; + +int send_siginfo(int signo, pid_t pid, pid_t tid, int group, siginfo_t *info) +{ + static int si_code = -10; + uint32_t crc = ~0; + + info->si_code = si_code; + si_code--; + info->si_signo = signo; + datagen((uint8_t *) &info->_sifields, + sizeof(siginfo_t) - offsetof(siginfo_t, _sifields), &crc); + + sent_sigs++; + + if (group) + return syscall(SYS_rt_sigqueueinfo, pid, signo, info); + else + return syscall(SYS_rt_tgsigqueueinfo, pid, tid, signo, info); +} + +int main(int argc, char ** argv) +{ + sigset_t blockmask; + struct sigaction act; + pthread_t pthrd; + int i; + + test_init(argc, argv); + pthread_mutex_init(&exit_lock, NULL); + pthread_mutex_lock(&exit_lock); + pthread_mutex_init(&init_lock, NULL); + pthread_mutex_lock(&init_lock); + + if (pthread_create(&pthrd, NULL, thread_fn, NULL)) { + err("Can't create a thread"); + return 1; + } + + pthread_mutex_lock(&init_lock); + + sigfillset(&blockmask); + sigdelset(&blockmask, SIGTERM); + + if (sigprocmask(SIG_BLOCK, &blockmask, NULL) == -1) { + err("sigprocmask"); + return -1; + } + + child = fork(); + if (child == -1) { + err("fork"); + return -1; + } + + if(child == 0) + return 5; /* SIGCHLD */ + + sent_sigs++; + + for (i = 0; i < sizeof(share_infos) / sizeof(siginfo_t); i++) { + send_siginfo(TESTSIG, getpid(), -1, 1, share_infos + i); + } + + for (i = 0; i < sizeof(self_infos) / sizeof(siginfo_t); i++) { + send_siginfo(THREADSIG, getpid(), getpid(), 0, self_infos + i); + } + + for (i = 0; i < sizeof(thread_infos) / sizeof(siginfo_t); i++) { + send_siginfo(THREADSIG, getpid(), thread_id, 0, thread_infos + i); + } + + act.sa_flags = SA_SIGINFO | SA_RESTART; + act.sa_sigaction = sig_handler; + sigemptyset(&act.sa_mask); + + if (sigaction(SIGCHLD, &act, NULL)) { + err("sigaction() failed\n"); + return -1; + } + + sigaddset(&act.sa_mask, TESTSIG); + sigaddset(&act.sa_mask, THREADSIG); + if (sigaction(TESTSIG, &act, NULL)) { + err("sigaction() failed\n"); + return -1; + } + + if (sigaction(THREADSIG, &act, NULL)) { + err("sigaction() failed\n"); + return -1; + } + + test_daemon(); + + test_waitsig(); + + if (sigprocmask(SIG_UNBLOCK, &blockmask, NULL) == -1) { + err("sigprocmask"); + return -1; + } + pthread_mutex_unlock(&exit_lock); + pthread_join(pthrd, NULL); + + if (numsig == sent_sigs) + pass(); + + return 0; +}