diff options
Diffstat (limited to 'src/cmd/cgo/internal')
-rw-r--r-- | src/cmd/cgo/internal/test/cgo_test.go | 7 | ||||
-rw-r--r-- | src/cmd/cgo/internal/test/cthread_unix.c | 24 | ||||
-rw-r--r-- | src/cmd/cgo/internal/test/cthread_windows.c | 22 | ||||
-rw-r--r-- | src/cmd/cgo/internal/test/testx.go | 14 | ||||
-rw-r--r-- | src/cmd/cgo/internal/testcarchive/carchive_test.go | 54 | ||||
-rw-r--r-- | src/cmd/cgo/internal/testcarchive/testdata/libgo9/a.go | 14 | ||||
-rw-r--r-- | src/cmd/cgo/internal/testcarchive/testdata/main9.c | 24 | ||||
-rw-r--r-- | src/cmd/cgo/internal/testsanitizers/testdata/tsan14.go | 53 | ||||
-rw-r--r-- | src/cmd/cgo/internal/testsanitizers/tsan_test.go | 1 |
9 files changed, 210 insertions, 3 deletions
diff --git a/src/cmd/cgo/internal/test/cgo_test.go b/src/cmd/cgo/internal/test/cgo_test.go index 5a07c4c0fa..5e02888b3d 100644 --- a/src/cmd/cgo/internal/test/cgo_test.go +++ b/src/cmd/cgo/internal/test/cgo_test.go @@ -106,6 +106,7 @@ func TestThreadLock(t *testing.T) { testThreadLockFunc(t) } func TestUnsignedInt(t *testing.T) { testUnsignedInt(t) } func TestZeroArgCallback(t *testing.T) { testZeroArgCallback(t) } -func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) } -func BenchmarkGoString(b *testing.B) { benchGoString(b) } -func BenchmarkCGoCallback(b *testing.B) { benchCallback(b) } +func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) } +func BenchmarkGoString(b *testing.B) { benchGoString(b) } +func BenchmarkCGoCallback(b *testing.B) { benchCallback(b) } +func BenchmarkCGoInCThread(b *testing.B) { benchCGoInCthread(b) } diff --git a/src/cmd/cgo/internal/test/cthread_unix.c b/src/cmd/cgo/internal/test/cthread_unix.c index b6ec39816b..d0da643158 100644 --- a/src/cmd/cgo/internal/test/cthread_unix.c +++ b/src/cmd/cgo/internal/test/cthread_unix.c @@ -32,3 +32,27 @@ doAdd(int max, int nthread) for(i=0; i<nthread; i++) pthread_join(thread_id[i], 0); } + +static void* +goDummyCallbackThread(void* p) +{ + int i, max; + + max = *(int*)p; + for(i=0; i<max; i++) + goDummy(); + return NULL; +} + +int +callGoInCThread(int max) +{ + pthread_t thread; + + if (pthread_create(&thread, NULL, goDummyCallbackThread, (void*)(&max)) != 0) + return -1; + if (pthread_join(thread, NULL) != 0) + return -1; + + return max; +} diff --git a/src/cmd/cgo/internal/test/cthread_windows.c b/src/cmd/cgo/internal/test/cthread_windows.c index 3a62ddd373..4e52209dee 100644 --- a/src/cmd/cgo/internal/test/cthread_windows.c +++ b/src/cmd/cgo/internal/test/cthread_windows.c @@ -35,3 +35,25 @@ doAdd(int max, int nthread) CloseHandle((HANDLE)thread_id[i]); } } + +__stdcall +static unsigned int +goDummyCallbackThread(void* p) +{ + int i, max; + + max = *(int*)p; + for(i=0; i<max; i++) + goDummy(); + return 0; +} + +int +callGoInCThread(int max) +{ + uintptr_t thread_id; + thread_id = _beginthreadex(0, 0, goDummyCallbackThread, &max, 0, 0); + WaitForSingleObject((HANDLE)thread_id, INFINITE); + CloseHandle((HANDLE)thread_id); + return max; +} diff --git a/src/cmd/cgo/internal/test/testx.go b/src/cmd/cgo/internal/test/testx.go index 6a8e97ddf3..0e2a51a522 100644 --- a/src/cmd/cgo/internal/test/testx.go +++ b/src/cmd/cgo/internal/test/testx.go @@ -24,6 +24,7 @@ import ( /* // threads extern void doAdd(int, int); +extern int callGoInCThread(int); // issue 1328 void IntoC(void); @@ -146,6 +147,10 @@ func Add(x int) { *p = 2 } +//export goDummy +func goDummy() { +} + 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") @@ -159,6 +164,15 @@ func testCthread(t *testing.T) { } } +// Benchmark measuring overhead from C to Go in a C thread. +// Create a new C thread and invoke Go function repeatedly in the new C thread. +func benchCGoInCthread(b *testing.B) { + n := C.callGoInCThread(C.int(b.N)) + if int(n) != b.N { + b.Fatal("unmatch loop times") + } +} + // issue 1328 //export BackIntoGo diff --git a/src/cmd/cgo/internal/testcarchive/carchive_test.go b/src/cmd/cgo/internal/testcarchive/carchive_test.go index 51a73ee77f..a92ec46c1a 100644 --- a/src/cmd/cgo/internal/testcarchive/carchive_test.go +++ b/src/cmd/cgo/internal/testcarchive/carchive_test.go @@ -1265,3 +1265,57 @@ func TestPreemption(t *testing.T) { t.Error(err) } } + +// Issue 59294. Test calling Go function from C after using some +// stack space. +func TestDeepStack(t *testing.T) { + t.Parallel() + + if !testWork { + defer func() { + os.Remove("testp9" + exeSuffix) + os.Remove("libgo9.a") + os.Remove("libgo9.h") + }() + } + + cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo9.a", "./libgo9") + out, err := cmd.CombinedOutput() + t.Logf("%v\n%s", cmd.Args, out) + if err != nil { + t.Fatal(err) + } + checkLineComments(t, "libgo9.h") + checkArchive(t, "libgo9.a") + + // build with -O0 so the C compiler won't optimize out the large stack frame + ccArgs := append(cc, "-O0", "-o", "testp9"+exeSuffix, "main9.c", "libgo9.a") + out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput() + t.Logf("%v\n%s", ccArgs, out) + if err != nil { + t.Fatal(err) + } + + argv := cmdToRun("./testp9") + cmd = exec.Command(argv[0], argv[1:]...) + sb := new(strings.Builder) + cmd.Stdout = sb + cmd.Stderr = sb + if err := cmd.Start(); err != nil { + t.Fatal(err) + } + + timer := time.AfterFunc(time.Minute, + func() { + t.Error("test program timed out") + cmd.Process.Kill() + }, + ) + defer timer.Stop() + + err = cmd.Wait() + t.Logf("%v\n%s", cmd.Args, sb) + if err != nil { + t.Error(err) + } +} diff --git a/src/cmd/cgo/internal/testcarchive/testdata/libgo9/a.go b/src/cmd/cgo/internal/testcarchive/testdata/libgo9/a.go new file mode 100644 index 0000000000..acb08d90ec --- /dev/null +++ b/src/cmd/cgo/internal/testcarchive/testdata/libgo9/a.go @@ -0,0 +1,14 @@ +// Copyright 2023 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 "runtime" + +import "C" + +func main() {} + +//export GoF +func GoF() { runtime.GC() } diff --git a/src/cmd/cgo/internal/testcarchive/testdata/main9.c b/src/cmd/cgo/internal/testcarchive/testdata/main9.c new file mode 100644 index 0000000000..95ad4dea49 --- /dev/null +++ b/src/cmd/cgo/internal/testcarchive/testdata/main9.c @@ -0,0 +1,24 @@ +// Copyright 2023 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 "libgo9.h" + +void use(int *x) { (*x)++; } + +void callGoFWithDeepStack() { + int x[10000]; + + use(&x[0]); + use(&x[9999]); + + GoF(); + + use(&x[0]); + use(&x[9999]); +} + +int main() { + GoF(); // call GoF without using much stack + callGoFWithDeepStack(); // call GoF with a deep stack +} diff --git a/src/cmd/cgo/internal/testsanitizers/testdata/tsan14.go b/src/cmd/cgo/internal/testsanitizers/testdata/tsan14.go new file mode 100644 index 0000000000..d594ffb5c0 --- /dev/null +++ b/src/cmd/cgo/internal/testsanitizers/testdata/tsan14.go @@ -0,0 +1,53 @@ +// Copyright 2023 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 + +// This program failed when run under the C/C++ ThreadSanitizer. +// +// cgocallback on a new thread calls into runtime.needm -> _cgo_getstackbound +// to update gp.stack.lo with the stack bounds. If the G itself is passed to +// _cgo_getstackbound, then writes to the same G can be seen on multiple +// threads (when the G is reused after thread exit). This would trigger TSAN. + +/* +#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 ( + "time" +) + +//export go_callback +func go_callback() { +} + +func main() { + for i := 0; i < 2; i++ { + go func() { + for { + C.foo() + } + }() + } + + time.Sleep(1000*time.Millisecond) +} diff --git a/src/cmd/cgo/internal/testsanitizers/tsan_test.go b/src/cmd/cgo/internal/testsanitizers/tsan_test.go index cb63f873f9..6f70ebfef5 100644 --- a/src/cmd/cgo/internal/testsanitizers/tsan_test.go +++ b/src/cmd/cgo/internal/testsanitizers/tsan_test.go @@ -49,6 +49,7 @@ func TestTSAN(t *testing.T) { {src: "tsan11.go", needsRuntime: true}, {src: "tsan12.go", needsRuntime: true}, {src: "tsan13.go", needsRuntime: true}, + {src: "tsan14.go", needsRuntime: true}, } for _, tc := range cases { tc := tc |