github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/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 __attribute__ ((unused))) {
    48  	stack_t ss;
    49  	int i;
    50  	stack_t nss;
    51  
    52  	// Set up an alternate signal stack for this thread.
    53  	memset(&ss, 0, sizeof ss);
    54  	ss.ss_sp = malloc(SIGSTKSZ);
    55  	if (ss.ss_sp == NULL) {
    56  		die("malloc");
    57  	}
    58  	ss.ss_flags = 0;
    59  	ss.ss_size = SIGSTKSZ;
    60  	if (sigaltstack(&ss, NULL) < 0) {
    61  		die("sigaltstack");
    62  	}
    63  
    64  	// Send ourselves a SIGIO.  This will be caught by the Go
    65  	// signal handler which should forward to the C signal
    66  	// handler.
    67  	i = pthread_kill(pthread_self(), SIGIO);
    68  	if (i != 0) {
    69  		fprintf(stderr, "pthread_kill: %s\n", strerror(i));
    70  		exit(EXIT_FAILURE);
    71  	}
    72  
    73  	// Wait until the signal has been delivered.
    74  	i = 0;
    75  	while (SIGIOCount() == 0) {
    76  		if (sched_yield() < 0) {
    77  			perror("sched_yield");
    78  		}
    79  		i++;
    80  		if (i > 100000) {
    81  			fprintf(stderr, "looping too long waiting for signal\n");
    82  			exit(EXIT_FAILURE);
    83  		}
    84  	}
    85  
    86  	// We should still be on the same signal stack.
    87  	if (sigaltstack(NULL, &nss) < 0) {
    88  		die("sigaltstack check");
    89  	}
    90  	if ((nss.ss_flags & SS_DISABLE) != 0) {
    91  		fprintf(stderr, "sigaltstack disabled on return from Go\n");
    92  		ok = 0;
    93  	} else if (nss.ss_sp != ss.ss_sp) {
    94  		fprintf(stderr, "sigalstack changed on return from Go\n");
    95  		ok = 0;
    96  	}
    97  
    98  	return NULL;
    99  }
   100  
   101  // Test calling a Go function to raise SIGIO on a C thread with an
   102  // alternate signal stack when there is a Go signal handler for SIGIO.
   103  static void* thread2(void* arg __attribute__ ((unused))) {
   104  	stack_t ss;
   105  	int i;
   106  	int oldcount;
   107  	pthread_t tid;
   108  	stack_t nss;
   109  
   110  	// Set up an alternate signal stack for this thread.
   111  	memset(&ss, 0, sizeof ss);
   112  	ss.ss_sp = malloc(SIGSTKSZ);
   113  	if (ss.ss_sp == NULL) {
   114  		die("malloc");
   115  	}
   116  	ss.ss_flags = 0;
   117  	ss.ss_size = SIGSTKSZ;
   118  	if (sigaltstack(&ss, NULL) < 0) {
   119  		die("sigaltstack");
   120  	}
   121  
   122  	oldcount = SIGIOCount();
   123  
   124  	// Call a Go function that will call a C function to send us a
   125  	// SIGIO.
   126  	tid = pthread_self();
   127  	GoRaiseSIGIO(&tid);
   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, NULL);
   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, NULL);
   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  }