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  }