github.com/guyezi/gofrontend@v0.0.0-20200228202240-7a62a49e62c0/libgo/misc/cgo/testcarchive/testdata/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 <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 }