github.com/reiver/go@v0.0.0-20150109200633-1d0c7792f172/src/runtime/crash_cgo_test.go (about) 1 // Copyright 2012 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 // +build cgo 6 7 package runtime_test 8 9 import ( 10 "os/exec" 11 "runtime" 12 "strings" 13 "testing" 14 ) 15 16 func TestCgoCrashHandler(t *testing.T) { 17 testCrashHandler(t, true) 18 } 19 20 func TestCgoSignalDeadlock(t *testing.T) { 21 if testing.Short() && runtime.GOOS == "windows" { 22 t.Skip("Skipping in short mode") // takes up to 64 seconds 23 } 24 got := executeTest(t, cgoSignalDeadlockSource, nil) 25 want := "OK\n" 26 if got != want { 27 t.Fatalf("expected %q, but got %q", want, got) 28 } 29 } 30 31 func TestCgoTraceback(t *testing.T) { 32 got := executeTest(t, cgoTracebackSource, nil) 33 want := "OK\n" 34 if got != want { 35 t.Fatalf("expected %q, but got %q", want, got) 36 } 37 } 38 39 func TestCgoExternalThreadPanic(t *testing.T) { 40 if runtime.GOOS == "plan9" { 41 t.Skipf("no pthreads on %s", runtime.GOOS) 42 } 43 csrc := cgoExternalThreadPanicC 44 if runtime.GOOS == "windows" { 45 csrc = cgoExternalThreadPanicC_windows 46 } 47 got := executeTest(t, cgoExternalThreadPanicSource, nil, "main.c", csrc) 48 want := "panic: BOOM" 49 if !strings.Contains(got, want) { 50 t.Fatalf("want failure containing %q. output:\n%s\n", want, got) 51 } 52 } 53 54 func TestCgoExternalThreadSIGPROF(t *testing.T) { 55 // issue 9456. 56 switch runtime.GOOS { 57 case "plan9", "windows": 58 t.Skipf("no pthreads on %s", runtime.GOOS) 59 case "darwin": 60 // static constructor needs external linking, but we don't support 61 // external linking on OS X 10.6. 62 out, err := exec.Command("uname", "-r").Output() 63 if err != nil { 64 t.Fatalf("uname -r failed: %v", err) 65 } 66 // OS X 10.6 == Darwin 10.x 67 if strings.HasPrefix(string(out), "10.") { 68 t.Skipf("no external linking on OS X 10.6") 69 } 70 } 71 if runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" { 72 // TODO(austin) External linking not implemented on 73 // ppc64 (issue #8912) 74 t.Skipf("no external linking on ppc64") 75 } 76 got := executeTest(t, cgoExternalThreadSIGPROFSource, nil) 77 want := "OK\n" 78 if got != want { 79 t.Fatalf("expected %q, but got %q", want, got) 80 } 81 } 82 83 const cgoSignalDeadlockSource = ` 84 package main 85 86 import "C" 87 88 import ( 89 "fmt" 90 "runtime" 91 "time" 92 ) 93 94 func main() { 95 runtime.GOMAXPROCS(100) 96 ping := make(chan bool) 97 go func() { 98 for i := 0; ; i++ { 99 runtime.Gosched() 100 select { 101 case done := <-ping: 102 if done { 103 ping <- true 104 return 105 } 106 ping <- true 107 default: 108 } 109 func() { 110 defer func() { 111 recover() 112 }() 113 var s *string 114 *s = "" 115 }() 116 } 117 }() 118 time.Sleep(time.Millisecond) 119 for i := 0; i < 64; i++ { 120 go func() { 121 runtime.LockOSThread() 122 select {} 123 }() 124 go func() { 125 runtime.LockOSThread() 126 select {} 127 }() 128 time.Sleep(time.Millisecond) 129 ping <- false 130 select { 131 case <-ping: 132 case <-time.After(time.Second): 133 fmt.Printf("HANG\n") 134 return 135 } 136 } 137 ping <- true 138 select { 139 case <-ping: 140 case <-time.After(time.Second): 141 fmt.Printf("HANG\n") 142 return 143 } 144 fmt.Printf("OK\n") 145 } 146 ` 147 148 const cgoTracebackSource = ` 149 package main 150 151 /* void foo(void) {} */ 152 import "C" 153 154 import ( 155 "fmt" 156 "runtime" 157 ) 158 159 func main() { 160 C.foo() 161 buf := make([]byte, 1) 162 runtime.Stack(buf, true) 163 fmt.Printf("OK\n") 164 } 165 ` 166 167 const cgoExternalThreadPanicSource = ` 168 package main 169 170 // void start(void); 171 import "C" 172 173 func main() { 174 C.start() 175 select {} 176 } 177 178 //export gopanic 179 func gopanic() { 180 panic("BOOM") 181 } 182 ` 183 184 const cgoExternalThreadPanicC = ` 185 #include <stdlib.h> 186 #include <stdio.h> 187 #include <pthread.h> 188 189 void gopanic(void); 190 191 static void* 192 die(void* x) 193 { 194 gopanic(); 195 return 0; 196 } 197 198 void 199 start(void) 200 { 201 pthread_t t; 202 if(pthread_create(&t, 0, die, 0) != 0) 203 printf("pthread_create failed\n"); 204 } 205 ` 206 207 const cgoExternalThreadPanicC_windows = ` 208 #include <stdlib.h> 209 #include <stdio.h> 210 211 void gopanic(void); 212 213 static void* 214 die(void* x) 215 { 216 gopanic(); 217 return 0; 218 } 219 220 void 221 start(void) 222 { 223 if(_beginthreadex(0, 0, die, 0, 0, 0) != 0) 224 printf("_beginthreadex failed\n"); 225 } 226 ` 227 228 const cgoExternalThreadSIGPROFSource = ` 229 package main 230 231 /* 232 #include <stdint.h> 233 #include <signal.h> 234 #include <pthread.h> 235 236 volatile int32_t spinlock; 237 238 static void *thread1(void *p) { 239 (void)p; 240 while (spinlock == 0) 241 ; 242 pthread_kill(pthread_self(), SIGPROF); 243 spinlock = 0; 244 return NULL; 245 } 246 __attribute__((constructor)) void issue9456() { 247 pthread_t tid; 248 pthread_create(&tid, 0, thread1, NULL); 249 } 250 */ 251 import "C" 252 253 import ( 254 "runtime" 255 "sync/atomic" 256 "unsafe" 257 ) 258 259 func main() { 260 // This test intends to test that sending SIGPROF to foreign threads 261 // before we make any cgo call will not abort the whole process, so 262 // we cannot make any cgo call here. See http://golang.org/issue/9456. 263 atomic.StoreInt32((*int32)(unsafe.Pointer(&C.spinlock)), 1) 264 for atomic.LoadInt32((*int32)(unsafe.Pointer(&C.spinlock))) == 1 { 265 runtime.Gosched() 266 } 267 println("OK") 268 } 269 `