Commit 8d5ff2e1 authored by Russ Cox's avatar Russ Cox

runtime: move test programs out of source code, coalesce

Now there are just three programs to compile instead of many,
and repeated tests can reuse the compilation result instead of
rebuilding it.

Combined, these changes reduce the time spent testing runtime
during all.bash on my laptop from about 60 to about 30 seconds.
(All.bash itself runs in 5½ minutes.)

For #10571.

Change-Id: Ie2c1798b847f1a635a860d11dcdab14375319ae9
Reviewed-on: https://go-review.googlesource.com/18085Reviewed-by: 's avatarAustin Clements <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
parent a6993205
......@@ -21,18 +21,18 @@ func TestCgoSignalDeadlock(t *testing.T) {
if testing.Short() && runtime.GOOS == "windows" {
t.Skip("Skipping in short mode") // takes up to 64 seconds
}
got := executeTest(t, cgoSignalDeadlockSource, nil)
got := runTestProg(t, "testprogcgo", "CgoSignalDeadlock")
want := "OK\n"
if got != want {
t.Fatalf("expected %q, but got %q", want, got)
t.Fatalf("expected %q, but got:\n%s", want, got)
}
}
func TestCgoTraceback(t *testing.T) {
got := executeTest(t, cgoTracebackSource, nil)
got := runTestProg(t, "testprogcgo", "CgoTraceback")
want := "OK\n"
if got != want {
t.Fatalf("expected %q, but got %q", want, got)
t.Fatalf("expected %q, but got:\n%s", want, got)
}
}
......@@ -48,10 +48,10 @@ func TestCgoCallbackGC(t *testing.T) {
t.Skip("too slow for arm builders")
}
}
got := executeTest(t, cgoCallbackGCSource, nil)
got := runTestProg(t, "testprogcgo", "CgoCallbackGC")
want := "OK\n"
if got != want {
t.Fatalf("expected %q, but got %q", want, got)
t.Fatalf("expected %q, but got:\n%s", want, got)
}
}
......@@ -59,11 +59,7 @@ func TestCgoExternalThreadPanic(t *testing.T) {
if runtime.GOOS == "plan9" {
t.Skipf("no pthreads on %s", runtime.GOOS)
}
csrc := cgoExternalThreadPanicC
if runtime.GOOS == "windows" {
csrc = cgoExternalThreadPanicC_windows
}
got := executeTest(t, cgoExternalThreadPanicSource, nil, "main.c", csrc)
got := runTestProg(t, "testprogcgo", "CgoExternalThreadPanic")
want := "panic: BOOM"
if !strings.Contains(got, want) {
t.Fatalf("want failure containing %q. output:\n%s\n", want, got)
......@@ -94,10 +90,10 @@ func TestCgoExternalThreadSIGPROF(t *testing.T) {
// ppc64 (issue #8912)
t.Skipf("no external linking on ppc64")
}
got := executeTest(t, cgoExternalThreadSIGPROFSource, nil)
got := runTestProg(t, "testprogcgo", "CgoExternalThreadSIGPROF")
want := "OK\n"
if got != want {
t.Fatalf("expected %q, but got %q", want, got)
t.Fatalf("expected %q, but got:\n%s", want, got)
}
}
......@@ -107,10 +103,10 @@ func TestCgoExternalThreadSignal(t *testing.T) {
case "plan9", "windows":
t.Skipf("no pthreads on %s", runtime.GOOS)
}
got := executeTest(t, cgoExternalThreadSignalSource, nil)
got := runTestProg(t, "testprogcgo", "CgoExternalThreadSignal")
want := "OK\n"
if got != want {
t.Fatalf("expected %q, but got %q", want, got)
t.Fatalf("expected %q, but got:\n%s", want, got)
}
}
......@@ -119,371 +115,9 @@ func TestCgoDLLImports(t *testing.T) {
if runtime.GOOS != "windows" {
t.Skip("skipping windows specific test")
}
got := executeTest(t, cgoDLLImportsMainSource, nil, "a/a.go", cgoDLLImportsPkgSource)
got := runTestProg(t, "testprogcgo", "CgoDLLImportsMain")
want := "OK\n"
if got != want {
t.Fatalf("expected %q, but got %v", want, got)
}
}
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")
}
`
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")
}
`
const cgoCallbackGCSource = `
package main
import "runtime"
/*
#include <pthread.h>
void go_callback();
static void *thr(void *arg) {
go_callback();
return 0;
}
static void foo() {
pthread_t th;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 256 << 10);
pthread_create(&th, &attr, thr, 0);
pthread_join(th, 0);
}
*/
import "C"
import "fmt"
//export go_callback
func go_callback() {
runtime.GC()
grow()
runtime.GC()
}
var cnt int
func grow() {
x := 10000
sum := 0
if grow1(&x, &sum) == 0 {
panic("bad")
}
}
func grow1(x, sum *int) int {
if *x == 0 {
return *sum + 1
}
*x--
sum1 := *sum + *x
return grow1(x, &sum1)
}
func main() {
const P = 100
done := make(chan bool)
// allocate a bunch of stack frames and spray them with pointers
for i := 0; i < P; i++ {
go func() {
grow()
done <- true
}()
}
for i := 0; i < P; i++ {
<-done
}
// now give these stack frames to cgo callbacks
for i := 0; i < P; i++ {
go func() {
C.foo()
done <- true
}()
}
for i := 0; i < P; i++ {
<-done
}
fmt.Printf("OK\n")
}
`
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");
}
`
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");
}
`
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 https://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")
}
`
const cgoExternalThreadSignalSource = `
package main
/*
#include <pthread.h>
void **nullptr;
void *crash(void *p) {
*nullptr = p;
return 0;
}
int start_crashing_thread(void) {
pthread_t tid;
return pthread_create(&tid, 0, crash, 0);
}
*/
import "C"
import (
"fmt"
"os"
"os/exec"
"time"
)
func main() {
if len(os.Args) > 1 && os.Args[1] == "crash" {
i := C.start_crashing_thread()
if i != 0 {
fmt.Println("pthread_create failed:", i)
// Exit with 0 because parent expects us to crash.
return
}
// We should crash immediately, but give it plenty of
// time before failing (by exiting 0) in case we are
// running on a slow system.
time.Sleep(5 * time.Second)
return
}
out, err := exec.Command(os.Args[0], "crash").CombinedOutput()
if err == nil {
fmt.Println("C signal did not crash as expected\n")
fmt.Printf("%s\n", out)
os.Exit(1)
}
fmt.Println("OK")
}
`
const cgoDLLImportsMainSource = `
package main
/*
#include <windows.h>
DWORD getthread() {
return GetCurrentThreadId();
}
*/
import "C"
import "./a"
func main() {
C.getthread()
a.GetThread()
println("OK")
}
`
const cgoDLLImportsPkgSource = `
package a
/*
#cgo CFLAGS: -mnop-fun-dllimport
#include <windows.h>
DWORD agetthread() {
return GetCurrentThreadId();
}
*/
import "C"
func GetThread() uint32 {
return uint32(C.agetthread())
}
`
This diff is collapsed.
......@@ -19,59 +19,13 @@ func TestGcSys(t *testing.T) {
if os.Getenv("GOGC") == "off" {
t.Skip("skipping test; GOGC=off in environment")
}
data := struct{ Short bool }{testing.Short()}
got := executeTest(t, testGCSysSource, &data)
got := runTestProg(t, "testprog", "GCSys")
want := "OK\n"
if got != want {
t.Fatalf("expected %q, but got %q", want, got)
}
}
const testGCSysSource = `
package main
import (
"fmt"
"runtime"
)
func main() {
runtime.GOMAXPROCS(1)
memstats := new(runtime.MemStats)
runtime.GC()
runtime.ReadMemStats(memstats)
sys := memstats.Sys
runtime.MemProfileRate = 0 // disable profiler
itercount := 1000000
{{if .Short}}
itercount = 100000
{{end}}
for i := 0; i < itercount; i++ {
workthegc()
}
// Should only be using a few MB.
// We allocated 100 MB or (if not short) 1 GB.
runtime.ReadMemStats(memstats)
if sys > memstats.Sys {
sys = 0
} else {
sys = memstats.Sys - sys
}
if sys > 16<<20 {
fmt.Printf("using too much memory: %d bytes\n", sys)
return
}
fmt.Printf("OK\n")
}
func workthegc() []byte {
return make([]byte, 1029)
}
`
func TestGcDeepNesting(t *testing.T) {
type T [2][2][2][2][2][2][2][2][2][2]*int
a := new(T)
......
......@@ -329,48 +329,13 @@ func TestPreemptionGC(t *testing.T) {
}
func TestGCFairness(t *testing.T) {
output := executeTest(t, testGCFairnessSource, nil)
output := runTestProg(t, "testprog", "GCFairness")
want := "OK\n"
if output != want {
t.Fatalf("want %s, got %s\n", want, output)
}
}
const testGCFairnessSource = `
package main
import (
"fmt"
"os"
"runtime"
"time"
)
func main() {
runtime.GOMAXPROCS(1)
f, err := os.Open("/dev/null")
if os.IsNotExist(err) {
// This test tests what it is intended to test only if writes are fast.
// If there is no /dev/null, we just don't execute the test.
fmt.Println("OK")
return
}
if err != nil {
fmt.Println(err)
os.Exit(1)
}
for i := 0; i < 2; i++ {
go func() {
for {
f.Write([]byte("."))
}
}()
}
time.Sleep(10 * time.Millisecond)
fmt.Println("OK")
}
`
func TestPingPongHog(t *testing.T) {
if testing.Short() {
t.Skip("skipping in -short mode")
......
......@@ -125,7 +125,7 @@ func TestStringW(t *testing.T) {
}
func TestLargeStringConcat(t *testing.T) {
output := executeTest(t, largeStringConcatSource, nil)
output := runTestProg(t, "testprog", "stringconcat")
want := "panic: " + strings.Repeat("0", 1<<10) + strings.Repeat("1", 1<<10) +
strings.Repeat("2", 1<<10) + strings.Repeat("3", 1<<10)
if !strings.HasPrefix(output, want) {
......@@ -133,19 +133,6 @@ func TestLargeStringConcat(t *testing.T) {
}
}
var largeStringConcatSource = `
package main
import "strings"
func main() {
s0 := strings.Repeat("0", 1<<10)
s1 := strings.Repeat("1", 1<<10)
s2 := strings.Repeat("2", 1<<10)
s3 := strings.Repeat("3", 1<<10)
s := s0 + s1 + s2 + s3
panic(s)
}
`
func TestGostringnocopy(t *testing.T) {
max := *runtime.Maxstring
b := make([]byte, max+10)
......
......@@ -500,7 +500,7 @@ func TestOutputDebugString(t *testing.T) {
}
func TestRaiseException(t *testing.T) {
o := executeTest(t, raiseExceptionSource, nil)
o := runTestProg(t, "testprog", "RaiseException")
if strings.Contains(o, "RaiseException should not return") {
t.Fatalf("RaiseException did not crash program: %v", o)
}
......@@ -509,35 +509,13 @@ func TestRaiseException(t *testing.T) {
}
}
const raiseExceptionSource = `
package main
import "syscall"
func main() {
const EXCEPTION_NONCONTINUABLE = 1
mod := syscall.MustLoadDLL("kernel32.dll")
proc := mod.MustFindProc("RaiseException")
proc.Call(0xbad, EXCEPTION_NONCONTINUABLE, 0, 0)
println("RaiseException should not return")
}
`
func TestZeroDivisionException(t *testing.T) {
o := executeTest(t, zeroDivisionExceptionSource, nil)
o := runTestProg(t, "testprog", "ZeroDivisionException")
if !strings.Contains(o, "panic: runtime error: integer divide by zero") {
t.Fatalf("No stack trace: %v", o)
}
}
const zeroDivisionExceptionSource = `
package main
func main() {
x := 1
y := 0
z := x / y
println(z)
}
`
func TestWERDialogue(t *testing.T) {
if os.Getenv("TESTING_WER_DIALOGUE") == "1" {
defer os.Exit(0)
......
// Copyright 2015 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.
package main
import (
"fmt"
"runtime"
)
func init() {
register("Crash", Crash)
}
func test(name string) {
defer func() {
if x := recover(); x != nil {
fmt.Printf(" recovered")
}
fmt.Printf(" done\n")
}()
fmt.Printf("%s:", name)
var s *string
_ = *s
fmt.Print("SHOULD NOT BE HERE")
}
func testInNewThread(name string) {
c := make(chan bool)
go func() {
runtime.LockOSThread()
test(name)
c <- true
}()
<-c
}
func Crash() {
runtime.LockOSThread()
test("main")
testInNewThread("new-thread")
testInNewThread("second-new-thread")
test("main-again")
}
// Copyright 2015 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.
package main
import (
"fmt"
"runtime"
"runtime/debug"
"time"
)
func init() {
registerInit("InitDeadlock", InitDeadlock)
registerInit("NoHelperGoroutines", NoHelperGoroutines)
register("SimpleDeadlock", SimpleDeadlock)
register("LockedDeadlock", LockedDeadlock)
register("LockedDeadlock2", LockedDeadlock2)
register("GoexitDeadlock", GoexitDeadlock)
register("StackOverflow", StackOverflow)
register("ThreadExhaustion", ThreadExhaustion)
register("RecursivePanic", RecursivePanic)
register("GoexitExit", GoexitExit)
register("GoNil", GoNil)
register("MainGoroutineID", MainGoroutineID)
register("Breakpoint", Breakpoint)
register("GoexitInPanic", GoexitInPanic)
register("PanicAfterGoexit", PanicAfterGoexit)
register("RecoveredPanicAfterGoexit", RecoveredPanicAfterGoexit)
}
func SimpleDeadlock() {
select {}
panic("not reached")
}
func InitDeadlock() {
select {}
panic("not reached")
}
func LockedDeadlock() {
runtime.LockOSThread()
select {}
}
func LockedDeadlock2() {
go func() {
runtime.LockOSThread()
select {}
}()
time.Sleep(time.Millisecond)
select {}
}
func GoexitDeadlock() {
F := func() {
for i := 0; i < 10; i++ {
}
}
go F()
go F()
runtime.Goexit()
}
func StackOverflow() {
var f func() byte
f = func() byte {
var buf [64 << 10]byte
return buf[0] + f()
}
debug.SetMaxStack(1474560)
f()
}
func ThreadExhaustion() {
debug.SetMaxThreads(10)
c := make(chan int)
for i := 0; i < 100; i++ {
go func() {
runtime.LockOSThread()
c <- 0
select {}
}()
<-c
}
}
func RecursivePanic() {
func() {
defer func() {
fmt.Println(recover())
}()
var x [8192]byte
func(x [8192]byte) {
defer func() {
if err := recover(); err != nil {
panic("wrap: " + err.(string))
}
}()
panic("bad")
}(x)
}()
panic("again")
}
func GoexitExit() {
go func() {
time.Sleep(time.Millisecond)
}()
i := 0
runtime.SetFinalizer(&i, func(p *int) {})
runtime.GC()
runtime.Goexit()
}
func GoNil() {
defer func() {
recover()
}()
var f func()
go f()
select {}
}
func MainGoroutineID() {
panic("test")
}
func NoHelperGoroutines() {
i := 0
runtime.SetFinalizer(&i, func(p *int) {})
time.AfterFunc(time.Hour, func() {})
panic("oops")
}
func Breakpoint() {
runtime.Breakpoint()
}
func GoexitInPanic() {
go func() {
defer func() {
runtime.Goexit()
}()
panic("hello")
}()
runtime.Goexit()
}
func PanicAfterGoexit() {
defer func() {
panic("hello")
}()
runtime.Goexit()
}
func RecoveredPanicAfterGoexit() {
defer func() {
defer func() {
r := recover()
if r == nil {
panic("bad recover")
}
}()
panic("hello")
}()
runtime.Goexit()
}
// Copyright 2015 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.
package main
import (
"fmt"
"os"
"runtime"
"time"
)
func init() {
register("GCFairness", GCFairness)
register("GCSys", GCSys)
}
func GCSys() {
runtime.GOMAXPROCS(1)
memstats := new(runtime.MemStats)
runtime.GC()
runtime.ReadMemStats(memstats)
sys := memstats.Sys
runtime.MemProfileRate = 0 // disable profiler
itercount := 100000
for i := 0; i < itercount; i++ {
workthegc()
}
// Should only be using a few MB.
// We allocated 100 MB or (if not short) 1 GB.
runtime.ReadMemStats(memstats)
if sys > memstats.Sys {
sys = 0
} else {
sys = memstats.Sys - sys
}
if sys > 16<<20 {
fmt.Printf("using too much memory: %d bytes\n", sys)
return
}
fmt.Printf("OK\n")
}
func workthegc() []byte {
return make([]byte, 1029)
}
func GCFairness() {
runtime.GOMAXPROCS(1)
f, err := os.Open("/dev/null")
if os.IsNotExist(err) {
// This test tests what it is intended to test only if writes are fast.
// If there is no /dev/null, we just don't execute the test.
fmt.Println("OK")
return
}
if err != nil {
fmt.Println(err)
os.Exit(1)
}
for i := 0; i < 2; i++ {
go func() {
for {
f.Write([]byte("."))
}
}()
}
time.Sleep(10 * time.Millisecond)
fmt.Println("OK")
}
// Copyright 2015 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.
package main
import "os"
var cmds = map[string]func(){}
func register(name string, f func()) {
if cmds[name] != nil {
panic("duplicate registration: " + name)
}
cmds[name] = f
}
func registerInit(name string, f func()) {
if len(os.Args) >= 2 && os.Args[1] == name {
f()
}
}
func main() {
if len(os.Args) < 2 {
println("usage: "+os.Args[0]+" name-of-test")
return
}
f := cmds[os.Args[1]]
if f == nil {
println("unknown function: " + os.Args[1])
return
}
f()
}
// Copyright 2015 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.
package main
import "strings"
func init() {
register("stringconcat", stringconcat)
}
func stringconcat() {
s0 := strings.Repeat("0", 1<<10)
s1 := strings.Repeat("1", 1<<10)
s2 := strings.Repeat("2", 1<<10)
s3 := strings.Repeat("3", 1<<10)
s := s0 + s1 + s2 + s3
panic(s)
}
// Copyright 2015 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.
package main
import "syscall"
func init() {
register("RaiseException", RaiseException)
register("ZeroDivisionException", ZeroDivisionException)
}
func RaiseException() {
const EXCEPTION_NONCONTINUABLE = 1
mod := syscall.MustLoadDLL("kernel32.dll")
proc := mod.MustFindProc("RaiseException")
proc.Call(0xbad, EXCEPTION_NONCONTINUABLE, 0, 0)
println("RaiseException should not return")
}
func ZeroDivisionException() {
x := 1
y := 0
z := x / y
println(z)
}
// Copyright 2015 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 !plan9,!windows
package main
/*
#include <pthread.h>
void go_callback();
static void *thr(void *arg) {
go_callback();
return 0;
}
static void foo() {
pthread_t th;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 256 << 10);
pthread_create(&th, &attr, thr, 0);
pthread_join(th, 0);
}
*/
import "C"
import (
"fmt"
"runtime"
)
func init() {
register("CgoCallbackGC", CgoCallbackGC)
}
//export go_callback
func go_callback() {
runtime.GC()
grow()
runtime.GC()
}
var cnt int
func grow() {
x := 10000
sum := 0
if grow1(&x, &sum) == 0 {
panic("bad")
}
}
func grow1(x, sum *int) int {
if *x == 0 {
return *sum + 1
}
*x--
sum1 := *sum + *x
return grow1(x, &sum1)
}
func CgoCallbackGC() {
const P = 100
done := make(chan bool)
// allocate a bunch of stack frames and spray them with pointers
for i := 0; i < P; i++ {
go func() {
grow()
done <- true
}()
}
for i := 0; i < P; i++ {
<-done
}
// now give these stack frames to cgo callbacks
for i := 0; i < P; i++ {
go func() {
C.foo()
done <- true
}()
}
for i := 0; i < P; i++ {
<-done
}
fmt.Printf("OK\n")
}
// Copyright 2015 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.
package main
/*
void foo1(void) {}
*/
import "C"
import (
"fmt"
"runtime"
"time"
)
func init() {
register("CgoSignalDeadlock", CgoSignalDeadlock)
register("CgoTraceback", CgoTraceback)
}
func CgoSignalDeadlock() {
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")
}
func CgoTraceback() {
C.foo1()
buf := make([]byte, 1)
runtime.Stack(buf, true)
fmt.Printf("OK\n")
}
// Copyright 2015 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.
package main
import (
"fmt"
"runtime"
)
func init() {
register("Crash", Crash)
}
func test(name string) {
defer func() {
if x := recover(); x != nil {
fmt.Printf(" recovered")
}
fmt.Printf(" done\n")
}()
fmt.Printf("%s:", name)
var s *string
_ = *s
fmt.Print("SHOULD NOT BE HERE")
}
func testInNewThread(name string) {
c := make(chan bool)
go func() {
runtime.LockOSThread()
test(name)
c <- true
}()
<-c
}
func Crash() {
runtime.LockOSThread()
test("main")
testInNewThread("new-thread")
testInNewThread("second-new-thread")
test("main-again")
}
// Copyright 2015 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.
package main
/*
#include <windows.h>
DWORD getthread() {
return GetCurrentThreadId();
}
*/
import "C"
import "./windows"
func init() {
register("CgoDLLImportsMain", CgoDLLImportsMain)
}
func CgoDLLImportsMain() {
C.getthread()
windows.GetThread()
println("OK")
}
// Copyright 2015 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.
package main
import "os"
var cmds = map[string]func(){}
func register(name string, f func()) {
if cmds[name] != nil {
panic("duplicate registration: " + name)
}
cmds[name] = f
}
func registerInit(name string, f func()) {
if len(os.Args) >= 2 && os.Args[1] == name {
f()
}
}
func main() {
if len(os.Args) < 2 {
println("usage: "+os.Args[0]+" name-of-test")
return
}
f := cmds[os.Args[1]]
if f == nil {
println("unknown function: " + os.Args[1])
return
}
f()
}
// Copyright 2015 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 !plan9
package main
// void start(void);
import "C"
func init() {
register("CgoExternalThreadPanic", CgoExternalThreadPanic)
}
func CgoExternalThreadPanic() {
C.start()
select {}
}
//export gopanic
func gopanic() {
panic("BOOM")
}
// Copyright 2015 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 !plan9,!windows
#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");
}
// Copyright 2015 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.
#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");
}
// Copyright 2015 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 !plan9,!windows
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);
}
void **nullptr;
void *crash(void *p) {
*nullptr = p;
return 0;
}
int start_crashing_thread(void) {
pthread_t tid;
return pthread_create(&tid, 0, crash, 0);
}
*/
import "C"
import (
"fmt"
"os"
"os/exec"
"runtime"
"sync/atomic"
"time"
"unsafe"
)
func init() {
register("CgoExternalThreadSIGPROF", CgoExternalThreadSIGPROF)
register("CgoExternalThreadSignal", CgoExternalThreadSignal)
}
func CgoExternalThreadSIGPROF() {
// 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 https://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")
}
func CgoExternalThreadSignal() {
if len(os.Args) > 2 && os.Args[2] == "crash" {
i := C.start_crashing_thread()
if i != 0 {
fmt.Println("pthread_create failed:", i)
// Exit with 0 because parent expects us to crash.
return
}
// We should crash immediately, but give it plenty of
// time before failing (by exiting 0) in case we are
// running on a slow system.
time.Sleep(5 * time.Second)
return
}
out, err := exec.Command(os.Args[0], "CgoExternalThreadSignal", "crash").CombinedOutput()
if err == nil {
fmt.Println("C signal did not crash as expected\n")
fmt.Printf("%s\n", out)
os.Exit(1)
}
fmt.Println("OK")
}
package windows
/*
#cgo CFLAGS: -mnop-fun-dllimport
#include <windows.h>
DWORD agetthread() {
return GetCurrentThreadId();
}
*/
import "C"
func GetThread() uint32 {
return uint32(C.agetthread())
}
// Copyright 2015 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.
package main
import "os"
var cmds = map[string]func(){}
func register(name string, f func()) {
if cmds[name] != nil {
panic("duplicate registration: " + name)
}
cmds[name] = f
}
func registerInit(name string, f func()) {
if len(os.Args) >= 2 && os.Args[1] == name {
f()
}
}
func main() {
if len(os.Args) < 2 {
println("usage: "+os.Args[0]+" name-of-test")
return
}
f := cmds[os.Args[1]]
if f == nil {
println("unknown function: " + os.Args[1])
return
}
f()
}
// Copyright 2015 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.
package main
import (
"fmt"
"net"
)
func init() {
registerInit("NetpollDeadlock", NetpollDeadlockInit)
register("NetpollDeadlock", NetpollDeadlock)
}
func NetpollDeadlockInit() {
fmt.Println("dialing")
c, err := net.Dial("tcp", "localhost:14356")
if err == nil {
c.Close()
} else {
fmt.Println("error: ", err)
}
}
func NetpollDeadlock() {
fmt.Println("done")
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment