~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/powerpc/signal/sig_sc_double_restart.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  * Test that a syscall does not get restarted twice, handled by trap_norestart()
  4  *
  5  * Based on Al's description, and a test for the bug fixed in this commit:
  6  *
  7  * commit 9a81c16b527528ad307843be5571111aa8d35a80
  8  * Author: Al Viro <viro@zeniv.linux.org.uk>
  9  * Date:   Mon Sep 20 21:48:57 2010 +0100
 10  *
 11  *  powerpc: fix double syscall restarts
 12  *
 13  *  Make sigreturn zero regs->trap, make do_signal() do the same on all
 14  *  paths.  As it is, signal interrupting e.g. read() from fd 512 (==
 15  *  ERESTARTSYS) with another signal getting unblocked when the first
 16  *  handler finishes will lead to restart one insn earlier than it ought
 17  *  to.  Same for multiple signals with in-kernel handlers interrupting
 18  *  that sucker at the same time.  Same for multiple signals of any kind
 19  *  interrupting that sucker on 64bit...
 20  */
 21 #define _GNU_SOURCE
 22 #include <sys/types.h>
 23 #include <sys/wait.h>
 24 #include <sys/syscall.h>
 25 #include <unistd.h>
 26 #include <signal.h>
 27 #include <errno.h>
 28 #include <stdlib.h>
 29 #include <stdio.h>
 30 #include <string.h>
 31 
 32 #include "utils.h"
 33 
 34 static void SIGUSR1_handler(int sig)
 35 {
 36         kill(getpid(), SIGUSR2);
 37         /*
 38          * SIGUSR2 is blocked until the handler exits, at which point it will
 39          * be raised again and think there is a restart to be done because the
 40          * pending restarted syscall has 512 (ERESTARTSYS) in r3. The second
 41          * restart will retreat NIP another 4 bytes to fail case branch.
 42          */
 43 }
 44 
 45 static void SIGUSR2_handler(int sig)
 46 {
 47 }
 48 
 49 static ssize_t raw_read(int fd, void *buf, size_t count)
 50 {
 51         register long nr asm("r0") = __NR_read;
 52         register long _fd asm("r3") = fd;
 53         register void *_buf asm("r4") = buf;
 54         register size_t _count asm("r5") = count;
 55 
 56         asm volatile(
 57 "               b       0f              \n"
 58 "               b       1f              \n"
 59 "       0:      sc      0               \n"
 60 "               bns     2f              \n"
 61 "               neg     %0,%0           \n"
 62 "               b       2f              \n"
 63 "       1:                              \n"
 64 "               li      %0,%4           \n"
 65 "       2:                              \n"
 66                 : "+r"(_fd), "+r"(nr), "+r"(_buf), "+r"(_count)
 67                 : "i"(-ENOANO)
 68                 : "memory", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "ctr", "cr0");
 69 
 70         if (_fd < 0) {
 71                 errno = -_fd;
 72                 _fd = -1;
 73         }
 74 
 75         return _fd;
 76 }
 77 
 78 #define DATA "test 123"
 79 #define DLEN (strlen(DATA)+1)
 80 
 81 int test_restart(void)
 82 {
 83         int pipefd[2];
 84         pid_t pid;
 85         char buf[512];
 86 
 87         if (pipe(pipefd) == -1) {
 88                 perror("pipe");
 89                 exit(EXIT_FAILURE);
 90         }
 91 
 92         pid = fork();
 93         if (pid == -1) {
 94                 perror("fork");
 95                 exit(EXIT_FAILURE);
 96         }
 97 
 98         if (pid == 0) { /* Child reads from pipe */
 99                 struct sigaction act;
100                 int fd;
101 
102                 memset(&act, 0, sizeof(act));
103                 sigaddset(&act.sa_mask, SIGUSR2);
104                 act.sa_handler = SIGUSR1_handler;
105                 act.sa_flags = SA_RESTART;
106                 if (sigaction(SIGUSR1, &act, NULL) == -1) {
107                         perror("sigaction");
108                         exit(EXIT_FAILURE);
109                 }
110 
111                 memset(&act, 0, sizeof(act));
112                 act.sa_handler = SIGUSR2_handler;
113                 act.sa_flags = SA_RESTART;
114                 if (sigaction(SIGUSR2, &act, NULL) == -1) {
115                         perror("sigaction");
116                         exit(EXIT_FAILURE);
117                 }
118 
119                 /* Let's get ERESTARTSYS into r3 */
120                 while ((fd = dup(pipefd[0])) != 512) {
121                         if (fd == -1) {
122                                 perror("dup");
123                                 exit(EXIT_FAILURE);
124                         }
125                 }
126 
127                 if (raw_read(fd, buf, 512) == -1) {
128                         if (errno == ENOANO) {
129                                 fprintf(stderr, "Double restart moved restart before sc instruction.\n");
130                                 _exit(EXIT_FAILURE);
131                         }
132                         perror("read");
133                         exit(EXIT_FAILURE);
134                 }
135 
136                 if (strncmp(buf, DATA, DLEN)) {
137                         fprintf(stderr, "bad test string %s\n", buf);
138                         exit(EXIT_FAILURE);
139                 }
140 
141                 return 0;
142 
143         } else {
144                 int wstatus;
145 
146                 usleep(100000);         /* Hack to get reader waiting */
147                 kill(pid, SIGUSR1);
148                 usleep(100000);
149                 if (write(pipefd[1], DATA, DLEN) != DLEN) {
150                         perror("write");
151                         exit(EXIT_FAILURE);
152                 }
153                 close(pipefd[0]);
154                 close(pipefd[1]);
155                 if (wait(&wstatus) == -1) {
156                         perror("wait");
157                         exit(EXIT_FAILURE);
158                 }
159                 if (!WIFEXITED(wstatus)) {
160                         fprintf(stderr, "child exited abnormally\n");
161                         exit(EXIT_FAILURE);
162                 }
163 
164                 FAIL_IF(WEXITSTATUS(wstatus) != EXIT_SUCCESS);
165 
166                 return 0;
167         }
168 }
169 
170 int main(void)
171 {
172         test_harness_set_timeout(10);
173         return test_harness(test_restart, "sig sys restart");
174 }
175 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php