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

View as plain text