github.com/panjjo/go@v0.0.0-20161104043856-d62b31386338/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 116 verbose = argc > 1; 117 setvbuf(stdout, NULL, _IONBF, 0); 118 119 // Call setsid so that we can use kill(0, SIGIO) below. 120 // Don't check the return value so that this works both from 121 // a job control shell and from a shell script. 122 setsid(); 123 124 if (verbose) { 125 printf("calling RunGoroutines\n"); 126 } 127 128 RunGoroutines(); 129 130 // Block SIGIO in this thread to make it more likely that it 131 // will be delivered to a goroutine. 132 133 if (verbose) { 134 printf("calling pthread_sigmask\n"); 135 } 136 137 if (sigemptyset(&mask) < 0) { 138 die("sigemptyset"); 139 } 140 if (sigaddset(&mask, SIGIO) < 0) { 141 die("sigaddset"); 142 } 143 i = pthread_sigmask(SIG_BLOCK, &mask, NULL); 144 if (i != 0) { 145 fprintf(stderr, "pthread_sigmask: %s\n", strerror(i)); 146 exit(EXIT_FAILURE); 147 } 148 149 if (verbose) { 150 printf("calling kill\n"); 151 } 152 153 if (kill(0, SIGIO) < 0) { 154 die("kill"); 155 } 156 157 if (verbose) { 158 printf("waiting for sigioSeen\n"); 159 } 160 161 // Wait until the signal has been delivered. 162 i = 0; 163 while (!sigioSeen) { 164 if (sched_yield() < 0) { 165 perror("sched_yield"); 166 } 167 i++; 168 if (i > 100000) { 169 fprintf(stderr, "looping too long waiting for signal\n"); 170 exit(EXIT_FAILURE); 171 } 172 } 173 174 if (verbose) { 175 printf("calling setjmp\n"); 176 } 177 178 // Test that a SIGSEGV on this thread is delivered to us. 179 if (setjmp(jmp) == 0) { 180 if (verbose) { 181 printf("triggering SIGSEGV\n"); 182 } 183 184 *nullPointer = '\0'; 185 186 fprintf(stderr, "continued after address error\n"); 187 exit(EXIT_FAILURE); 188 } 189 190 if (verbose) { 191 printf("calling TestSEGV\n"); 192 } 193 194 TestSEGV(); 195 196 printf("PASS\n"); 197 return 0; 198 }