2012-05-29 23:10:54 -06:00
|
|
|
// Copyright 2012 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
// +build cgo
|
|
|
|
|
|
|
|
package runtime_test
|
|
|
|
|
|
|
|
import (
|
2013-08-07 14:04:28 -06:00
|
|
|
"runtime"
|
2014-10-28 19:53:09 -06:00
|
|
|
"strings"
|
2012-05-29 23:10:54 -06:00
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestCgoCrashHandler(t *testing.T) {
|
2013-02-20 01:15:02 -07:00
|
|
|
testCrashHandler(t, true)
|
2012-05-29 23:10:54 -06:00
|
|
|
}
|
2013-02-28 01:07:26 -07:00
|
|
|
|
|
|
|
func TestCgoSignalDeadlock(t *testing.T) {
|
2013-08-07 14:04:28 -06:00
|
|
|
if testing.Short() && runtime.GOOS == "windows" {
|
|
|
|
t.Skip("Skipping in short mode") // takes up to 64 seconds
|
|
|
|
}
|
2013-02-28 01:07:26 -07:00
|
|
|
got := executeTest(t, cgoSignalDeadlockSource, nil)
|
|
|
|
want := "OK\n"
|
|
|
|
if got != want {
|
|
|
|
t.Fatalf("expected %q, but got %q", want, got)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-07 14:31:52 -06:00
|
|
|
func TestCgoTraceback(t *testing.T) {
|
|
|
|
got := executeTest(t, cgoTracebackSource, nil)
|
|
|
|
want := "OK\n"
|
|
|
|
if got != want {
|
|
|
|
t.Fatalf("expected %q, but got %q", want, got)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-28 19:53:09 -06:00
|
|
|
func TestCgoExternalThreadPanic(t *testing.T) {
|
2014-10-29 17:24:37 -06:00
|
|
|
if runtime.GOOS == "plan9" {
|
2014-10-28 22:02:29 -06:00
|
|
|
t.Skipf("no pthreads on %s", runtime.GOOS)
|
|
|
|
}
|
2014-10-29 17:24:37 -06:00
|
|
|
csrc := cgoExternalThreadPanicC
|
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
csrc = cgoExternalThreadPanicC_windows
|
|
|
|
}
|
|
|
|
got := executeTest(t, cgoExternalThreadPanicSource, nil, "main.c", csrc)
|
2014-10-28 19:53:09 -06:00
|
|
|
want := "panic: BOOM"
|
|
|
|
if !strings.Contains(got, want) {
|
|
|
|
t.Fatalf("want failure containing %q. output:\n%s\n", want, got)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-28 01:07:26 -07:00
|
|
|
const cgoSignalDeadlockSource = `
|
|
|
|
package main
|
|
|
|
|
|
|
|
import "C"
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"runtime"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
runtime.GOMAXPROCS(100)
|
|
|
|
ping := make(chan bool)
|
|
|
|
go func() {
|
|
|
|
for i := 0; ; i++ {
|
|
|
|
runtime.Gosched()
|
|
|
|
select {
|
|
|
|
case done := <-ping:
|
|
|
|
if done {
|
|
|
|
ping <- true
|
|
|
|
return
|
|
|
|
}
|
|
|
|
ping <- true
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
func() {
|
|
|
|
defer func() {
|
|
|
|
recover()
|
|
|
|
}()
|
|
|
|
var s *string
|
|
|
|
*s = ""
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
time.Sleep(time.Millisecond)
|
|
|
|
for i := 0; i < 64; i++ {
|
|
|
|
go func() {
|
|
|
|
runtime.LockOSThread()
|
|
|
|
select {}
|
|
|
|
}()
|
|
|
|
go func() {
|
|
|
|
runtime.LockOSThread()
|
|
|
|
select {}
|
|
|
|
}()
|
|
|
|
time.Sleep(time.Millisecond)
|
|
|
|
ping <- false
|
|
|
|
select {
|
|
|
|
case <-ping:
|
|
|
|
case <-time.After(time.Second):
|
|
|
|
fmt.Printf("HANG\n")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ping <- true
|
|
|
|
select {
|
|
|
|
case <-ping:
|
|
|
|
case <-time.After(time.Second):
|
|
|
|
fmt.Printf("HANG\n")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
fmt.Printf("OK\n")
|
|
|
|
}
|
|
|
|
`
|
2013-08-07 14:31:52 -06:00
|
|
|
|
|
|
|
const cgoTracebackSource = `
|
|
|
|
package main
|
|
|
|
|
|
|
|
/* void foo(void) {} */
|
|
|
|
import "C"
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"runtime"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
C.foo()
|
|
|
|
buf := make([]byte, 1)
|
|
|
|
runtime.Stack(buf, true)
|
|
|
|
fmt.Printf("OK\n")
|
|
|
|
}
|
|
|
|
`
|
2014-10-28 19:53:09 -06:00
|
|
|
|
|
|
|
const cgoExternalThreadPanicSource = `
|
|
|
|
package main
|
|
|
|
|
|
|
|
// void start(void);
|
|
|
|
import "C"
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
C.start()
|
|
|
|
select {}
|
|
|
|
}
|
|
|
|
|
|
|
|
//export gopanic
|
|
|
|
func gopanic() {
|
|
|
|
panic("BOOM")
|
|
|
|
}
|
|
|
|
`
|
|
|
|
|
|
|
|
const cgoExternalThreadPanicC = `
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
|
|
|
|
void gopanic(void);
|
|
|
|
|
|
|
|
static void*
|
|
|
|
die(void* x)
|
|
|
|
{
|
|
|
|
gopanic();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
start(void)
|
|
|
|
{
|
|
|
|
pthread_t t;
|
|
|
|
if(pthread_create(&t, 0, die, 0) != 0)
|
|
|
|
printf("pthread_create failed\n");
|
|
|
|
}
|
|
|
|
`
|
2014-10-29 17:24:37 -06:00
|
|
|
|
|
|
|
const cgoExternalThreadPanicC_windows = `
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
void gopanic(void);
|
|
|
|
|
|
|
|
static void*
|
|
|
|
die(void* x)
|
|
|
|
{
|
|
|
|
gopanic();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
start(void)
|
|
|
|
{
|
|
|
|
if(_beginthreadex(0, 0, die, 0, 0, 0) != 0)
|
|
|
|
printf("_beginthreadex failed\n");
|
|
|
|
}
|
|
|
|
`
|