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  }