| commit c283946eb7d25a856563cc5cd7d09a151b6801d0 |
| Author: Stefan Liebler <stli@linux.vnet.ibm.com> |
| Date: Fri Jul 31 13:23:12 2015 +0200 |
| |
| S/390: Fix setcontext/swapcontext which are not restoring sigmask. |
| |
| 2015-03-12 Stefan Liebler <stli@linux.vnet.ibm.com> |
| |
| [BZ #18080] |
| * sysdeps/unix/sysv/linux/s390/s390-32/setcontext.S |
| (__setcontext): Use SIG_SETMASK instead of SIG_BLOCK. |
| * sysdeps/unix/sysv/linux/s390/s390-64/setcontext.S |
| (__setcontext): Likewise. |
| * sysdeps/unix/sysv/linux/s390/s390-32/swapcontext.S |
| (__swapcontext): Use SIG_SETMASK instead of SIG_BLOCK. |
| Call rt_sigprocmask syscall one time to set new signal mask |
| and retrieve the current signal mask instead of two calls. |
| * sysdeps/unix/sysv/linux/s390/s390-64/swapcontext.S |
| (__swapcontext): Likewise. |
| * stdlib/Makefile (tests): Add new testcase tst-setcontext2. |
| * stdlib/tst-setcontext2.c: New file. |
| |
| diff --git a/stdlib/Makefile b/stdlib/Makefile |
| index 5e99d7f..8f22c8d 100644 |
| |
| |
| @@ -64,10 +64,10 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \ |
| test-canon test-canon2 tst-strtoll tst-environ \ |
| tst-xpg-basename tst-random tst-random2 tst-bsearch \ |
| tst-limits tst-rand48 bug-strtod tst-setcontext \ |
| - test-a64l tst-qsort tst-system testmb2 bug-strtod2 \ |
| - tst-atof1 tst-atof2 tst-strtod2 tst-strtod3 tst-rand48-2 \ |
| - tst-makecontext tst-strtod4 tst-strtod5 tst-qsort2 \ |
| - tst-makecontext2 tst-strtod6 tst-unsetenv1 \ |
| + tst-setcontext2 test-a64l tst-qsort tst-system testmb2 \ |
| + bug-strtod2 tst-atof1 tst-atof2 tst-strtod2 tst-strtod3 \ |
| + tst-rand48-2 tst-makecontext tst-strtod4 tst-strtod5 \ |
| + tst-qsort2 tst-makecontext2 tst-strtod6 tst-unsetenv1 \ |
| tst-makecontext3 bug-getcontext bug-fmtmsg1 \ |
| tst-secure-getenv tst-strtod-overflow tst-strtod-round \ |
| tst-tininess tst-strtod-underflow |
| diff --git a/stdlib/tst-setcontext2.c b/stdlib/tst-setcontext2.c |
| new file mode 100644 |
| index 0000000..8582cc0 |
| |
| |
| @@ -0,0 +1,230 @@ |
| +/* Testcase checks, if setcontext(), swapcontext() restores signal-mask |
| + and if pending signals are delivered after those calls. |
| + Copyright (C) 2015 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 ("after returned from swapcontext"); |
| + |
| + if (global != 3) |
| + { |
| + puts ("FAIL: returned from swapcontext without ctx-context called."); |
| + exit (1); |
| + } |
| + |
| + puts ("test succeeded"); |
| + return 0; |
| + } |
| + 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); |
| + } |
| + |
| + /* change to old context, which was gathered by swapcontext() call. */ |
| + setcontext (&oldctx); |
| + |
| + puts ("FAIL: returned from setcontext (&oldctx)"); |
| + exit (1); |
| +} |
| + |
| +#define TEST_FUNCTION do_test () |
| +#include "../test-skeleton.c" |
| diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/setcontext.S b/sysdeps/unix/sysv/linux/s390/s390-32/setcontext.S |
| index b19fd8d..5f60f49 100644 |
| |
| |
| @@ -34,7 +34,7 @@ ENTRY(__setcontext) |
| lr %r1,%r2 |
| |
| /* sigprocmask (SIG_SETMASK, &sc->sc_mask, NULL). */ |
| - la %r2,SIG_BLOCK |
| + la %r2,SIG_SETMASK |
| la %r3,SC_MASK(%r1) |
| slr %r4,%r4 |
| lhi %r5,_NSIG8 |
| diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/swapcontext.S b/sysdeps/unix/sysv/linux/s390/s390-32/swapcontext.S |
| index 092f2bc..dc21b44 100644 |
| |
| |
| @@ -24,7 +24,7 @@ |
| /* __swapcontext (ucontext_t *oucp, const ucontext_t *ucp) |
| |
| Saves the machine context in oucp such that when it is activated, |
| - it appears as if __swapcontextt() returned again, restores the |
| + it appears as if __swapcontext() returned again, restores the |
| machine context in ucp and thereby resumes execution in that |
| context. |
| |
| @@ -36,13 +36,6 @@ ENTRY(__swapcontext) |
| lr %r1,%r2 |
| lr %r0,%r3 |
| |
| - /* sigprocmask (SIG_BLOCK, NULL, &sc->sc_mask). */ |
| - la %r2,SIG_BLOCK |
| - slr %r3,%r3 |
| - la %r4,SC_MASK(%r1) |
| - lhi %r5,_NSIG8 |
| - svc SYS_ify(rt_sigprocmask) |
| - |
| /* Store fpu context. */ |
| stfpc SC_FPC(%r1) |
| std %f0,SC_FPRS(%r1) |
| @@ -71,11 +64,12 @@ ENTRY(__swapcontext) |
| /* Store general purpose registers. */ |
| stm %r0,%r15,SC_GPRS(%r1) |
| |
| - /* sigprocmask (SIG_SETMASK, &sc->sc_mask, NULL). */ |
| - la %r2,SIG_BLOCK |
| + /* rt_sigprocmask (SIG_SETMASK, &ucp->uc_sigmask, &oucp->uc_sigmask, |
| + sigsetsize). */ |
| + la %r2,SIG_SETMASK |
| lr %r5,%r0 |
| la %r3,SC_MASK(%r5) |
| - slr %r4,%r4 |
| + la %r4,SC_MASK(%r1) |
| lhi %r5,_NSIG8 |
| svc SYS_ify(rt_sigprocmask) |
| |
| diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/setcontext.S b/sysdeps/unix/sysv/linux/s390/s390-64/setcontext.S |
| index b9a55ed..004eafc 100644 |
| |
| |
| @@ -34,7 +34,7 @@ ENTRY(__setcontext) |
| lgr %r1,%r2 |
| |
| /* sigprocmask (SIG_SETMASK, &sc->sc_mask, NULL). */ |
| - la %r2,SIG_BLOCK |
| + la %r2,SIG_SETMASK |
| la %r3,SC_MASK(%r1) |
| slgr %r4,%r4 |
| lghi %r5,_NSIG8 |
| diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/swapcontext.S b/sysdeps/unix/sysv/linux/s390/s390-64/swapcontext.S |
| index 6e2630c..2688762 100644 |
| |
| |
| @@ -24,7 +24,7 @@ |
| /* __swapcontext (ucontext_t *oucp, const ucontext_t *ucp) |
| |
| Saves the machine context in oucp such that when it is activated, |
| - it appears as if __swapcontextt() returned again, restores the |
| + it appears as if __swapcontext() returned again, restores the |
| machine context in ucp and thereby resumes execution in that |
| context. |
| |
| @@ -36,13 +36,6 @@ ENTRY(__swapcontext) |
| lgr %r1,%r2 |
| lgr %r0,%r3 |
| |
| - /* sigprocmask (SIG_BLOCK, NULL, &sc->sc_mask). */ |
| - la %r2,SIG_BLOCK |
| - slgr %r3,%r3 |
| - la %r4,SC_MASK(%r1) |
| - lghi %r5,_NSIG8 |
| - svc SYS_ify(rt_sigprocmask) |
| - |
| /* Store fpu context. */ |
| stfpc SC_FPC(%r1) |
| std %f0,SC_FPRS(%r1) |
| @@ -71,12 +64,13 @@ ENTRY(__swapcontext) |
| /* Store general purpose registers. */ |
| stmg %r0,%r15,SC_GPRS(%r1) |
| |
| - /* sigprocmask (SIG_SETMASK, &sc->sc_mask, NULL). */ |
| - la %r2,SIG_BLOCK |
| + /* rt_sigprocmask (SIG_SETMASK, &ucp->uc_sigmask, &oucp->uc_sigmask, |
| + sigsetsize). */ |
| + la %r2,SIG_SETMASK |
| lgr %r5,%r0 |
| la %r3,SC_MASK(%r5) |
| + la %r4,SC_MASK(%r1) |
| lghi %r5,_NSIG8 |
| - slgr %r4,%r4 |
| svc SYS_ify(rt_sigprocmask) |
| |
| /* Load fpu context. */ |