...

Text file src/cmd/cgo/internal/testcarchive/testdata/main2.c

Documentation: cmd/cgo/internal/testcarchive/testdata

     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 ../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
    24static void die(const char* msg) {
    25	perror(msg);
    26	exit(EXIT_FAILURE);
    27}
    28
    29static volatile sig_atomic_t sigioSeen;
    30static volatile sig_atomic_t sigpipeSeen;
    31
    32// Use up some stack space.
    33static 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
    42static 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.
    47static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
    48	char a[1024];
    49
    50	recur(4, a);
    51	sigioSeen = 1;
    52}
    53
    54static jmp_buf jmp;
    55static char* nullPointer;
    56
    57// An arbitrary function which requires proper stack alignment; see
    58// http://golang.org/issue/17641.
    59static 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.
    66static 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
    95static void init(void) __attribute__ ((constructor (200)));
    96
    97static 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
   121int 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}

View as plain text