github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/misc/cgo/testcarchive/main4.c (about)

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