blob: df6c15df6933740e51a7d7ea7449eea71068d25a [file] [log] [blame]
Alex Brainmanafe0e972012-05-30 15:10:54 +10001// 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
7package runtime_test
8
9import (
Shenghou Ma865e5e92015-01-03 00:12:34 -050010 "os/exec"
Dmitriy Vyukov1590abe2013-08-08 00:04:28 +040011 "runtime"
Russ Coxc4efaac2014-10-28 21:53:09 -040012 "strings"
Alex Brainmanafe0e972012-05-30 15:10:54 +100013 "testing"
14)
15
16func TestCgoCrashHandler(t *testing.T) {
Dmitriy Vyukov06a488f2013-02-20 12:15:02 +040017 testCrashHandler(t, true)
Alex Brainmanafe0e972012-05-30 15:10:54 +100018}
Shenghou Ma6ecb39f2013-02-28 16:07:26 +080019
20func TestCgoSignalDeadlock(t *testing.T) {
Dmitriy Vyukov1590abe2013-08-08 00:04:28 +040021 if testing.Short() && runtime.GOOS == "windows" {
22 t.Skip("Skipping in short mode") // takes up to 64 seconds
23 }
Shenghou Ma6ecb39f2013-02-28 16:07:26 +080024 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
Dmitriy Vyukov326ae8d2013-08-08 00:31:52 +040031func 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
Russ Coxfde39262015-07-29 16:16:13 -040039func TestCgoCallbackGC(t *testing.T) {
40 if runtime.GOOS == "plan9" || runtime.GOOS == "windows" {
41 t.Skipf("no pthreads on %s", runtime.GOOS)
42 }
Mikio Hara5e15e282015-08-03 12:43:25 +090043 if testing.Short() && runtime.GOOS == "dragonfly" {
44 t.Skip("see golang.org/issue/11990")
45 }
Russ Coxfde39262015-07-29 16:16:13 -040046 got := executeTest(t, cgoCallbackGCSource, nil)
47 want := "OK\n"
48 if got != want {
49 t.Fatalf("expected %q, but got %q", want, got)
50 }
51}
52
Russ Coxc4efaac2014-10-28 21:53:09 -040053func TestCgoExternalThreadPanic(t *testing.T) {
Alex Brainmanf9c4c162014-10-30 10:24:37 +110054 if runtime.GOOS == "plan9" {
Russ Cox3ce6a4f2014-10-29 00:02:29 -040055 t.Skipf("no pthreads on %s", runtime.GOOS)
56 }
Alex Brainmanf9c4c162014-10-30 10:24:37 +110057 csrc := cgoExternalThreadPanicC
58 if runtime.GOOS == "windows" {
59 csrc = cgoExternalThreadPanicC_windows
60 }
61 got := executeTest(t, cgoExternalThreadPanicSource, nil, "main.c", csrc)
Russ Coxc4efaac2014-10-28 21:53:09 -040062 want := "panic: BOOM"
63 if !strings.Contains(got, want) {
64 t.Fatalf("want failure containing %q. output:\n%s\n", want, got)
65 }
66}
67
Shenghou Ma5da9c8c2014-12-27 19:15:38 -050068func TestCgoExternalThreadSIGPROF(t *testing.T) {
69 // issue 9456.
Shenghou Ma2cbe27a2015-01-01 01:10:39 -050070 switch runtime.GOOS {
71 case "plan9", "windows":
Shenghou Ma5da9c8c2014-12-27 19:15:38 -050072 t.Skipf("no pthreads on %s", runtime.GOOS)
Shenghou Ma2cbe27a2015-01-01 01:10:39 -050073 case "darwin":
David Crawshawd6d423b2015-04-11 19:00:53 -040074 if runtime.GOARCH != "arm" && runtime.GOARCH != "arm64" {
David Crawshaw95bf77b2015-02-26 18:05:47 -050075 // static constructor needs external linking, but we don't support
76 // external linking on OS X 10.6.
77 out, err := exec.Command("uname", "-r").Output()
78 if err != nil {
79 t.Fatalf("uname -r failed: %v", err)
80 }
81 // OS X 10.6 == Darwin 10.x
82 if strings.HasPrefix(string(out), "10.") {
83 t.Skipf("no external linking on OS X 10.6")
84 }
Shenghou Ma2cbe27a2015-01-01 01:10:39 -050085 }
Shenghou Ma5da9c8c2014-12-27 19:15:38 -050086 }
Michael Hudson-Doyle58db5fc2015-11-12 13:05:49 +130087 if runtime.GOARCH == "ppc64" {
Austin Clementsaf7ca8d2014-12-16 18:34:55 -050088 // TODO(austin) External linking not implemented on
89 // ppc64 (issue #8912)
90 t.Skipf("no external linking on ppc64")
91 }
Shenghou Ma5da9c8c2014-12-27 19:15:38 -050092 got := executeTest(t, cgoExternalThreadSIGPROFSource, nil)
93 want := "OK\n"
94 if got != want {
95 t.Fatalf("expected %q, but got %q", want, got)
96 }
97}
98
Ian Lance Taylor872b1682015-07-21 22:34:48 -070099func TestCgoExternalThreadSignal(t *testing.T) {
100 // issue 10139
101 switch runtime.GOOS {
102 case "plan9", "windows":
103 t.Skipf("no pthreads on %s", runtime.GOOS)
104 }
105 got := executeTest(t, cgoExternalThreadSignalSource, nil)
106 want := "OK\n"
107 if got != want {
108 t.Fatalf("expected %q, but got %q", want, got)
109 }
110}
111
Alex Brainman9b691962015-03-16 15:46:22 +1100112func TestCgoDLLImports(t *testing.T) {
113 // test issue 9356
114 if runtime.GOOS != "windows" {
115 t.Skip("skipping windows specific test")
116 }
117 got := executeTest(t, cgoDLLImportsMainSource, nil, "a/a.go", cgoDLLImportsPkgSource)
118 want := "OK\n"
119 if got != want {
120 t.Fatalf("expected %q, but got %v", want, got)
121 }
122}
123
Shenghou Ma6ecb39f2013-02-28 16:07:26 +0800124const cgoSignalDeadlockSource = `
125package main
126
127import "C"
128
129import (
130 "fmt"
131 "runtime"
132 "time"
133)
134
135func main() {
136 runtime.GOMAXPROCS(100)
137 ping := make(chan bool)
138 go func() {
139 for i := 0; ; i++ {
140 runtime.Gosched()
141 select {
142 case done := <-ping:
143 if done {
144 ping <- true
145 return
146 }
147 ping <- true
148 default:
149 }
150 func() {
151 defer func() {
152 recover()
153 }()
154 var s *string
155 *s = ""
156 }()
157 }
158 }()
159 time.Sleep(time.Millisecond)
160 for i := 0; i < 64; i++ {
161 go func() {
162 runtime.LockOSThread()
163 select {}
164 }()
165 go func() {
166 runtime.LockOSThread()
167 select {}
168 }()
169 time.Sleep(time.Millisecond)
170 ping <- false
171 select {
172 case <-ping:
173 case <-time.After(time.Second):
174 fmt.Printf("HANG\n")
175 return
176 }
177 }
178 ping <- true
179 select {
180 case <-ping:
181 case <-time.After(time.Second):
182 fmt.Printf("HANG\n")
183 return
184 }
185 fmt.Printf("OK\n")
186}
187`
Dmitriy Vyukov326ae8d2013-08-08 00:31:52 +0400188
189const cgoTracebackSource = `
190package main
191
192/* void foo(void) {} */
193import "C"
194
195import (
196 "fmt"
197 "runtime"
198)
199
200func main() {
201 C.foo()
202 buf := make([]byte, 1)
203 runtime.Stack(buf, true)
204 fmt.Printf("OK\n")
205}
206`
Russ Coxc4efaac2014-10-28 21:53:09 -0400207
Russ Coxfde39262015-07-29 16:16:13 -0400208const cgoCallbackGCSource = `
209package main
210
211import "runtime"
212
213/*
214#include <pthread.h>
215
216void go_callback();
217
218static void *thr(void *arg) {
219 go_callback();
220 return 0;
221}
222
223static void foo() {
224 pthread_t th;
Dave Cheney4f485072015-08-20 13:46:19 +1000225 pthread_attr_t attr;
226 pthread_attr_init(&attr);
227 pthread_attr_setstacksize(&attr, 256 << 10);
228 pthread_create(&th, &attr, thr, 0);
Russ Coxfde39262015-07-29 16:16:13 -0400229 pthread_join(th, 0);
230}
231*/
232import "C"
233import "fmt"
234
235//export go_callback
236func go_callback() {
237 runtime.GC()
238 grow()
239 runtime.GC()
240}
241
242var cnt int
243
244func grow() {
245 x := 10000
246 sum := 0
247 if grow1(&x, &sum) == 0 {
248 panic("bad")
249 }
250}
251
252func grow1(x, sum *int) int {
253 if *x == 0 {
254 return *sum + 1
255 }
256 *x--
257 sum1 := *sum + *x
258 return grow1(x, &sum1)
259}
260
261func main() {
262 const P = 100
263 done := make(chan bool)
264 // allocate a bunch of stack frames and spray them with pointers
265 for i := 0; i < P; i++ {
266 go func() {
267 grow()
268 done <- true
269 }()
270 }
271 for i := 0; i < P; i++ {
272 <-done
273 }
274 // now give these stack frames to cgo callbacks
275 for i := 0; i < P; i++ {
276 go func() {
277 C.foo()
278 done <- true
279 }()
280 }
281 for i := 0; i < P; i++ {
282 <-done
283 }
284 fmt.Printf("OK\n")
285}
286`
287
Russ Coxc4efaac2014-10-28 21:53:09 -0400288const cgoExternalThreadPanicSource = `
289package main
290
291// void start(void);
292import "C"
293
294func main() {
295 C.start()
296 select {}
297}
298
299//export gopanic
300func gopanic() {
301 panic("BOOM")
302}
303`
304
305const cgoExternalThreadPanicC = `
306#include <stdlib.h>
307#include <stdio.h>
308#include <pthread.h>
309
310void gopanic(void);
311
312static void*
313die(void* x)
314{
315 gopanic();
316 return 0;
317}
318
319void
320start(void)
321{
322 pthread_t t;
323 if(pthread_create(&t, 0, die, 0) != 0)
324 printf("pthread_create failed\n");
325}
326`
Alex Brainmanf9c4c162014-10-30 10:24:37 +1100327
328const cgoExternalThreadPanicC_windows = `
329#include <stdlib.h>
330#include <stdio.h>
331
332void gopanic(void);
333
334static void*
335die(void* x)
336{
337 gopanic();
338 return 0;
339}
340
341void
342start(void)
343{
344 if(_beginthreadex(0, 0, die, 0, 0, 0) != 0)
345 printf("_beginthreadex failed\n");
346}
347`
Shenghou Ma5da9c8c2014-12-27 19:15:38 -0500348
349const cgoExternalThreadSIGPROFSource = `
350package main
351
352/*
353#include <stdint.h>
354#include <signal.h>
355#include <pthread.h>
356
357volatile int32_t spinlock;
358
359static void *thread1(void *p) {
360 (void)p;
361 while (spinlock == 0)
362 ;
363 pthread_kill(pthread_self(), SIGPROF);
364 spinlock = 0;
365 return NULL;
366}
367__attribute__((constructor)) void issue9456() {
368 pthread_t tid;
369 pthread_create(&tid, 0, thread1, NULL);
370}
371*/
372import "C"
373
374import (
375 "runtime"
376 "sync/atomic"
377 "unsafe"
378)
379
380func main() {
381 // This test intends to test that sending SIGPROF to foreign threads
382 // before we make any cgo call will not abort the whole process, so
Brad Fitzpatrick2ae77372015-07-10 17:17:11 -0600383 // we cannot make any cgo call here. See https://golang.org/issue/9456.
Shenghou Ma5da9c8c2014-12-27 19:15:38 -0500384 atomic.StoreInt32((*int32)(unsafe.Pointer(&C.spinlock)), 1)
385 for atomic.LoadInt32((*int32)(unsafe.Pointer(&C.spinlock))) == 1 {
386 runtime.Gosched()
387 }
388 println("OK")
389}
390`
Alex Brainman9b691962015-03-16 15:46:22 +1100391
Ian Lance Taylor872b1682015-07-21 22:34:48 -0700392const cgoExternalThreadSignalSource = `
393package main
394
395/*
396#include <pthread.h>
397
398void **nullptr;
399
400void *crash(void *p) {
401 *nullptr = p;
402 return 0;
403}
404
405int start_crashing_thread(void) {
406 pthread_t tid;
407 return pthread_create(&tid, 0, crash, 0);
408}
409*/
410import "C"
411
412import (
413 "fmt"
414 "os"
415 "os/exec"
416 "time"
417)
418
419func main() {
420 if len(os.Args) > 1 && os.Args[1] == "crash" {
421 i := C.start_crashing_thread()
422 if i != 0 {
423 fmt.Println("pthread_create failed:", i)
424 // Exit with 0 because parent expects us to crash.
425 return
426 }
427
428 // We should crash immediately, but give it plenty of
429 // time before failing (by exiting 0) in case we are
430 // running on a slow system.
431 time.Sleep(5 * time.Second)
432 return
433 }
434
435 out, err := exec.Command(os.Args[0], "crash").CombinedOutput()
436 if err == nil {
437 fmt.Println("C signal did not crash as expected\n")
438 fmt.Printf("%s\n", out)
439 os.Exit(1)
440 }
441
442 fmt.Println("OK")
443}
444`
445
Alex Brainman9b691962015-03-16 15:46:22 +1100446const cgoDLLImportsMainSource = `
447package main
448
449/*
450#include <windows.h>
451
452DWORD getthread() {
453 return GetCurrentThreadId();
454}
455*/
456import "C"
457
458import "./a"
459
460func main() {
461 C.getthread()
462 a.GetThread()
463 println("OK")
464}
465`
466
467const cgoDLLImportsPkgSource = `
468package a
469
470/*
471#cgo CFLAGS: -mnop-fun-dllimport
472
473#include <windows.h>
474
475DWORD agetthread() {
476 return GetCurrentThreadId();
477}
478*/
479import "C"
480
481func GetThread() uint32 {
482 return uint32(C.agetthread())
483}
484`