1
0
mirror of https://github.com/golang/go synced 2024-11-19 10:24:43 -07:00
go/misc/cgo/test/callback.go
Russ Cox f985638b94 misc/cgo/test: run tests
The new gotest ignores Test functions outside *_test.go files
(the old shell script allowed them), so replace one clumsy hack
with another.

The root problem is that the package makefiles only know
how to run cgo for source files in the package proper, not
for test files.  Making it work for test files is probably more
trouble than it's worth.

R=bradfitz
CC=golang-dev
https://golang.org/cl/4452060
2011-05-02 13:55:51 -04:00

137 lines
2.6 KiB
Go

package cgotest
/*
void callback(void *f);
void callGoFoo(void) {
extern void goFoo(void);
goFoo();
}
*/
import "C"
import (
"runtime"
"testing"
"unsafe"
)
// nestedCall calls into C, back into Go, and finally to f.
func nestedCall(f func()) {
// NOTE: Depends on representation of f.
// callback(x) calls goCallback(x)
C.callback(*(*unsafe.Pointer)(unsafe.Pointer(&f)))
}
//export goCallback
func goCallback(p unsafe.Pointer) {
(*(*func())(unsafe.Pointer(&p)))()
}
func testCallback(t *testing.T) {
var x = false
nestedCall(func() { x = true })
if !x {
t.Fatal("nestedCall did not call func")
}
}
func testCallbackGC(t *testing.T) {
nestedCall(runtime.GC)
}
func lockedOSThread() bool // in runtime.c
func testCallbackPanic(t *testing.T) {
// Make sure panic during callback unwinds properly.
if lockedOSThread() {
t.Fatal("locked OS thread on entry to TestCallbackPanic")
}
defer func() {
s := recover()
if s == nil {
t.Fatal("did not panic")
}
if s.(string) != "callback panic" {
t.Fatal("wrong panic:", s)
}
if lockedOSThread() {
t.Fatal("locked OS thread on exit from TestCallbackPanic")
}
}()
nestedCall(func() { panic("callback panic") })
panic("nestedCall returned")
}
func testCallbackPanicLoop(t *testing.T) {
// Make sure we don't blow out m->g0 stack.
for i := 0; i < 100000; i++ {
TestCallbackPanic(t)
}
}
func testCallbackPanicLocked(t *testing.T) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
if !lockedOSThread() {
t.Fatal("runtime.LockOSThread didn't")
}
defer func() {
s := recover()
if s == nil {
t.Fatal("did not panic")
}
if s.(string) != "callback panic" {
t.Fatal("wrong panic:", s)
}
if !lockedOSThread() {
t.Fatal("lost lock on OS thread after panic")
}
}()
nestedCall(func() { panic("callback panic") })
panic("nestedCall returned")
}
// Callback with zero arguments used to make the stack misaligned,
// which broke the garbage collector and other things.
func testZeroArgCallback(t *testing.T) {
defer func() {
s := recover()
if s != nil {
t.Fatal("panic during callback:", s)
}
}()
C.callGoFoo()
}
//export goFoo
func goFoo() {
x := 1
for i := 0; i < 10000; i++ {
// variadic call mallocs + writes to
variadic(x, x, x)
if x != 1 {
panic("bad x")
}
}
}
func variadic(x ...interface{}) {}
func testBlocking(t *testing.T) {
c := make(chan int)
go func() {
for i := 0; i < 10; i++ {
c <- <-c
}
}()
nestedCall(func() {
for i := 0; i < 10; i++ {
c <- i
if j := <-c; j != i {
t.Errorf("out of sync %d != %d", j, i)
}
}
})
}