summaryrefslogtreecommitdiffstats
path: root/misc/cgo/test/testx.go
diff options
context:
space:
mode:
Diffstat (limited to 'misc/cgo/test/testx.go')
-rw-r--r--misc/cgo/test/testx.go564
1 files changed, 564 insertions, 0 deletions
diff --git a/misc/cgo/test/testx.go b/misc/cgo/test/testx.go
new file mode 100644
index 0000000..2b2e69e
--- /dev/null
+++ b/misc/cgo/test/testx.go
@@ -0,0 +1,564 @@
+// Copyright 2011 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.
+
+// Test cases for cgo.
+// Both the import "C" prologue and the main file are sorted by issue number.
+// This file contains //export directives on Go functions
+// and so it must NOT contain C definitions (only declarations).
+// See test.go for C definitions.
+
+package cgotest
+
+import (
+ "runtime"
+ "runtime/debug"
+ "strings"
+ "sync"
+ "sync/atomic"
+ "testing"
+ "time"
+ "unsafe"
+)
+
+/*
+// threads
+extern void doAdd(int, int);
+
+// issue 1328
+extern void BackIntoGo(void);
+void IntoC(void);
+
+// issue 1560
+// mysleep returns the absolute start time in ms.
+long long mysleep(int seconds);
+
+// twoSleep returns the absolute start time of the first sleep
+// in ms.
+long long twoSleep(int);
+
+// issue 3775
+void lockOSThreadCallback(void);
+inline static void lockOSThreadC(void)
+{
+ lockOSThreadCallback();
+}
+int usleep(unsigned usec);
+
+// issue 4054 part 2 - part 1 in test.go
+typedef enum {
+ A = 0,
+ B,
+ C,
+ D,
+ E,
+ F,
+ G,
+ H,
+ II,
+ J,
+} issue4054b;
+
+// issue 5548
+
+extern int issue5548_in_c(void);
+
+// issue 6833
+
+extern unsigned long long issue6833Func(unsigned int, unsigned long long);
+
+// issue 6907
+
+extern int CheckIssue6907C(_GoString_);
+
+// issue 7665
+
+extern void f7665(void);
+
+// issue 7978
+// Stack tracing didn't work during cgo code after calling a Go
+// callback. Make sure GC works and the stack trace is correct.
+
+#include <stdint.h>
+
+void issue7978cb(void);
+
+// use ugly atomic variable sync since that doesn't require calling back into
+// Go code or OS dependencies
+static void issue7978c(uint32_t *sync) {
+ while(__atomic_load_n(sync, __ATOMIC_SEQ_CST) != 0)
+ ;
+ __atomic_add_fetch(sync, 1, __ATOMIC_SEQ_CST);
+ while(__atomic_load_n(sync, __ATOMIC_SEQ_CST) != 2)
+ ;
+ issue7978cb();
+ __atomic_add_fetch(sync, 1, __ATOMIC_SEQ_CST);
+ while(__atomic_load_n(sync, __ATOMIC_SEQ_CST) != 6)
+ ;
+}
+
+// issue 8331 part 2 - part 1 in test.go
+// A typedef of an unnamed struct is the same struct when
+// #include'd twice. No runtime test; just make sure it compiles.
+#include "issue8331.h"
+
+// issue 8945
+
+typedef void (*PFunc8945)();
+extern PFunc8945 func8945; // definition is in test.go
+
+// issue 20910
+void callMulti(void);
+
+// issue 28772 part 2 - part 1 in issuex.go
+#define issue28772Constant2 2
+
+
+// issue 31891
+typedef struct {
+ long obj;
+} Issue31891A;
+
+typedef struct {
+ long obj;
+} Issue31891B;
+
+void callIssue31891(void);
+
+typedef struct {
+ int i;
+} Issue38408, *PIssue38408;
+
+*/
+import "C"
+
+// exports
+
+//export ReturnIntLong
+func ReturnIntLong() (int, C.long) {
+ return 1, 2
+}
+
+//export gc
+func gc() {
+ runtime.GC()
+}
+
+// threads
+
+var sum struct {
+ sync.Mutex
+ i int
+}
+
+//export Add
+func Add(x int) {
+ defer func() {
+ recover()
+ }()
+ sum.Lock()
+ sum.i += x
+ sum.Unlock()
+ var p *int
+ *p = 2
+}
+
+func testCthread(t *testing.T) {
+ if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && runtime.GOARCH == "arm64" {
+ t.Skip("the iOS exec wrapper is unable to properly handle the panic from Add")
+ }
+ sum.i = 0
+ C.doAdd(10, 6)
+
+ want := 10 * (10 - 1) / 2 * 6
+ if sum.i != want {
+ t.Fatalf("sum=%d, want %d", sum.i, want)
+ }
+}
+
+// issue 1328
+
+//export BackIntoGo
+func BackIntoGo() {
+ x := 1
+
+ for i := 0; i < 10000; i++ {
+ xvariadic(x)
+ if x != 1 {
+ panic("x is not 1?")
+ }
+ }
+}
+
+func xvariadic(x ...interface{}) {
+}
+
+func test1328(t *testing.T) {
+ C.IntoC()
+}
+
+// issue 1560
+
+var sleepDone = make(chan int64)
+
+// parallelSleep returns the absolute difference between the start time
+// of the two sleeps.
+func parallelSleep(n int) int64 {
+ t := int64(C.twoSleep(C.int(n))) - <-sleepDone
+ if t < 0 {
+ return -t
+ }
+ return t
+}
+
+//export BackgroundSleep
+func BackgroundSleep(n int32) {
+ go func() {
+ sleepDone <- int64(C.mysleep(C.int(n)))
+ }()
+}
+
+func testParallelSleep(t *testing.T) {
+ sleepSec := 1
+ dt := time.Duration(parallelSleep(sleepSec)) * time.Millisecond
+ t.Logf("difference in start time for two sleep(%d) is %v", sleepSec, dt)
+ // bug used to run sleeps in serial, producing a 2*sleepSec-second delay.
+ // we detect if the start times of those sleeps are > 0.5*sleepSec-second.
+ if dt >= time.Duration(sleepSec)*time.Second/2 {
+ t.Fatalf("parallel %d-second sleeps slept for %f seconds", sleepSec, dt.Seconds())
+ }
+}
+
+// issue 2462
+
+//export exportbyte
+func exportbyte() byte {
+ return 0
+}
+
+//export exportbool
+func exportbool() bool {
+ return false
+}
+
+//export exportrune
+func exportrune() rune {
+ return 0
+}
+
+//export exporterror
+func exporterror() error {
+ return nil
+}
+
+//export exportint
+func exportint() int {
+ return 0
+}
+
+//export exportuint
+func exportuint() uint {
+ return 0
+}
+
+//export exportuintptr
+func exportuintptr() uintptr {
+ return (uintptr)(0)
+}
+
+//export exportint8
+func exportint8() int8 {
+ return 0
+}
+
+//export exportuint8
+func exportuint8() uint8 {
+ return 0
+}
+
+//export exportint16
+func exportint16() int16 {
+ return 0
+}
+
+//export exportuint16
+func exportuint16() uint16 {
+ return 0
+}
+
+//export exportint32
+func exportint32() int32 {
+ return 0
+}
+
+//export exportuint32
+func exportuint32() uint32 {
+ return 0
+}
+
+//export exportint64
+func exportint64() int64 {
+ return 0
+}
+
+//export exportuint64
+func exportuint64() uint64 {
+ return 0
+}
+
+//export exportfloat32
+func exportfloat32() float32 {
+ return 0
+}
+
+//export exportfloat64
+func exportfloat64() float64 {
+ return 0
+}
+
+//export exportcomplex64
+func exportcomplex64() complex64 {
+ return 0
+}
+
+//export exportcomplex128
+func exportcomplex128() complex128 {
+ return 0
+}
+
+// issue 3741
+
+//export exportSliceIn
+func exportSliceIn(s []byte) bool {
+ return len(s) == cap(s)
+}
+
+//export exportSliceOut
+func exportSliceOut() []byte {
+ return []byte{1}
+}
+
+//export exportSliceInOut
+func exportSliceInOut(s []byte) []byte {
+ return s
+}
+
+// issue 3775
+
+func init() {
+ if runtime.GOOS == "android" {
+ return
+ }
+ // Same as test3775 but run during init so that
+ // there are two levels of internal runtime lock
+ // (1 for init, 1 for cgo).
+ // This would have been broken by CL 11663043.
+ C.lockOSThreadC()
+}
+
+func test3775(t *testing.T) {
+ if runtime.GOOS == "android" {
+ return
+ }
+ // Used to panic because of the UnlockOSThread below.
+ C.lockOSThreadC()
+}
+
+//export lockOSThreadCallback
+func lockOSThreadCallback() {
+ runtime.LockOSThread()
+ runtime.UnlockOSThread()
+ go C.usleep(10000)
+ runtime.Gosched()
+}
+
+// issue 4054 part 2 - part 1 in test.go
+
+var issue4054b = []int{C.A, C.B, C.C, C.D, C.E, C.F, C.G, C.H, C.II, C.J}
+
+//export issue5548FromC
+func issue5548FromC(s string, i int) int {
+ if len(s) == 4 && s == "test" && i == 42 {
+ return 12345
+ }
+ println("got", len(s), i)
+ return 9876
+}
+
+func test5548(t *testing.T) {
+ if x := C.issue5548_in_c(); x != 12345 {
+ t.Errorf("issue5548_in_c = %d, want %d", x, 12345)
+ }
+}
+
+// issue 6833
+
+//export GoIssue6833Func
+func GoIssue6833Func(aui uint, aui64 uint64) uint64 {
+ return aui64 + uint64(aui)
+}
+
+func test6833(t *testing.T) {
+ ui := 7
+ ull := uint64(0x4000300020001000)
+ v := uint64(C.issue6833Func(C.uint(ui), C.ulonglong(ull)))
+ exp := uint64(ui) + ull
+ if v != exp {
+ t.Errorf("issue6833Func() returns %x, expected %x", v, exp)
+ }
+}
+
+// issue 6907
+
+const CString = "C string"
+
+//export CheckIssue6907Go
+func CheckIssue6907Go(s string) C.int {
+ if s == CString {
+ return 1
+ }
+ return 0
+}
+
+func test6907Go(t *testing.T) {
+ if got := C.CheckIssue6907C(CString); got != 1 {
+ t.Errorf("C.CheckIssue6907C() == %d, want %d", got, 1)
+ }
+}
+
+// issue 7665
+
+//export f7665
+func f7665() {}
+
+var bad7665 unsafe.Pointer = C.f7665
+var good7665 uintptr = uintptr(C.f7665)
+
+func test7665(t *testing.T) {
+ if bad7665 == nil || uintptr(bad7665) != good7665 {
+ t.Errorf("ptrs = %p, %#x, want same non-nil pointer", bad7665, good7665)
+ }
+}
+
+// issue 7978
+
+var issue7978sync uint32
+
+func issue7978check(t *testing.T, wantFunc string, badFunc string, depth int) {
+ runtime.GC()
+ buf := make([]byte, 65536)
+ trace := string(buf[:runtime.Stack(buf, true)])
+ for _, goroutine := range strings.Split(trace, "\n\n") {
+ if strings.Contains(goroutine, "test.issue7978go") {
+ trace := strings.Split(goroutine, "\n")
+ // look for the expected function in the stack
+ for i := 0; i < depth; i++ {
+ if badFunc != "" && strings.Contains(trace[1+2*i], badFunc) {
+ t.Errorf("bad stack: found %s in the stack:\n%s", badFunc, goroutine)
+ return
+ }
+ if strings.Contains(trace[1+2*i], wantFunc) {
+ return
+ }
+ }
+ t.Errorf("bad stack: didn't find %s in the stack:\n%s", wantFunc, goroutine)
+ return
+ }
+ }
+ t.Errorf("bad stack: goroutine not found. Full stack dump:\n%s", trace)
+}
+
+func issue7978wait(store uint32, wait uint32) {
+ if store != 0 {
+ atomic.StoreUint32(&issue7978sync, store)
+ }
+ for atomic.LoadUint32(&issue7978sync) != wait {
+ runtime.Gosched()
+ }
+}
+
+//export issue7978cb
+func issue7978cb() {
+ // Force a stack growth from the callback to put extra
+ // pressure on the runtime. See issue #17785.
+ growStack(64)
+ issue7978wait(3, 4)
+}
+
+func growStack(n int) int {
+ var buf [128]int
+ if n == 0 {
+ return 0
+ }
+ return buf[growStack(n-1)]
+}
+
+func issue7978go() {
+ C.issue7978c((*C.uint32_t)(&issue7978sync))
+ issue7978wait(7, 8)
+}
+
+func test7978(t *testing.T) {
+ if runtime.Compiler == "gccgo" {
+ t.Skip("gccgo can not do stack traces of C code")
+ }
+ debug.SetTraceback("2")
+ issue7978sync = 0
+ go issue7978go()
+ // test in c code, before callback
+ issue7978wait(0, 1)
+ issue7978check(t, "_Cfunc_issue7978c(", "", 1)
+ // test in go code, during callback
+ issue7978wait(2, 3)
+ issue7978check(t, "test.issue7978cb(", "test.issue7978go", 3)
+ // test in c code, after callback
+ issue7978wait(4, 5)
+ issue7978check(t, "_Cfunc_issue7978c(", "_cgoexpwrap", 1)
+ // test in go code, after return from cgo
+ issue7978wait(6, 7)
+ issue7978check(t, "test.issue7978go(", "", 3)
+ atomic.StoreUint32(&issue7978sync, 8)
+}
+
+// issue 8331 part 2
+
+var issue8331Var C.issue8331
+
+// issue 8945
+
+//export Test8945
+func Test8945() {
+ _ = C.func8945
+}
+
+// issue 20910
+
+//export multi
+func multi() (*C.char, C.int) {
+ return C.CString("multi"), 0
+}
+
+func test20910(t *testing.T) {
+ C.callMulti()
+}
+
+// issue 28772 part 2
+
+const issue28772Constant2 = C.issue28772Constant2
+
+// issue 31891
+
+//export useIssue31891A
+func useIssue31891A(c *C.Issue31891A) {}
+
+//export useIssue31891B
+func useIssue31891B(c *C.Issue31891B) {}
+
+func test31891(t *testing.T) {
+ C.callIssue31891()
+}
+
+// issue 38408
+// A typedef pointer can be used as the element type.
+// No runtime test; just make sure it compiles.
+var _ C.PIssue38408 = &C.Issue38408{i: 1}