github.com/dannin/go@v0.0.0-20161031215817-d35dfd405eaa/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  }