github.com/guyezi/gofrontend@v0.0.0-20200228202240-7a62a49e62c0/libgo/misc/cgo/testcarchive/testdata/main2.c (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Test installing a signal handler before the Go code starts. 6 // This is a lot like misc/cgo/testcshared/main4.c. 7 8 #include <setjmp.h> 9 #include <signal.h> 10 #include <stdarg.h> 11 #include <stddef.h> 12 #include <stdio.h> 13 #include <stdint.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <sys/types.h> 17 #include <unistd.h> 18 #include <sched.h> 19 #include <time.h> 20 #include <errno.h> 21 22 #include "libgo2.h" 23 24 static void die(const char* msg) { 25 perror(msg); 26 exit(EXIT_FAILURE); 27 } 28 29 static volatile sig_atomic_t sigioSeen; 30 static volatile sig_atomic_t sigpipeSeen; 31 32 // Use up some stack space. 33 static void recur(int i, char *p) { 34 char a[1024]; 35 36 *p = '\0'; 37 if (i > 0) { 38 recur(i - 1, a); 39 } 40 } 41 42 static void pipeHandler(int signo, siginfo_t* info, void* ctxt) { 43 sigpipeSeen = 1; 44 } 45 46 // Signal handler that uses up more stack space than a goroutine will have. 47 static void ioHandler(int signo, siginfo_t* info, void* ctxt) { 48 char a[1024]; 49 50 recur(4, a); 51 sigioSeen = 1; 52 } 53 54 static jmp_buf jmp; 55 static char* nullPointer; 56 57 // An arbitrary function which requires proper stack alignment; see 58 // http://golang.org/issue/17641. 59 static void callWithVarargs(void* dummy, ...) { 60 va_list args; 61 va_start(args, dummy); 62 va_end(args); 63 } 64 65 // Signal handler for SIGSEGV on a C thread. 66 static void segvHandler(int signo, siginfo_t* info, void* ctxt) { 67 sigset_t mask; 68 int i; 69 70 // Call an arbitrary function that requires the stack to be properly aligned. 71 callWithVarargs("dummy arg", 3.1415); 72 73 if (sigemptyset(&mask) < 0) { 74 die("sigemptyset"); 75 } 76 if (sigaddset(&mask, SIGSEGV) < 0) { 77 die("sigaddset"); 78 } 79 i = sigprocmask(SIG_UNBLOCK, &mask, NULL); 80 if (i != 0) { 81 fprintf(stderr, "sigprocmask: %s\n", strerror(i)); 82 exit(EXIT_FAILURE); 83 } 84 85 // Don't try this at home. 86 longjmp(jmp, signo); 87 88 // We should never get here. 89 abort(); 90 } 91 92 // Set up the signal handlers in a high priority constructor, 93 // so that they are installed before the Go code starts. 94 95 static void init(void) __attribute__ ((constructor (200))); 96 97 static void init() { 98 struct sigaction sa; 99 100 memset(&sa, 0, sizeof sa); 101 sa.sa_sigaction = ioHandler; 102 if (sigemptyset(&sa.sa_mask) < 0) { 103 die("sigemptyset"); 104 } 105 sa.sa_flags = SA_SIGINFO; 106 if (sigaction(SIGIO, &sa, NULL) < 0) { 107 die("sigaction"); 108 } 109 110 sa.sa_sigaction = segvHandler; 111 if (sigaction(SIGSEGV, &sa, NULL) < 0 || sigaction(SIGBUS, &sa, NULL) < 0) { 112 die("sigaction"); 113 } 114 115 sa.sa_sigaction = pipeHandler; 116 if (sigaction(SIGPIPE, &sa, NULL) < 0) { 117 die("sigaction"); 118 } 119 } 120 121 int main(int argc, char** argv) { 122 int verbose; 123 sigset_t mask; 124 int i; 125 struct timespec ts; 126 int darwin; 127 128 darwin = atoi(argv[1]); 129 130 verbose = argc > 2; 131 132 setvbuf(stdout, NULL, _IONBF, 0); 133 134 // Call setsid so that we can use kill(0, SIGIO) below. 135 // Don't check the return value so that this works both from 136 // a job control shell and from a shell script. 137 setsid(); 138 139 if (verbose) { 140 printf("calling RunGoroutines\n"); 141 } 142 143 RunGoroutines(); 144 145 // Block SIGIO in this thread to make it more likely that it 146 // will be delivered to a goroutine. 147 148 if (verbose) { 149 printf("calling pthread_sigmask\n"); 150 } 151 152 if (sigemptyset(&mask) < 0) { 153 die("sigemptyset"); 154 } 155 if (sigaddset(&mask, SIGIO) < 0) { 156 die("sigaddset"); 157 } 158 i = pthread_sigmask(SIG_BLOCK, &mask, NULL); 159 if (i != 0) { 160 fprintf(stderr, "pthread_sigmask: %s\n", strerror(i)); 161 exit(EXIT_FAILURE); 162 } 163 164 if (verbose) { 165 printf("calling kill\n"); 166 } 167 168 if (kill(0, SIGIO) < 0) { 169 die("kill"); 170 } 171 172 if (verbose) { 173 printf("waiting for sigioSeen\n"); 174 } 175 176 // Wait until the signal has been delivered. 177 i = 0; 178 while (!sigioSeen) { 179 ts.tv_sec = 0; 180 ts.tv_nsec = 1000000; 181 nanosleep(&ts, NULL); 182 i++; 183 if (i > 5000) { 184 fprintf(stderr, "looping too long waiting for SIGIO\n"); 185 exit(EXIT_FAILURE); 186 } 187 } 188 189 if (verbose) { 190 printf("provoking SIGPIPE\n"); 191 } 192 193 // SIGPIPE is never forwarded on Darwin, see golang.org/issue/33384. 194 if (!darwin) { 195 GoRaiseSIGPIPE(); 196 197 if (verbose) { 198 printf("waiting for sigpipeSeen\n"); 199 } 200 201 // Wait until the signal has been delivered. 202 i = 0; 203 while (!sigpipeSeen) { 204 ts.tv_sec = 0; 205 ts.tv_nsec = 1000000; 206 nanosleep(&ts, NULL); 207 i++; 208 if (i > 5000) { 209 fprintf(stderr, "looping too long waiting for SIGPIPE\n"); 210 exit(EXIT_FAILURE); 211 } 212 } 213 } 214 215 if (verbose) { 216 printf("calling setjmp\n"); 217 } 218 219 // Test that a SIGSEGV on this thread is delivered to us. 220 if (setjmp(jmp) == 0) { 221 if (verbose) { 222 printf("triggering SIGSEGV\n"); 223 } 224 225 *nullPointer = '\0'; 226 227 fprintf(stderr, "continued after address error\n"); 228 exit(EXIT_FAILURE); 229 } 230 231 if (verbose) { 232 printf("calling TestSEGV\n"); 233 } 234 235 TestSEGV(); 236 237 printf("PASS\n"); 238 return 0; 239 }