Text file misc/cgo/testcarchive/testdata/main4.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 a C thread that calls sigaltstack and then calls Go code.
     6  
     7  #include <signal.h>
     8  #include <stdio.h>
     9  #include <stdlib.h>
    10  #include <string.h>
    11  #include <time.h>
    12  #include <sched.h>
    13  #include <pthread.h>
    14  
    15  #include "libgo4.h"
    16  
    17  #ifdef _AIX
    18  // On AIX, CSIGSTKSZ is too small to handle Go sighandler.
    19  #define CSIGSTKSZ 0x4000
    20  #else
    21  #define CSIGSTKSZ SIGSTKSZ
    22  #endif
    23  
    24  static void die(const char* msg) {
    25  	perror(msg);
    26  	exit(EXIT_FAILURE);
    27  }
    28  
    29  static int ok = 1;
    30  
    31  static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
    32  }
    33  
    34  // Set up the SIGIO signal handler in a high priority constructor, so
    35  // that it is installed before the Go code starts.
    36  
    37  static void init(void) __attribute__ ((constructor (200)));
    38  
    39  static void init() {
    40  	struct sigaction sa;
    41  
    42  	memset(&sa, 0, sizeof sa);
    43  	sa.sa_sigaction = ioHandler;
    44  	if (sigemptyset(&sa.sa_mask) < 0) {
    45  		die("sigemptyset");
    46  	}
    47  	sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
    48  	if (sigaction(SIGIO, &sa, NULL) < 0) {
    49  		die("sigaction");
    50  	}
    51  }
    52  
    53  // Test raising SIGIO on a C thread with an alternate signal stack
    54  // when there is a Go signal handler for SIGIO.
    55  static void* thread1(void* arg __attribute__ ((unused))) {
    56  	stack_t ss;
    57  	int i;
    58  	stack_t nss;
    59  	struct timespec ts;
    60  
    61  	// Set up an alternate signal stack for this thread.
    62  	memset(&ss, 0, sizeof ss);
    63  	ss.ss_sp = malloc(CSIGSTKSZ);
    64  	if (ss.ss_sp == NULL) {
    65  		die("malloc");
    66  	}
    67  	ss.ss_flags = 0;
    68  	ss.ss_size = CSIGSTKSZ;
    69  	if (sigaltstack(&ss, NULL) < 0) {
    70  		die("sigaltstack");
    71  	}
    72  
    73  	// Send ourselves a SIGIO.  This will be caught by the Go
    74  	// signal handler which should forward to the C signal
    75  	// handler.
    76  	i = pthread_kill(pthread_self(), SIGIO);
    77  	if (i != 0) {
    78  		fprintf(stderr, "pthread_kill: %s\n", strerror(i));
    79  		exit(EXIT_FAILURE);
    80  	}
    81  
    82  	// Wait until the signal has been delivered.
    83  	i = 0;
    84  	while (SIGIOCount() == 0) {
    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  	// We should still be on the same signal stack.
    96  	if (sigaltstack(NULL, &nss) < 0) {
    97  		die("sigaltstack check");
    98  	}
    99  	if ((nss.ss_flags & SS_DISABLE) != 0) {
   100  		fprintf(stderr, "sigaltstack disabled on return from Go\n");
   101  		ok = 0;
   102  	} else if (nss.ss_sp != ss.ss_sp) {
   103  		fprintf(stderr, "sigaltstack changed on return from Go\n");
   104  		ok = 0;
   105  	}
   106  
   107  	return NULL;
   108  }
   109  
   110  // Test calling a Go function to raise SIGIO on a C thread with an
   111  // alternate signal stack when there is a Go signal handler for SIGIO.
   112  static void* thread2(void* arg __attribute__ ((unused))) {
   113  	stack_t ss;
   114  	int i;
   115  	int oldcount;
   116  	pthread_t tid;
   117  	struct timespec ts;
   118  	stack_t nss;
   119  
   120  	// Set up an alternate signal stack for this thread.
   121  	memset(&ss, 0, sizeof ss);
   122  	ss.ss_sp = malloc(CSIGSTKSZ);
   123  	if (ss.ss_sp == NULL) {
   124  		die("malloc");
   125  	}
   126  	ss.ss_flags = 0;
   127  	ss.ss_size = CSIGSTKSZ;
   128  	if (sigaltstack(&ss, NULL) < 0) {
   129  		die("sigaltstack");
   130  	}
   131  
   132  	oldcount = SIGIOCount();
   133  
   134  	// Call a Go function that will call a C function to send us a
   135  	// SIGIO.
   136  	tid = pthread_self();
   137  	GoRaiseSIGIO(&tid);
   138  
   139  	// Wait until the signal has been delivered.
   140  	i = 0;
   141  	while (SIGIOCount() == oldcount) {
   142  		ts.tv_sec = 0;
   143  		ts.tv_nsec = 1000000;
   144  		nanosleep(&ts, NULL);
   145  		i++;
   146  		if (i > 5000) {
   147  			fprintf(stderr, "looping too long waiting for signal\n");
   148  			exit(EXIT_FAILURE);
   149  		}
   150  	}
   151  
   152  	// We should still be on the same signal stack.
   153  	if (sigaltstack(NULL, &nss) < 0) {
   154  		die("sigaltstack check");
   155  	}
   156  	if ((nss.ss_flags & SS_DISABLE) != 0) {
   157  		fprintf(stderr, "sigaltstack disabled on return from Go\n");
   158  		ok = 0;
   159  	} else if (nss.ss_sp != ss.ss_sp) {
   160  		fprintf(stderr, "sigaltstack changed on return from Go\n");
   161  		ok = 0;
   162  	}
   163  
   164  	return NULL;
   165  }
   166  
   167  int main(int argc, char **argv) {
   168  	pthread_t tid;
   169  	int i;
   170  
   171  	// Tell the Go library to start looking for SIGIO.
   172  	GoCatchSIGIO();
   173  
   174  	i = pthread_create(&tid, NULL, thread1, NULL);
   175  	if (i != 0) {
   176  		fprintf(stderr, "pthread_create: %s\n", strerror(i));
   177  		exit(EXIT_FAILURE);
   178  	}
   179  
   180  	i = pthread_join(tid, NULL);
   181  	if (i != 0) {
   182  		fprintf(stderr, "pthread_join: %s\n", strerror(i));
   183  		exit(EXIT_FAILURE);
   184  	}
   185  
   186  	i = pthread_create(&tid, NULL, thread2, NULL);
   187  	if (i != 0) {
   188  		fprintf(stderr, "pthread_create: %s\n", strerror(i));
   189  		exit(EXIT_FAILURE);
   190  	}
   191  
   192  	i = pthread_join(tid, NULL);
   193  	if (i != 0) {
   194  		fprintf(stderr, "pthread_join: %s\n", strerror(i));
   195  		exit(EXIT_FAILURE);
   196  	}
   197  
   198  	if (!ok) {
   199  		exit(EXIT_FAILURE);
   200  	}
   201  
   202  	printf("PASS\n");
   203  	return 0;
   204  }
   205  

View as plain text