Text file misc/cgo/testcarchive/testdata/main3.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 os/signal.Notify and os/signal.Reset.
     6  // This is a lot like misc/cgo/testcshared/main5.c.
     7  
     8  #include <signal.h>
     9  #include <stdio.h>
    10  #include <stdlib.h>
    11  #include <string.h>
    12  #include <time.h>
    13  #include <sched.h>
    14  #include <unistd.h>
    15  #include <pthread.h>
    16  
    17  #include "libgo3.h"
    18  
    19  static void die(const char* msg) {
    20  	perror(msg);
    21  	exit(EXIT_FAILURE);
    22  }
    23  
    24  static volatile sig_atomic_t sigioSeen;
    25  
    26  static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
    27  	sigioSeen = 1;
    28  }
    29  
    30  // Set up the SIGPIPE signal handler in a high priority constructor, so
    31  // that it is installed before the Go code starts.
    32  
    33  static void pipeHandler(int signo, siginfo_t* info, void* ctxt) {
    34  	const char *s = "unexpected SIGPIPE\n";
    35  	write(2, s, strlen(s));
    36  	exit(EXIT_FAILURE);
    37  }
    38  
    39  static void init(void) __attribute__ ((constructor (200)));
    40  
    41  static void init() {
    42      struct sigaction sa;
    43  
    44  	memset(&sa, 0, sizeof sa);
    45  	sa.sa_sigaction = pipeHandler;
    46  	if (sigemptyset(&sa.sa_mask) < 0) {
    47  		die("sigemptyset");
    48  	}
    49  	sa.sa_flags = SA_SIGINFO;
    50  	if (sigaction(SIGPIPE, &sa, NULL) < 0) {
    51  		die("sigaction");
    52  	}
    53  }
    54  
    55  static void *provokeSIGPIPE(void *arg) {
    56  	ProvokeSIGPIPE();
    57  	return NULL;
    58  }
    59  
    60  int main(int argc, char** argv) {
    61  	int verbose;
    62  	struct sigaction sa;
    63  	int i;
    64  	struct timespec ts;
    65  	int res;
    66  	pthread_t tid;
    67  
    68  	verbose = argc > 2;
    69  	setvbuf(stdout, NULL, _IONBF, 0);
    70  
    71  	if (verbose) {
    72  		printf("raising SIGPIPE\n");
    73  	}
    74  
    75  	// Test that the Go runtime handles SIGPIPE, even if we installed
    76  	// a non-default SIGPIPE handler before the runtime initializes.
    77  	ProvokeSIGPIPE();
    78  
    79  	// Test that SIGPIPE on a non-main thread is also handled by Go.
    80  	res = pthread_create(&tid, NULL, provokeSIGPIPE, NULL);
    81  	if (res != 0) {
    82  		fprintf(stderr, "pthread_create: %s\n", strerror(res));
    83  		exit(EXIT_FAILURE);
    84  	}
    85  
    86  	res = pthread_join(tid, NULL);
    87  	if (res != 0) {
    88  		fprintf(stderr, "pthread_join: %s\n", strerror(res));
    89  		exit(EXIT_FAILURE);
    90  	}
    91  
    92  	if (verbose) {
    93  		printf("calling sigaction\n");
    94  	}
    95  
    96  	memset(&sa, 0, sizeof sa);
    97  	sa.sa_sigaction = ioHandler;
    98  	if (sigemptyset(&sa.sa_mask) < 0) {
    99  		die("sigemptyset");
   100  	}
   101  	sa.sa_flags = SA_SIGINFO;
   102  	if (sigaction(SIGIO, &sa, NULL) < 0) {
   103  		die("sigaction");
   104  	}
   105  
   106  	// At this point there should not be a Go signal handler
   107  	// installed for SIGIO.
   108  
   109  	if (verbose) {
   110  		printf("raising SIGIO\n");
   111  	}
   112  
   113  	if (raise(SIGIO) < 0) {
   114  		die("raise");
   115  	}
   116  
   117  	if (verbose) {
   118  		printf("waiting for sigioSeen\n");
   119  	}
   120  
   121  	// Wait until the signal has been delivered.
   122  	i = 0;
   123  	while (!sigioSeen) {
   124  		ts.tv_sec = 0;
   125  		ts.tv_nsec = 1000000;
   126  		nanosleep(&ts, NULL);
   127  		i++;
   128  		if (i > 5000) {
   129  			fprintf(stderr, "looping too long waiting for signal\n");
   130  			exit(EXIT_FAILURE);
   131  		}
   132  	}
   133  
   134  	sigioSeen = 0;
   135  
   136  	// Tell the Go code to catch SIGIO.
   137  
   138  	if (verbose) {
   139  		printf("calling CatchSIGIO\n");
   140  	}
   141  
   142  	CatchSIGIO();
   143  
   144  	if (verbose) {
   145  		printf("raising SIGIO\n");
   146  	}
   147  
   148  	if (raise(SIGIO) < 0) {
   149  		die("raise");
   150  	}
   151  
   152  	if (verbose) {
   153  		printf("calling SawSIGIO\n");
   154  	}
   155  
   156  	if (!SawSIGIO()) {
   157  		fprintf(stderr, "Go handler did not see SIGIO\n");
   158  		exit(EXIT_FAILURE);
   159  	}
   160  
   161  	if (sigioSeen != 0) {
   162  		fprintf(stderr, "C handler saw SIGIO when only Go handler should have\n");
   163  		exit(EXIT_FAILURE);
   164  	}
   165  
   166  	// Tell the Go code to stop catching SIGIO.
   167  
   168  	if (verbose) {
   169  		printf("calling ResetSIGIO\n");
   170  	}
   171  
   172  	ResetSIGIO();
   173  
   174  	if (verbose) {
   175  		printf("raising SIGIO\n");
   176  	}
   177  
   178  	if (raise(SIGIO) < 0) {
   179  		die("raise");
   180  	}
   181  
   182  	if (verbose) {
   183  		printf("calling SawSIGIO\n");
   184  	}
   185  
   186  	if (SawSIGIO()) {
   187  		fprintf(stderr, "Go handler saw SIGIO after Reset\n");
   188  		exit(EXIT_FAILURE);
   189  	}
   190  
   191  	if (verbose) {
   192  		printf("waiting for sigioSeen\n");
   193  	}
   194  
   195  	// Wait until the signal has been delivered.
   196  	i = 0;
   197  	while (!sigioSeen) {
   198  		ts.tv_sec = 0;
   199  		ts.tv_nsec = 1000000;
   200  		nanosleep(&ts, NULL);
   201  		i++;
   202  		if (i > 5000) {
   203  			fprintf(stderr, "looping too long waiting for signal\n");
   204  			exit(EXIT_FAILURE);
   205  		}
   206  	}
   207  
   208  	printf("PASS\n");
   209  	return 0;
   210  }
   211  

View as plain text