summaryrefslogtreecommitdiffstats
path: root/src/runtime/testdata/testprogcgo/pprof_callback.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/testdata/testprogcgo/pprof_callback.go')
-rw-r--r--src/runtime/testdata/testprogcgo/pprof_callback.go89
1 files changed, 89 insertions, 0 deletions
diff --git a/src/runtime/testdata/testprogcgo/pprof_callback.go b/src/runtime/testdata/testprogcgo/pprof_callback.go
new file mode 100644
index 0000000..fd87eb8
--- /dev/null
+++ b/src/runtime/testdata/testprogcgo/pprof_callback.go
@@ -0,0 +1,89 @@
+// Copyright 2022 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.
+
+//go:build !plan9 && !windows
+
+package main
+
+// Make many C-to-Go callback while collecting a CPU profile.
+//
+// This is a regression test for issue 50936.
+
+/*
+#include <unistd.h>
+
+void goCallbackPprof();
+
+static void callGo() {
+ // Spent >20us in C so this thread is eligible for sysmon to retake its
+ // P.
+ usleep(50);
+ goCallbackPprof();
+}
+*/
+import "C"
+
+import (
+ "fmt"
+ "os"
+ "runtime"
+ "runtime/pprof"
+ "time"
+)
+
+func init() {
+ register("CgoPprofCallback", CgoPprofCallback)
+}
+
+//export goCallbackPprof
+func goCallbackPprof() {
+ // No-op. We want to stress the cgocall and cgocallback internals,
+ // landing as many pprof signals there as possible.
+}
+
+func CgoPprofCallback() {
+ // Issue 50936 was a crash in the SIGPROF handler when the signal
+ // arrived during the exitsyscall following a cgocall(back) in dropg or
+ // execute, when updating mp.curg.
+ //
+ // These are reachable only when exitsyscall finds no P available. Thus
+ // we make C calls from significantly more Gs than there are available
+ // Ps. Lots of runnable work combined with >20us spent in callGo makes
+ // it possible for sysmon to retake Ps, forcing C calls to go down the
+ // desired exitsyscall path.
+ //
+ // High GOMAXPROCS is used to increase opportunities for failure on
+ // high CPU machines.
+ const (
+ P = 16
+ G = 64
+ )
+ runtime.GOMAXPROCS(P)
+
+ f, err := os.CreateTemp("", "prof")
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(2)
+ }
+ defer f.Close()
+
+ if err := pprof.StartCPUProfile(f); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(2)
+ }
+
+ for i := 0; i < G; i++ {
+ go func() {
+ for {
+ C.callGo()
+ }
+ }()
+ }
+
+ time.Sleep(time.Second)
+
+ pprof.StopCPUProfile()
+
+ fmt.Println("OK")
+}