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 (
|
2015-01-02 22:12:34 -07:00
|
|
|
"os/exec"
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-27 17:15:38 -07:00
|
|
|
func TestCgoExternalThreadSIGPROF(t *testing.T) {
|
|
|
|
// issue 9456.
|
2014-12-31 23:10:39 -07:00
|
|
|
switch runtime.GOOS {
|
|
|
|
case "plan9", "windows":
|
2014-12-27 17:15:38 -07:00
|
|
|
t.Skipf("no pthreads on %s", runtime.GOOS)
|
2014-12-31 23:10:39 -07:00
|
|
|
case "darwin":
|
|
|
|
// static constructor needs external linking, but we don't support
|
|
|
|
// external linking on OS X 10.6.
|
2015-01-02 22:12:34 -07:00
|
|
|
out, err := exec.Command("uname", "-r").Output()
|
2014-12-31 23:10:39 -07:00
|
|
|
if err != nil {
|
2015-01-02 22:12:34 -07:00
|
|
|
t.Fatalf("uname -r failed: %v", err)
|
2014-12-31 23:10:39 -07:00
|
|
|
}
|
|
|
|
// OS X 10.6 == Darwin 10.x
|
2015-01-02 22:12:34 -07:00
|
|
|
if strings.HasPrefix(string(out), "10.") {
|
2014-12-31 23:10:39 -07:00
|
|
|
t.Skipf("no external linking on OS X 10.6")
|
|
|
|
}
|
2014-12-27 17:15:38 -07:00
|
|
|
}
|
|
|
|
got := executeTest(t, cgoExternalThreadSIGPROFSource, nil)
|
|
|
|
want := "OK\n"
|
|
|
|
if got != want {
|
|
|
|
t.Fatalf("expected %q, but got %q", 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");
|
|
|
|
}
|
|
|
|
`
|
2014-12-27 17:15:38 -07:00
|
|
|
|
|
|
|
const cgoExternalThreadSIGPROFSource = `
|
|
|
|
package main
|
|
|
|
|
|
|
|
/*
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
|
|
|
|
volatile int32_t spinlock;
|
|
|
|
|
|
|
|
static void *thread1(void *p) {
|
|
|
|
(void)p;
|
|
|
|
while (spinlock == 0)
|
|
|
|
;
|
|
|
|
pthread_kill(pthread_self(), SIGPROF);
|
|
|
|
spinlock = 0;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
__attribute__((constructor)) void issue9456() {
|
|
|
|
pthread_t tid;
|
|
|
|
pthread_create(&tid, 0, thread1, NULL);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
import "C"
|
|
|
|
|
|
|
|
import (
|
|
|
|
"runtime"
|
|
|
|
"sync/atomic"
|
|
|
|
"unsafe"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
// This test intends to test that sending SIGPROF to foreign threads
|
|
|
|
// before we make any cgo call will not abort the whole process, so
|
|
|
|
// we cannot make any cgo call here. See http://golang.org/issue/9456.
|
|
|
|
atomic.StoreInt32((*int32)(unsafe.Pointer(&C.spinlock)), 1)
|
|
|
|
for atomic.LoadInt32((*int32)(unsafe.Pointer(&C.spinlock))) == 1 {
|
|
|
|
runtime.Gosched()
|
|
|
|
}
|
|
|
|
println("OK")
|
|
|
|
}
|
|
|
|
`
|