diff options
Diffstat (limited to 'stdlib')
-rw-r--r-- | stdlib/Makefile | 2 | ||||
-rw-r--r-- | stdlib/tst-setcontext4.c | 217 |
2 files changed, 218 insertions, 1 deletions
diff --git a/stdlib/Makefile b/stdlib/Makefile index bc8929f2b9..e3f2093544 100644 --- a/stdlib/Makefile +++ b/stdlib/Makefile @@ -85,7 +85,7 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \ test-at_quick_exit-race test-cxa_atexit-race \ test-on_exit-race test-dlclose-exit-race \ tst-makecontext-align test-bz22786 tst-strtod-nan-sign \ - tst-swapcontext1 + tst-swapcontext1 tst-setcontext4 tests-internal := tst-strtod1i tst-strtod3 tst-strtod4 tst-strtod5i \ tst-tls-atexit tst-tls-atexit-nodelete diff --git a/stdlib/tst-setcontext4.c b/stdlib/tst-setcontext4.c new file mode 100644 index 0000000000..64d3fc9137 --- /dev/null +++ b/stdlib/tst-setcontext4.c @@ -0,0 +1,217 @@ +/* Testcase checks, if setcontext(), swapcontext() restores signal-mask + and if pending signals are delivered after those calls. + Copyright (C) 2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <signal.h> +#include <ucontext.h> +#include <unistd.h> + +volatile int global; +volatile sig_atomic_t handlerCalled; + +static void +check (const char *funcName) +{ + sigset_t set; + + /* check if SIGUSR2 is unblocked after setcontext-call. */ + sigprocmask (SIG_BLOCK, NULL, &set); + + if (sigismember (&set, SIGUSR2) != 0) + { + printf ("FAIL: SIGUSR2 is blocked after %s.\n", funcName); + exit (1); + } + + if (sigismember (&set, SIGUSR1) != 1) + { + printf ("FAIL: SIGUSR1 is not blocked after %s.\n", funcName); + exit (1); + } +} + +static void +signalmask (int how, int signum) +{ + sigset_t set; + sigemptyset (&set); + sigaddset (&set, signum); + if (sigprocmask (how, &set, NULL) != 0) + { + printf ("FAIL: sigprocmaks (%d, %d, NULL): %m\n", how, signum); + exit (1); + } +} + +static void +signalpending (int signum, const char *msg) +{ + sigset_t set; + sigemptyset (&set); + if (sigpending (&set) != 0) + { + printf ("FAIL: sigpending: %m\n"); + exit (1); + } + if (sigismember (&set, SIGUSR2) != 1) + { + printf ("FAIL: Signal %d is not pending %s\n", signum, msg); + exit (1); + } +} + +static void +handler (int __attribute__ ((unused)) signum) +{ + handlerCalled ++; +} + +static int +do_test (void) +{ + ucontext_t ctx, oldctx; + struct sigaction action; + pid_t pid; + + pid = getpid (); + + /* unblock SIGUSR2 */ + signalmask (SIG_UNBLOCK, SIGUSR2); + + /* block SIGUSR1 */ + signalmask (SIG_BLOCK, SIGUSR1); + + /* register handler for SIGUSR2 */ + action.sa_flags = 0; + action.sa_handler = handler; + sigemptyset (&action.sa_mask); + sigaction (SIGUSR2, &action, NULL); + + if (getcontext (&ctx) != 0) + { + printf ("FAIL: getcontext: %m\n"); + exit (1); + } + + global++; + + if (global == 1) + { + puts ("after getcontext"); + + /* block SIGUSR2 */ + signalmask (SIG_BLOCK, SIGUSR2); + + /* send SIGUSR2 to me */ + handlerCalled = 0; + kill (pid, SIGUSR2); + + /* was SIGUSR2 handler called? */ + if (handlerCalled != 0) + { + puts ("FAIL: signal handler was called, but signal was blocked."); + exit (1); + } + + /* is SIGUSR2 pending? */ + signalpending (SIGUSR2, "before setcontext"); + + /* SIGUSR2 will be unblocked by setcontext-call. */ + if (setcontext (&ctx) != 0) + { + printf ("FAIL: setcontext: %m\n"); + exit (1); + } + } + else if (global == 2) + { + puts ("after setcontext"); + + /* check SIGUSR1/2 */ + check ("setcontext"); + + /* was SIGUSR2 handler called? */ + if (handlerCalled != 1) + { + puts ("FAIL: signal handler was not called after setcontext."); + exit (1); + } + + /* block SIGUSR2 */ + signalmask (SIG_BLOCK, SIGUSR2); + + /* send SIGUSR2 to me */ + handlerCalled = 0; + kill (pid, SIGUSR2); + + /* was SIGUSR2 handler called? */ + if (handlerCalled != 0) + { + puts ("FAIL: signal handler was called, but signal was blocked."); + exit (1); + } + + /* is SIGUSR2 pending? */ + signalpending (SIGUSR2, "before swapcontext"); + + if (swapcontext (&oldctx, &ctx) != 0) + { + printf ("FAIL: swapcontext: %m\n"); + exit (1); + } + + puts ("FAIL: returned from (&oldctx, &ctx)"); + exit (1); + } + else if ( global != 3 ) + { + puts ("FAIL: 'global' not incremented three times"); + exit (1); + } + + puts ("after swapcontext"); + /* check SIGUSR1/2 */ + check ("swapcontext"); + + /* was SIGUSR2 handler called? */ + if (handlerCalled != 1) + { + puts ("FAIL: signal handler was not called after swapcontext."); + exit (1); + } + + /* check sigmask in old context of swapcontext-call */ + if (sigismember (&oldctx.uc_sigmask, SIGUSR2) != 1) + { + puts ("FAIL: SIGUSR2 is not blocked in oldctx.uc_sigmask."); + exit (1); + } + + if (sigismember (&oldctx.uc_sigmask, SIGUSR1) != 1) + { + puts ("FAIL: SIGUSR1 is not blocked in oldctx.uc_sigmaks."); + exit (1); + } + + return 0; +} + +#include <support/test-driver.c> |