You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
376 lines
10 KiB
376 lines
10 KiB
commit 2e807f29595eb5b1e5d0decc6e356a3562ecc58e |
|
Author: Stefan Liebler <stli@linux.vnet.ibm.com> |
|
Date: Thu Mar 12 11:08:11 2015 +0100 |
|
|
|
S/390: Fix setcontext/swapcontext which are not restoring sigmask. |
|
|
|
[BZ #18080] |
|
|
|
diff --git a/stdlib/Makefile b/stdlib/Makefile |
|
index 5e99d7f..8f22c8d 100644 |
|
--- a/stdlib/Makefile |
|
+++ b/stdlib/Makefile |
|
@@ -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 |
|
--- /dev/null |
|
+++ b/stdlib/tst-setcontext2.c |
|
@@ -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 |
|
--- a/sysdeps/unix/sysv/linux/s390/s390-32/setcontext.S |
|
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/setcontext.S |
|
@@ -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 |
|
--- a/sysdeps/unix/sysv/linux/s390/s390-32/swapcontext.S |
|
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/swapcontext.S |
|
@@ -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 |
|
--- a/sysdeps/unix/sysv/linux/s390/s390-64/setcontext.S |
|
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/setcontext.S |
|
@@ -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 |
|
--- a/sysdeps/unix/sysv/linux/s390/s390-64/swapcontext.S |
|
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/swapcontext.S |
|
@@ -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. */
|
|
|