github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/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 21 #include "libgo2.h" 22 23 static void die(const char* msg) { 24 perror(msg); 25 exit(EXIT_FAILURE); 26 } 27 28 static volatile sig_atomic_t sigioSeen; 29 30 // Use up some stack space. 31 static void recur(int i, char *p) { 32 char a[1024]; 33 34 *p = '\0'; 35 if (i > 0) { 36 recur(i - 1, a); 37 } 38 } 39 40 // Signal handler that uses up more stack space than a goroutine will have. 41 static void ioHandler(int signo, siginfo_t* info, void* ctxt) { 42 char a[1024]; 43 44 recur(4, a); 45 sigioSeen = 1; 46 } 47 48 static jmp_buf jmp; 49 static char* nullPointer; 50 51 // An arbitrary function which requires proper stack alignment; see 52 // http://golang.org/issue/17641. 53 static void callWithVarargs(void* dummy, ...) { 54 va_list args; 55 va_start(args, dummy); 56 va_end(args); 57 } 58 59 // Signal handler for SIGSEGV on a C thread. 60 static void segvHandler(int signo, siginfo_t* info, void* ctxt) { 61 sigset_t mask; 62 int i; 63 64 // Call an arbitrary function that requires the stack to be properly aligned. 65 callWithVarargs("dummy arg", 3.1415); 66 67 if (sigemptyset(&mask) < 0) { 68 die("sigemptyset"); 69 } 70 if (sigaddset(&mask, SIGSEGV) < 0) { 71 die("sigaddset"); 72 } 73 i = sigprocmask(SIG_UNBLOCK, &mask, NULL); 74 if (i != 0) { 75 fprintf(stderr, "sigprocmask: %s\n", strerror(i)); 76 exit(EXIT_FAILURE); 77 } 78 79 // Don't try this at home. 80 longjmp(jmp, signo); 81 82 // We should never get here. 83 abort(); 84 } 85 86 // Set up the signal handlers in a high priority constructor, 87 // so that they are installed before the Go code starts. 88 89 static void init(void) __attribute__ ((constructor (200))); 90 91 static void init() { 92 struct sigaction sa; 93 94 memset(&sa, 0, sizeof sa); 95 sa.sa_sigaction = ioHandler; 96 if (sigemptyset(&sa.sa_mask) < 0) { 97 die("sigemptyset"); 98 } 99 sa.sa_flags = SA_SIGINFO; 100 if (sigaction(SIGIO, &sa, NULL) < 0) { 101 die("sigaction"); 102 } 103 104 sa.sa_sigaction = segvHandler; 105 if (sigaction(SIGSEGV, &sa, NULL) < 0 || sigaction(SIGBUS, &sa, NULL) < 0) { 106 die("sigaction"); 107 } 108 109 } 110 111 int main(int argc, char** argv) { 112 int verbose; 113 sigset_t mask; 114 int i; 115 struct timespec ts; 116 117 verbose = argc > 1; 118 setvbuf(stdout, NULL, _IONBF, 0); 119 120 // Call setsid so that we can use kill(0, SIGIO) below. 121 // Don't check the return value so that this works both from 122 // a job control shell and from a shell script. 123 setsid(); 124 125 if (verbose) { 126 printf("calling RunGoroutines\n"); 127 } 128 129 RunGoroutines(); 130 131 // Block SIGIO in this thread to make it more likely that it 132 // will be delivered to a goroutine. 133 134 if (verbose) { 135 printf("calling pthread_sigmask\n"); 136 } 137 138 if (sigemptyset(&mask) < 0) { 139 die("sigemptyset"); 140 } 141 if (sigaddset(&mask, SIGIO) < 0) { 142 die("sigaddset"); 143 } 144 i = pthread_sigmask(SIG_BLOCK, &mask, NULL); 145 if (i != 0) { 146 fprintf(stderr, "pthread_sigmask: %s\n", strerror(i)); 147 exit(EXIT_FAILURE); 148 } 149 150 if (verbose) { 151 printf("calling kill\n"); 152 } 153 154 if (kill(0, SIGIO) < 0) { 155 die("kill"); 156 } 157 158 if (verbose) { 159 printf("waiting for sigioSeen\n"); 160 } 161 162 // Wait until the signal has been delivered. 163 i = 0; 164 while (!sigioSeen) { 165 ts.tv_sec = 0; 166 ts.tv_nsec = 1000000; 167 nanosleep(&ts, NULL); 168 i++; 169 if (i > 5000) { 170 fprintf(stderr, "looping too long waiting for signal\n"); 171 exit(EXIT_FAILURE); 172 } 173 } 174 175 if (verbose) { 176 printf("calling setjmp\n"); 177 } 178 179 // Test that a SIGSEGV on this thread is delivered to us. 180 if (setjmp(jmp) == 0) { 181 if (verbose) { 182 printf("triggering SIGSEGV\n"); 183 } 184 185 *nullPointer = '\0'; 186 187 fprintf(stderr, "continued after address error\n"); 188 exit(EXIT_FAILURE); 189 } 190 191 if (verbose) { 192 printf("calling TestSEGV\n"); 193 } 194 195 TestSEGV(); 196 197 printf("PASS\n"); 198 return 0; 199 }