import (
"fmt"
"internal/goos"
+ "internal/platform"
"internal/testenv"
"os"
"os/exec"
t.Fatalf("expected %q, but got:\n%s", want, got)
}
}
+
+func TestDestructorCallback(t *testing.T) {
+ t.Parallel()
+ got := runTestProg(t, "testprogcgo", "DestructorCallback")
+ if want := "OK\n"; got != want {
+ t.Errorf("expected %q, but got:\n%s", want, got)
+ }
+}
+
+func TestDestructorCallbackRace(t *testing.T) {
+ // This test requires building with -race,
+ // so it's somewhat slow.
+ if testing.Short() {
+ t.Skip("skipping test in -short mode")
+ }
+
+ if !platform.RaceDetectorSupported(runtime.GOOS, runtime.GOARCH) {
+ t.Skipf("skipping on %s/%s because race detector not supported", runtime.GOOS, runtime.GOARCH)
+ }
+
+ t.Parallel()
+
+ exe, err := buildTestProg(t, "testprogcgo", "-race")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ got, err := testenv.CleanCmdEnv(exec.Command(exe, "DestructorCallback")).CombinedOutput()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if want := "OK\n"; string(got) != want {
+ t.Errorf("expected %q, but got:\n%s", want, got)
+ }
+}
// already held it's assumed that the first caller exits the program
// so other calls can hang forever without an issue.
lock(&raceFiniLock)
+
+ // __tsan_fini will run C atexit functions and C++ destructors,
+ // which can theoretically call back into Go.
+ // Tell the scheduler we entering external code.
+ entersyscall()
+
// We're entering external code that may call ExitProcess on
// Windows.
osPreemptExtEnter(getg().m)
+
racecall(&__tsan_fini, 0, 0, 0, 0)
}
--- /dev/null
+// 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 "_cgo_export.h"
+
+static void callDestructorCallback() {
+ GoDestructorCallback();
+}
+
+static void (*destructorFn)(void);
+
+void registerDestructor() {
+ destructorFn = callDestructorCallback;
+}
+
+__attribute__((destructor))
+static void destructor() {
+ if (destructorFn) {
+ destructorFn();
+ }
+}
--- /dev/null
+// 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
+
+// extern void registerDestructor();
+import "C"
+
+import "fmt"
+
+func init() {
+ register("DestructorCallback", DestructorCallback)
+}
+
+//export GoDestructorCallback
+func GoDestructorCallback() {
+}
+
+func DestructorCallback() {
+ C.registerDestructor()
+ fmt.Println("OK")
+}