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  }