diff options
author | Changkun Ou <hi@changkun.de> | 2021-02-23 09:58:14 +0100 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2021-04-06 23:39:42 +0000 |
commit | 972e8839254d59dc04a1193c4c9633a74595a2e7 (patch) | |
tree | 51a67555636f9e9aebddb52022baba14bdefb95d /misc | |
parent | b084073b53bfc4236d95819a3cc34dcbb4f15392 (diff) | |
download | go-972e8839254d59dc04a1193c4c9633a74595a2e7.tar.gz go-972e8839254d59dc04a1193c4c9633a74595a2e7.zip |
runtime/cgo: add Handle for managing (c)go pointers
A non-trivial Cgo program may need to use callbacks and interact with
go objects per goroutine. Because of the rules for passing pointers
between Go and C, such a program needs to store handles to associated
Go values. This often causes much extra effort to figure out a way to
correctly deal with: 1) map collision; 2) identifying leaks and 3)
concurrency.
This CL implements a Handle representation in runtime/cgo package, and
related methods such as Value, Delete, etc. which allows Go users can
use a standard way to handle the above difficulties.
In addition, the CL allows a Go value to have multiple handles, and the
NewHandle always returns a different handle compare to the previously
returned handles. In comparison, CL 294670 implements a different
behavior of NewHandle that returns a unique handle when the Go value is
referring to the same object.
Benchmark:
name time/op
Handle/non-concurrent-16 487ns ± 1%
Handle/concurrent-16 674ns ± 1%
Fixes #37033
Change-Id: I0eadb9d44332fffef8fb567c745246a49dd6d4c1
Reviewed-on: https://go-review.googlesource.com/c/go/+/295369
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Trust: Cherry Zhang <cherryyz@google.com>
Diffstat (limited to 'misc')
-rw-r--r-- | misc/cgo/test/cgo_test.go | 1 | ||||
-rw-r--r-- | misc/cgo/test/test.go | 22 | ||||
-rw-r--r-- | misc/cgo/test/testx.go | 12 |
3 files changed, 35 insertions, 0 deletions
diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go index f7a76d047b..837307263a 100644 --- a/misc/cgo/test/cgo_test.go +++ b/misc/cgo/test/cgo_test.go @@ -80,6 +80,7 @@ func TestNamedEnum(t *testing.T) { testNamedEnum(t) } func TestCastToEnum(t *testing.T) { testCastToEnum(t) } func TestErrno(t *testing.T) { testErrno(t) } func TestFpVar(t *testing.T) { testFpVar(t) } +func TestHandle(t *testing.T) { testHandle(t) } func TestHelpers(t *testing.T) { testHelpers(t) } func TestLibgcc(t *testing.T) { testLibgcc(t) } func TestMultipleAssign(t *testing.T) { testMultipleAssign(t) } diff --git a/misc/cgo/test/test.go b/misc/cgo/test/test.go index 65823b1ca0..76afa524c3 100644 --- a/misc/cgo/test/test.go +++ b/misc/cgo/test/test.go @@ -899,6 +899,10 @@ static uint16_t issue31093F(uint16_t v) { return v; } // issue 32579 typedef struct S32579 { unsigned char data[1]; } S32579; +// issue 37033, cgo.Handle +extern void GoFunc37033(uintptr_t handle); +void cFunc37033(uintptr_t handle) { GoFunc37033(handle); } + // issue 38649 // Test that #define'd type aliases work. #define netbsd_gid unsigned int @@ -920,6 +924,7 @@ import ( "os/signal" "reflect" "runtime" + "runtime/cgo" "sync" "syscall" "testing" @@ -2230,6 +2235,23 @@ func test32579(t *testing.T) { } } +// issue 37033, check if cgo.Handle works properly + +func testHandle(t *testing.T) { + ch := make(chan int) + + for i := 0; i < 42; i++ { + h := cgo.NewHandle(ch) + go func() { + C.cFunc37033(C.uintptr_t(h)) + }() + if v := <-ch; issue37033 != v { + t.Fatalf("unexpected receiving value: got %d, want %d", v, issue37033) + } + h.Delete() + } +} + // issue 38649 var issue38649 C.netbsd_gid = 42 diff --git a/misc/cgo/test/testx.go b/misc/cgo/test/testx.go index 2b2e69ec00..044c5bceff 100644 --- a/misc/cgo/test/testx.go +++ b/misc/cgo/test/testx.go @@ -12,6 +12,7 @@ package cgotest import ( "runtime" + "runtime/cgo" "runtime/debug" "strings" "sync" @@ -558,6 +559,17 @@ 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. |