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 }