Text file misc/cgo/testcarchive/testdata/main2.c

     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  	int darwin;
   127  
   128  	darwin = atoi(argv[1]);
   129  
   130  	verbose = argc > 2;
   131  
   132  	setvbuf(stdout, NULL, _IONBF, 0);
   133  
   134  	// Call setsid so that we can use kill(0, SIGIO) below.
   135  	// Don't check the return value so that this works both from
   136  	// a job control shell and from a shell script.
   137  	setsid();
   138  
   139  	if (verbose) {
   140  		printf("calling RunGoroutines\n");
   141  	}
   142  
   143  	RunGoroutines();
   144  
   145  	// Block SIGIO in this thread to make it more likely that it
   146  	// will be delivered to a goroutine.
   147  
   148  	if (verbose) {
   149  		printf("calling pthread_sigmask\n");
   150  	}
   151  
   152  	if (sigemptyset(&mask) < 0) {
   153  		die("sigemptyset");
   154  	}
   155  	if (sigaddset(&mask, SIGIO) < 0) {
   156  		die("sigaddset");
   157  	}
   158  	i = pthread_sigmask(SIG_BLOCK, &mask, NULL);
   159  	if (i != 0) {
   160  		fprintf(stderr, "pthread_sigmask: %s\n", strerror(i));
   161  		exit(EXIT_FAILURE);
   162  	}
   163  
   164  	if (verbose) {
   165  		printf("calling kill\n");
   166  	}
   167  
   168  	if (kill(0, SIGIO) < 0) {
   169  		die("kill");
   170  	}
   171  
   172  	if (verbose) {
   173  		printf("waiting for sigioSeen\n");
   174  	}
   175  
   176  	// Wait until the signal has been delivered.
   177  	i = 0;
   178  	while (!sigioSeen) {
   179  		ts.tv_sec = 0;
   180  		ts.tv_nsec = 1000000;
   181  		nanosleep(&ts, NULL);
   182  		i++;
   183  		if (i > 5000) {
   184  			fprintf(stderr, "looping too long waiting for SIGIO\n");
   185  			exit(EXIT_FAILURE);
   186  		}
   187  	}
   188  
   189  	if (verbose) {
   190  		printf("provoking SIGPIPE\n");
   191  	}
   192  
   193  	// SIGPIPE is never forwarded on Darwin, see golang.org/issue/33384.
   194  	if (!darwin) {
   195  		GoRaiseSIGPIPE();
   196  
   197  		if (verbose) {
   198  			printf("waiting for sigpipeSeen\n");
   199  		}
   200  
   201  		// Wait until the signal has been delivered.
   202  		i = 0;
   203  		while (!sigpipeSeen) {
   204  			ts.tv_sec = 0;
   205  			ts.tv_nsec = 1000000;
   206  			nanosleep(&ts, NULL);
   207  			i++;
   208  			if (i > 5000) {
   209  				fprintf(stderr, "looping too long waiting for SIGPIPE\n");
   210  				exit(EXIT_FAILURE);
   211  			}
   212  		}
   213  	}
   214  
   215  	if (verbose) {
   216  		printf("calling setjmp\n");
   217  	}
   218  
   219  	// Test that a SIGSEGV on this thread is delivered to us.
   220  	if (setjmp(jmp) == 0) {
   221  		if (verbose) {
   222  			printf("triggering SIGSEGV\n");
   223  		}
   224  
   225  		*nullPointer = '\0';
   226  
   227  		fprintf(stderr, "continued after address error\n");
   228  		exit(EXIT_FAILURE);
   229  	}
   230  
   231  	if (verbose) {
   232  		printf("calling TestSEGV\n");
   233  	}
   234  
   235  	TestSEGV();
   236  
   237  	printf("PASS\n");
   238  	return 0;
   239  }
   240  

View as plain text