github.com/MangoDowner/go-gm@v0.0.0-20180818020936-8baa2bd4408c/misc/cgo/testcarchive/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 127 verbose = argc > 1; 128 setvbuf(stdout, NULL, _IONBF, 0); 129 130 // Call setsid so that we can use kill(0, SIGIO) below. 131 // Don't check the return value so that this works both from 132 // a job control shell and from a shell script. 133 setsid(); 134 135 if (verbose) { 136 printf("calling RunGoroutines\n"); 137 } 138 139 RunGoroutines(); 140 141 // Block SIGIO in this thread to make it more likely that it 142 // will be delivered to a goroutine. 143 144 if (verbose) { 145 printf("calling pthread_sigmask\n"); 146 } 147 148 if (sigemptyset(&mask) < 0) { 149 die("sigemptyset"); 150 } 151 if (sigaddset(&mask, SIGIO) < 0) { 152 die("sigaddset"); 153 } 154 i = pthread_sigmask(SIG_BLOCK, &mask, NULL); 155 if (i != 0) { 156 fprintf(stderr, "pthread_sigmask: %s\n", strerror(i)); 157 exit(EXIT_FAILURE); 158 } 159 160 if (verbose) { 161 printf("calling kill\n"); 162 } 163 164 if (kill(0, SIGIO) < 0) { 165 die("kill"); 166 } 167 168 if (verbose) { 169 printf("waiting for sigioSeen\n"); 170 } 171 172 // Wait until the signal has been delivered. 173 i = 0; 174 while (!sigioSeen) { 175 ts.tv_sec = 0; 176 ts.tv_nsec = 1000000; 177 nanosleep(&ts, NULL); 178 i++; 179 if (i > 5000) { 180 fprintf(stderr, "looping too long waiting for SIGIO\n"); 181 exit(EXIT_FAILURE); 182 } 183 } 184 185 if (verbose) { 186 printf("provoking SIGPIPE\n"); 187 } 188 189 GoRaiseSIGPIPE(); 190 191 if (verbose) { 192 printf("waiting for sigpipeSeen\n"); 193 } 194 195 // Wait until the signal has been delivered. 196 i = 0; 197 while (!sigpipeSeen) { 198 ts.tv_sec = 0; 199 ts.tv_nsec = 1000000; 200 nanosleep(&ts, NULL); 201 i++; 202 if (i > 5000) { 203 fprintf(stderr, "looping too long waiting for SIGPIPE\n"); 204 exit(EXIT_FAILURE); 205 } 206 } 207 208 if (verbose) { 209 printf("calling setjmp\n"); 210 } 211 212 // Test that a SIGSEGV on this thread is delivered to us. 213 if (setjmp(jmp) == 0) { 214 if (verbose) { 215 printf("triggering SIGSEGV\n"); 216 } 217 218 *nullPointer = '\0'; 219 220 fprintf(stderr, "continued after address error\n"); 221 exit(EXIT_FAILURE); 222 } 223 224 if (verbose) { 225 printf("calling TestSEGV\n"); 226 } 227 228 TestSEGV(); 229 230 printf("PASS\n"); 231 return 0; 232 }