123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580 |
- // 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/cgo"
- "runtime/debug"
- "strings"
- "sync"
- "sync/atomic"
- "testing"
- "time"
- "unsafe"
- )
- /*
- // threads
- extern void doAdd(int, int);
- // issue 1328
- 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 lockOSThreadC(void);
- 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>
- // use ugly atomic variable sync since that doesn't require calling back into
- // Go code or OS dependencies
- void issue7978c(uint32_t *sync);
- // 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;
- extern void cfunc49633(void*); // definition is in test.go
- */
- 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
- 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 37033, check if cgo.Handle works properly
- var issue37033 = 42
- //export GoFunc37033
- func GoFunc37033(handle C.uintptr_t) {
- h := cgo.Handle(handle)
- ch := h.Value().(chan int)
- ch <- issue37033
- }
- // 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}
- // issue 49633, example use of cgo.Handle with void*
- type data49633 struct {
- msg string
- }
- //export GoFunc49633
- func GoFunc49633(context unsafe.Pointer) {
- h := *(*cgo.Handle)(context)
- v := h.Value().(*data49633)
- v.msg = "hello"
- }
- func test49633(t *testing.T) {
- v := &data49633{}
- h := cgo.NewHandle(v)
- defer h.Delete()
- C.cfunc49633(unsafe.Pointer(&h))
- if v.msg != "hello" {
- t.Errorf("msg = %q, want 'hello'", v.msg)
- }
- }
|