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 }