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