(root)/
gcc-13.2.0/
libgo/
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  }