(root)/
gcc-13.2.0/
libgo/
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  }