From 49df346fa1777b0d2bad82c9d0610c09be7e66a1 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Tue, 12 May 2015 12:39:21 -0600 Subject: [PATCH] Add a test of nested signals. There are no failures to handle signals but neither am I getting any nested signal handling --- examples/ostest/Makefile | 2 +- examples/ostest/ostest.h | 4 + examples/ostest/ostest_main.c | 4 + examples/ostest/signest.c | 453 ++++++++++++++++++++++++++++++++++ 4 files changed, 462 insertions(+), 1 deletion(-) create mode 100644 examples/ostest/signest.c diff --git a/examples/ostest/Makefile b/examples/ostest/Makefile index db18d467a..5831ad914 100644 --- a/examples/ostest/Makefile +++ b/examples/ostest/Makefile @@ -75,7 +75,7 @@ endif # CONFIG_MUTEX_TYPES endif # CONFIG_DISABLE_PTHREAD ifneq ($(CONFIG_DISABLE_SIGNALS),y) -CSRCS += sigprocmask.c sighand.c +CSRCS += sigprocmask.c sighand.c signest.c ifneq ($(CONFIG_DISABLE_PTHREAD),y) CSRCS += timedwait.c endif # CONFIG_DISABLE_PTHREAD diff --git a/examples/ostest/ostest.h b/examples/ostest/ostest.h index 97e1beea9..c9a04528f 100644 --- a/examples/ostest/ostest.h +++ b/examples/ostest/ostest.h @@ -175,6 +175,10 @@ void sigprocmask_test(void); void sighand_test(void); +/* signest.c ****************************************************************/ + +void signext_test(void); + /* posixtimers.c ************************************************************/ void timer_test(void); diff --git a/examples/ostest/ostest_main.c b/examples/ostest/ostest_main.c index 8c21af154..31136cd99 100644 --- a/examples/ostest/ostest_main.c +++ b/examples/ostest/ostest_main.c @@ -447,6 +447,10 @@ static int user_main(int argc, char *argv[]) printf("\nuser_main: signal handler test\n"); sighand_test(); check_test_memory_usage(); + + printf("\nuser_main: nested signal handler test\n"); + signest_test(); + check_test_memory_usage(); #endif #if !defined(CONFIG_DISABLE_POSIX_TIMERS) && !defined(CONFIG_DISABLE_SIGNALS) diff --git a/examples/ostest/signest.c b/examples/ostest/signest.c new file mode 100644 index 000000000..dc2ed9126 --- /dev/null +++ b/examples/ostest/signest.c @@ -0,0 +1,453 @@ +/*********************************************************************** + * apps/examples/ostest/signest.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ***********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ostest.h" + +/*********************************************************************** + * Pre-processor Definitions + ***********************************************************************/ + +#ifndef NULL +# define NULL (void*)0 +#endif + +#define WAKEUP_SIGNAL 17 +#define SIGVALUE_INT 42 + +/*********************************************************************** + * Private Data + ***********************************************************************/ + +static sem_t g_waiter_sem; +static sem_t g_interferer_sem; +static bool g_waiter_running; +static bool g_interferer_running; +static bool g_done; +static int g_nestlevel; + +static int g_even_signals; +static int g_odd_signals; +static int g_even_handled; +static int g_odd_handled; +static int g_even_nested; +static int g_odd_nested; + +static int g_nest_level; + +/*********************************************************************** + * Private Functions + ***********************************************************************/ + +static void waiter_action(int signo) +{ + int nest_level; + + sched_lock(); + nest_level = g_nest_level++; + sched_unlock(); + + if ((signo & 1) != 0) + { + g_odd_handled++; + if (nest_level > 0) + { + g_odd_nested++; + } + } + else + { + g_even_handled++; + if (nest_level > 0) + { + g_even_nested++; + } + } + + g_nest_level = nest_level; +} + +#ifdef CONFIG_BUILD_KERNEL +int main(int argc, FAR char *argv[]) +#else +static int waiter_main(int argc, char *argv[]) +#endif +{ + sigset_t sigset; + struct sigaction act; + int ret; + int i; + + printf("waiter_main: Waiter started\n" ); + printf("waiter_main: Setting signal mask\n" ); + + (void)sigemptyset(&sigset); + ret = sigprocmask(SIG_SETMASK, &sigset, NULL); + if (ret < 0) + { + printf("waiter_main: ERROR sigprocmask failed: %d\n", errno); + return EXIT_FAILURE; + } + + printf("waiter_main: Registering signal handler\n" ); + + act.sa_handler = waiter_action; + act.sa_flags = 0; + + (void)sigemptyset(&act.sa_mask); + for (i = 1; i < MAX_SIGNO; i += 2) + { + (void)sigaddset(&act.sa_mask, i); + } + + for (i = 1; i < MAX_SIGNO; i++) + { + ret = sigaction(i, &act, NULL); + if (ret < 0) + { + printf("waiter_main: ERROR sigaction failed\n" , errno); + return EXIT_FAILURE; + } + } + + /* Now just loop until the test completes */ + + printf("waiter_main: Waiting on semaphore\n" ); + FFLUSH(); + + g_waiter_running = true; + while (!g_done) + { + ret = sem_wait(&g_waiter_sem); + } + + /* Just exit, the system should clean up the signal handlers */ + + g_waiter_running = false; + return EXIT_SUCCESS; +} + +#ifdef CONFIG_BUILD_KERNEL +int main(int argc, FAR char *argv[]) +#else +static int interfere_main(int argc, char *argv[]) +#endif +{ + /* Now just loop staying in the way as much as possible */ + + printf("interfere_main: Waiting on semaphore\n" ); + FFLUSH(); + + g_interferer_running = true; + while (!g_done) + { + (void)sem_wait(&g_interferer_sem); + } + + /* Just exit, the system should clean up the signal handlers */ + + g_interferer_running = false; + return EXIT_SUCCESS; +} +/*********************************************************************** + * Public Functions + ***********************************************************************/ + +void signest_test(void) +{ + struct sched_param param; + pid_t waiterpid; + pid_t interferepid; + int total_signals; + int total_handled; + int total_nested; + int prio; + int ret; + int i; + int j; + + sem_init(&g_waiter_sem, 0, 0); + sem_init(&g_interferer_sem, 0, 0); + g_waiter_running = false; + g_interferer_running = false; + g_done = false; + g_nestlevel = 0; + + g_even_signals = 0; + g_odd_signals = 0; + g_even_handled = 0; + g_odd_handled = 0; + g_even_nested = 0; + g_odd_nested = 0; + + g_nest_level = 0; + + ret = sched_getparam (0, ¶m); + if (ret < 0) + { + printf("signest_test: ERROR sched_getparam() failed\n" ); + param.sched_priority = PTHREAD_DEFAULT_PRIORITY; + } + + /* Start waiter thread */ + + prio = param.sched_priority + 1; + printf("signest_test: Starting signal waiter task at priority %d\n", prio); + waiterpid = task_create("waiter", param.sched_priority, + PTHREAD_STACK_DEFAULT, waiter_main, NULL); + if (waiterpid == ERROR) + { + printf("signest_test: ERROR failed to start waiter_main\n"); + return; + } + + printf("signest_test: Started waiter_main pid=%d\n", waiterpid); + + /* Start interfering thread */ + + prio++; + printf("signest_test: Starting interfering task at priority %d\n", prio); + interferepid = task_create("interfere", param.sched_priority, + PTHREAD_STACK_DEFAULT, interfere_main, NULL); + if (interferepid == ERROR) + { + printf("signest_test: ERROR failed to start interfere_main\n"); + goto errout_with_waiter; + } + + printf("signest_test: Started interfere_main pid=%d\n", interferepid); + + /* Wait a bit */ + + FFLUSH(); + usleep(500*1000); + + /* Then signal the waiter thread with back-to-back signals, one masked and the other unmasked. */ + + for (i = 0; i < 10; i++) + { + for (j = 1; j < MAX_SIGNO; j += 2) + { + /* Odd then even */ + + kill(waiterpid, j); + kill(waiterpid, j+1); + + g_odd_signals++; + g_even_signals++; + + usleep(10*1000); + + /* Even then odd */ + + kill(waiterpid, j+1); + kill(waiterpid, j); + + g_odd_signals++; + g_even_signals++; + + usleep(10*1000); + } + } + + /* Check the test results so far */ + + total_signals = g_odd_signals + g_even_signals; + total_handled = g_odd_handled + g_even_handled; + total_nested = g_odd_nested + g_even_nested; + + printf("signest_test: Simple case:\n"); + printf(" Total signalled %-3d Odd=%-3d Even=%-3d\n", + total_signals, g_odd_signals, g_even_signals); + printf(" Total handled %-3d Odd=%-3d Even=%-3d\n", + total_handled, g_odd_handled, g_even_handled); + printf(" Total nested %-3d Odd=%-3d Even=%-3d\n", + total_nested, g_odd_nested, g_even_nested); + + /* Then signal the waiter thread with two signals pending. The + * sched_lock() assures that the first signal was not processed + * before the second was delivered. + */ + + for (i = 0; i < 10; i++) + { + for (j = 1; j < MAX_SIGNO; j += 2) + { + /* Odd then even */ + + sched_lock(); + kill(waiterpid, j); + kill(waiterpid, j+1); + + g_odd_signals++; + g_even_signals++; + sched_unlock(); + + usleep(10*1000); + + /* Even then odd */ + + sched_lock(); + kill(waiterpid, j+1); + kill(waiterpid, j); + + g_odd_signals++; + g_even_signals++; + sched_unlock(); + + usleep(10*1000); + } + } + + /* Check the test results so far */ + + total_signals = g_odd_signals + g_even_signals; + total_handled = g_odd_handled + g_even_handled; + total_nested = g_odd_nested + g_even_nested; + + printf("signest_test: With task locking\n"); + printf(" Total signalled %-3d Odd=%-3d Even=%-3d\n", + total_signals, g_odd_signals, g_even_signals); + printf(" Total handled %-3d Odd=%-3d Even=%-3d\n", + total_handled, g_odd_handled, g_even_handled); + printf(" Total nested %-3d Odd=%-3d Even=%-3d\n", + total_nested, g_odd_nested, g_even_nested); + + /* Then do it all over again with the interfering thread. */ + + for (i = 0; i < 10; i++) + { + for (j = 1; j < MAX_SIGNO; j += 2) + { + /* Odd then even */ + + sched_lock(); + kill(waiterpid, j); + sem_post(&g_interferer_sem); + kill(waiterpid, j+1); + + g_odd_signals++; + g_even_signals++; + sched_unlock(); + + usleep(10*1000); + + /* Even then odd */ + + sched_lock(); + kill(waiterpid, j+1); + sem_post(&g_interferer_sem); + kill(waiterpid, j); + + g_odd_signals++; + g_even_signals++; + sched_unlock(); + + usleep(10*1000); + } + } + + /* Stop the threads */ + +errout_with_waiter: + g_done = true; + sem_post(&g_waiter_sem); + sem_post(&g_interferer_sem); + usleep(500*1000); + + /* Check the final test results */ + + total_signals = g_odd_signals + g_even_signals; + total_handled = g_odd_handled + g_even_handled; + total_nested = g_odd_nested + g_even_nested; + + printf("signest_test: With intefering thread\n"); + printf(" Total signalled %-3d Odd=%-3d Even=%-3d\n", + total_signals, g_odd_signals, g_even_signals); + printf(" Total handled %-3d Odd=%-3d Even=%-3d\n", + total_handled, g_odd_handled, g_even_handled); + printf(" Total nested %-3d Odd=%-3d Even=%-3d\n", + total_nested, g_odd_nested, g_even_nested); + + /* Check for error */ + + if (g_waiter_running) + { + printf("signest_test: ERROR waiter is still running\n"); + } + + if (g_interferer_running) + { + printf("signest_test: ERROR interferer is still running\n"); + } + + if (total_signals != total_handled) + { + printf("signest_test: ERROR only %d of %d signals were handled\n", + total_handled, total_signals); + } + + if (g_odd_signals != g_odd_handled) + { + printf("signest_test: ERROR only %d of %d ODD signals were handled\n", + g_odd_handled, g_odd_signals); + } + + if (g_even_signals != g_even_handled) + { + printf("signest_test: ERROR only %d of %d EVEN signals were handled\n", + g_even_handled, g_even_signals); + } + + if (g_odd_nested > 0) + { + printf("signest_test: ERROR %d ODD signals were nested\n", + g_odd_nested); + } + + sem_destroy(&g_waiter_sem); + sem_destroy(&g_interferer_sem); + + printf("signest_test: done\n" ); + FFLUSH(); +}