aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/runtime/testdata
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/runtime/testdata')
-rw-r--r--libgo/go/runtime/testdata/testprog/badtraceback.go3
-rw-r--r--libgo/go/runtime/testdata/testprog/checkptr.go8
-rw-r--r--libgo/go/runtime/testdata/testprog/gc.go143
-rw-r--r--libgo/go/runtime/testdata/testprog/numcpu_freebsd.go11
-rw-r--r--libgo/go/runtime/testdata/testprog/preempt.go4
-rw-r--r--libgo/go/runtime/testdata/testprog/signal.go1
-rw-r--r--libgo/go/runtime/testdata/testprog/sleep.go7
-rw-r--r--libgo/go/runtime/testdata/testprog/syscalls_none.go1
-rw-r--r--libgo/go/runtime/testdata/testprog/traceback_ancestors.go38
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/callback.go3
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/catchpanic.go1
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/dropm.go1
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/eintr.go1
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/exec.go1
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/gprof.go49
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/gprof_c.c33
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/lockosthread.go1
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/needmdeadlock.go1
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/numgoroutine.go1
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/panic.c9
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/panic.go23
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/pprof.go11
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/raceprof.go2
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/racesig.go1
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/segv.go1
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/sigstack.go1
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/sigthrow.go20
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/threadpanic.go1
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/threadpprof.go25
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/threadprof.go17
-rw-r--r--libgo/go/runtime/testdata/testprognet/signal.go1
-rw-r--r--libgo/go/runtime/testdata/testprognet/signalexec.go1
-rw-r--r--libgo/go/runtime/testdata/testwinlib/main.c5
-rw-r--r--libgo/go/runtime/testdata/testwinlib/main.go1
34 files changed, 294 insertions, 133 deletions
diff --git a/libgo/go/runtime/testdata/testprog/badtraceback.go b/libgo/go/runtime/testdata/testprog/badtraceback.go
index d558adc..09aa2b8 100644
--- a/libgo/go/runtime/testdata/testprog/badtraceback.go
+++ b/libgo/go/runtime/testdata/testprog/badtraceback.go
@@ -17,6 +17,9 @@ func init() {
func BadTraceback() {
// Disable GC to prevent traceback at unexpected time.
debug.SetGCPercent(-1)
+ // Out of an abundance of caution, also make sure that there are
+ // no GCs actively in progress.
+ runtime.GC()
// Run badLR1 on its own stack to minimize the stack size and
// exercise the stack bounds logic in the hex dump.
diff --git a/libgo/go/runtime/testdata/testprog/checkptr.go b/libgo/go/runtime/testdata/testprog/checkptr.go
index 9c55613..b27e5f7 100644
--- a/libgo/go/runtime/testdata/testprog/checkptr.go
+++ b/libgo/go/runtime/testdata/testprog/checkptr.go
@@ -20,6 +20,7 @@ func init() {
register("CheckPtrSmall", CheckPtrSmall)
register("CheckPtrSliceOK", CheckPtrSliceOK)
register("CheckPtrSliceFail", CheckPtrSliceFail)
+ register("CheckPtrAlignmentNested", CheckPtrAlignmentNested)
}
func CheckPtrAlignmentNoPtr() {
@@ -96,3 +97,10 @@ func CheckPtrSliceFail() {
sink2 = p
sink2 = unsafe.Slice(p, 100)
}
+
+func CheckPtrAlignmentNested() {
+ s := make([]int8, 100)
+ p := unsafe.Pointer(&s[0])
+ n := 9
+ _ = ((*[10]int8)(unsafe.Pointer((*[10]int64)(unsafe.Pointer(&p)))))[:n:n]
+}
diff --git a/libgo/go/runtime/testdata/testprog/gc.go b/libgo/go/runtime/testdata/testprog/gc.go
index 74732cd..215228e 100644
--- a/libgo/go/runtime/testdata/testprog/gc.go
+++ b/libgo/go/runtime/testdata/testprog/gc.go
@@ -90,7 +90,7 @@ func GCFairness2() {
runtime.GOMAXPROCS(1)
debug.SetGCPercent(1)
var count [3]int64
- var sink [3]interface{}
+ var sink [3]any
for i := range count {
go func(i int) {
for {
@@ -132,81 +132,88 @@ func GCFairness2() {
func GCPhys() {
// This test ensures that heap-growth scavenging is working as intended.
//
- // It sets up a specific scenario: it allocates two pairs of objects whose
- // sizes sum to size. One object in each pair is "small" (though must be
- // large enough to be considered a large object by the runtime) and one is
- // large. The small objects are kept while the large objects are freed,
- // creating two large unscavenged holes in the heap. The heap goal should
- // also be small as a result (so size must be at least as large as the
- // minimum heap size). We then allocate one large object, bigger than both
- // pairs of objects combined. This allocation, because it will tip
- // HeapSys-HeapReleased well above the heap goal, should trigger heap-growth
- // scavenging and scavenge most, if not all, of the large holes we created
- // earlier.
+ // It attempts to construct a sizeable "swiss cheese" heap, with many
+ // allocChunk-sized holes. Then, it triggers a heap growth by trying to
+ // allocate as much memory as would fit in those holes.
+ //
+ // The heap growth should cause a large number of those holes to be
+ // returned to the OS.
+
const (
- // Size must be also large enough to be considered a large
- // object (not in any size-segregated span).
- size = 4 << 20
- split = 64 << 10
- objects = 2
+ // The total amount of memory we're willing to allocate.
+ allocTotal = 32 << 20
// The page cache could hide 64 8-KiB pages from the scavenger today.
maxPageCache = (8 << 10) * 64
-
- // Reduce GOMAXPROCS down to 4 if it's greater. We need to bound the amount
- // of memory held in the page cache because the scavenger can't reach it.
- // The page cache will hold at most maxPageCache of memory per-P, so this
- // bounds the amount of memory hidden from the scavenger to 4*maxPageCache
- // at most.
- maxProcs = 4
)
- // Set GOGC so that this test operates under consistent assumptions.
- debug.SetGCPercent(100)
- procs := runtime.GOMAXPROCS(-1)
- if procs > maxProcs {
- defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs))
- procs = runtime.GOMAXPROCS(-1)
+
+ // How big the allocations are needs to depend on the page size.
+ // If the page size is too big and the allocations are too small,
+ // they might not be aligned to the physical page size, so the scavenger
+ // will gloss over them.
+ pageSize := os.Getpagesize()
+ var allocChunk int
+ if pageSize <= 8<<10 {
+ allocChunk = 64 << 10
+ } else {
+ allocChunk = 512 << 10
}
- // Save objects which we want to survive, and condemn objects which we don't.
- // Note that we condemn objects in this way and release them all at once in
- // order to avoid having the GC start freeing up these objects while the loop
- // is still running and filling in the holes we intend to make.
- saved := make([][]byte, 0, objects+1)
- condemned := make([][]byte, 0, objects)
- for i := 0; i < 2*objects; i++ {
+ allocs := allocTotal / allocChunk
+
+ // Set GC percent just so this test is a little more consistent in the
+ // face of varying environments.
+ debug.SetGCPercent(100)
+
+ // Set GOMAXPROCS to 1 to minimize the amount of memory held in the page cache,
+ // and to reduce the chance that the background scavenger gets scheduled.
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
+
+ // Allocate allocTotal bytes of memory in allocChunk byte chunks.
+ // Alternate between whether the chunk will be held live or will be
+ // condemned to GC to create holes in the heap.
+ saved := make([][]byte, allocs/2+1)
+ condemned := make([][]byte, allocs/2)
+ for i := 0; i < allocs; i++ {
+ b := make([]byte, allocChunk)
if i%2 == 0 {
- saved = append(saved, make([]byte, split))
+ saved = append(saved, b)
} else {
- condemned = append(condemned, make([]byte, size-split))
+ condemned = append(condemned, b)
}
}
- condemned = nil
- // Clean up the heap. This will free up every other object created above
- // (i.e. everything in condemned) creating holes in the heap.
- // Also, if the condemned objects are still being swept, its possible that
- // the scavenging that happens as a result of the next allocation won't see
- // the holes at all. We call runtime.GC() twice here so that when we allocate
- // our large object there's no race with sweeping.
- runtime.GC()
+
+ // Run a GC cycle just so we're at a consistent state.
runtime.GC()
- // Perform one big allocation which should also scavenge any holes.
- //
- // The heap goal will rise after this object is allocated, so it's very
- // important that we try to do all the scavenging in a single allocation
- // that exceeds the heap goal. Otherwise the rising heap goal could foil our
- // test.
- saved = append(saved, make([]byte, objects*size))
- // Clean up the heap again just to put it in a known state.
+
+ // Drop the only reference to all the condemned memory.
+ condemned = nil
+
+ // Clear the condemned memory.
runtime.GC()
+
+ // At this point, the background scavenger is likely running
+ // and could pick up the work, so the next line of code doesn't
+ // end up doing anything. That's fine. What's important is that
+ // this test fails somewhat regularly if the runtime doesn't
+ // scavenge on heap growth, and doesn't fail at all otherwise.
+
+ // Make a large allocation that in theory could fit, but won't
+ // because we turned the heap into swiss cheese.
+ saved = append(saved, make([]byte, allocTotal/2))
+
// heapBacked is an estimate of the amount of physical memory used by
// this test. HeapSys is an estimate of the size of the mapped virtual
// address space (which may or may not be backed by physical pages)
// whereas HeapReleased is an estimate of the amount of bytes returned
// to the OS. Their difference then roughly corresponds to the amount
// of virtual address space that is backed by physical pages.
+ //
+ // heapBacked also subtracts out maxPageCache bytes of memory because
+ // this is memory that may be hidden from the scavenger per-P. Since
+ // GOMAXPROCS=1 here, subtracting it out once is fine.
var stats runtime.MemStats
runtime.ReadMemStats(&stats)
- heapBacked := stats.HeapSys - stats.HeapReleased
+ heapBacked := stats.HeapSys - stats.HeapReleased - maxPageCache
// If heapBacked does not exceed the heap goal by more than retainExtraPercent
// then the scavenger is working as expected; the newly-created holes have been
// scavenged immediately as part of the allocations which cannot fit in the holes.
@@ -216,19 +223,14 @@ func GCPhys() {
// to other allocations that happen during this test we may still see some physical
// memory over-use.
overuse := (float64(heapBacked) - float64(stats.HeapAlloc)) / float64(stats.HeapAlloc)
- // Compute the threshold.
+ // Check against our overuse threshold, which is what the scavenger always reserves
+ // to encourage allocation of memory that doesn't need to be faulted in.
//
- // In theory, this threshold should just be zero, but that's not possible in practice.
- // Firstly, the runtime's page cache can hide up to maxPageCache of free memory from the
- // scavenger per P. To account for this, we increase the threshold by the ratio between the
- // total amount the runtime could hide from the scavenger to the amount of memory we expect
- // to be able to scavenge here, which is (size-split)*objects. This computation is the crux
- // GOMAXPROCS above; if GOMAXPROCS is too high the threshold just becomes 100%+ since the
- // amount of memory being allocated is fixed. Then we add 5% to account for noise, such as
- // other allocations this test may have performed that we don't explicitly account for The
- // baseline threshold here is around 11% for GOMAXPROCS=1, capping out at around 30% for
- // GOMAXPROCS=4.
- threshold := 0.05 + float64(procs)*maxPageCache/float64((size-split)*objects)
+ // Add additional slack in case the page size is large and the scavenger
+ // can't reach that memory because it doesn't constitute a complete aligned
+ // physical page. Assume the worst case: a full physical page out of each
+ // allocation.
+ threshold := 0.1 + float64(pageSize)/float64(allocChunk)
if overuse <= threshold {
fmt.Println("OK")
return
@@ -243,6 +245,7 @@ func GCPhys() {
"(alloc: %d, goal: %d, sys: %d, rel: %d, objs: %d)\n", threshold*100, overuse*100,
stats.HeapAlloc, stats.NextGC, stats.HeapSys, stats.HeapReleased, len(saved))
runtime.KeepAlive(saved)
+ runtime.KeepAlive(condemned)
}
// Test that defer closure is correctly scanned when the stack is scanned.
@@ -263,9 +266,9 @@ func DeferLiveness() {
}
//go:noinline
-func escape(x interface{}) { sink2 = x; sink2 = nil }
+func escape(x any) { sink2 = x; sink2 = nil }
-var sink2 interface{}
+var sink2 any
// Test zombie object detection and reporting.
func GCZombie() {
diff --git a/libgo/go/runtime/testdata/testprog/numcpu_freebsd.go b/libgo/go/runtime/testdata/testprog/numcpu_freebsd.go
index aff36ec..7209f67 100644
--- a/libgo/go/runtime/testdata/testprog/numcpu_freebsd.go
+++ b/libgo/go/runtime/testdata/testprog/numcpu_freebsd.go
@@ -85,19 +85,18 @@ func getList() ([]string, error) {
if err != nil {
return nil, fmt.Errorf("fail to execute '%s': %s", cmdline, err)
}
- pos := bytes.IndexRune(output, '\n')
- if pos == -1 {
+ output, _, ok := bytes.Cut(output, []byte("\n"))
+ if !ok {
return nil, fmt.Errorf("invalid output from '%s', '\\n' not found: %s", cmdline, output)
}
- output = output[0:pos]
- pos = bytes.IndexRune(output, ':')
- if pos == -1 {
+ _, cpus, ok := bytes.Cut(output, []byte(":"))
+ if !ok {
return nil, fmt.Errorf("invalid output from '%s', ':' not found: %s", cmdline, output)
}
var list []string
- for _, val := range bytes.Split(output[pos+1:], []byte(",")) {
+ for _, val := range bytes.Split(cpus, []byte(",")) {
index := string(bytes.TrimSpace(val))
if len(index) == 0 {
continue
diff --git a/libgo/go/runtime/testdata/testprog/preempt.go b/libgo/go/runtime/testdata/testprog/preempt.go
index 1c74d0e..fb6755a 100644
--- a/libgo/go/runtime/testdata/testprog/preempt.go
+++ b/libgo/go/runtime/testdata/testprog/preempt.go
@@ -20,6 +20,10 @@ func AsyncPreempt() {
runtime.GOMAXPROCS(1)
// Disable GC so we have complete control of what we're testing.
debug.SetGCPercent(-1)
+ // Out of an abundance of caution, also make sure that there are
+ // no GCs actively in progress. The sweep phase of a GC cycle
+ // for instance tries to preempt Ps at the very beginning.
+ runtime.GC()
// Start a goroutine with no sync safe-points.
var ready, ready2 uint32
diff --git a/libgo/go/runtime/testdata/testprog/signal.go b/libgo/go/runtime/testdata/testprog/signal.go
index 417e105..cc5ac8a 100644
--- a/libgo/go/runtime/testdata/testprog/signal.go
+++ b/libgo/go/runtime/testdata/testprog/signal.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !windows && !plan9
// +build !windows,!plan9
package main
diff --git a/libgo/go/runtime/testdata/testprog/sleep.go b/libgo/go/runtime/testdata/testprog/sleep.go
index 86e2f6c..b230e60 100644
--- a/libgo/go/runtime/testdata/testprog/sleep.go
+++ b/libgo/go/runtime/testdata/testprog/sleep.go
@@ -4,7 +4,10 @@
package main
-import "time"
+import (
+ "os"
+ "time"
+)
// for golang.org/issue/27250
@@ -13,5 +16,7 @@ func init() {
}
func After1() {
+ os.Stdout.WriteString("ready\n")
+ os.Stdout.Close()
<-time.After(1 * time.Second)
}
diff --git a/libgo/go/runtime/testdata/testprog/syscalls_none.go b/libgo/go/runtime/testdata/testprog/syscalls_none.go
index 7f8ded3..068bb59 100644
--- a/libgo/go/runtime/testdata/testprog/syscalls_none.go
+++ b/libgo/go/runtime/testdata/testprog/syscalls_none.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !linux
// +build !linux
package main
diff --git a/libgo/go/runtime/testdata/testprog/traceback_ancestors.go b/libgo/go/runtime/testdata/testprog/traceback_ancestors.go
index 0ee402c..1d0d00b 100644
--- a/libgo/go/runtime/testdata/testprog/traceback_ancestors.go
+++ b/libgo/go/runtime/testdata/testprog/traceback_ancestors.go
@@ -33,30 +33,27 @@ func printStack() {
for {
n := runtime.Stack(buf, true)
if n < len(buf) {
- tb := string(buf[:n])
+ all := string(buf[:n])
+ var saved string
// Delete any ignored goroutines, if present.
- pos := 0
- for pos < len(tb) {
- next := pos + strings.Index(tb[pos:], "\n\n")
- if next < pos {
- next = len(tb)
- } else {
- next += len("\n\n")
- }
+ for all != "" {
+ var g string
+ g, all, _ = strings.Cut(all, "\n\n")
- if strings.HasPrefix(tb[pos:], "goroutine ") {
- id := tb[pos+len("goroutine "):]
- id = id[:strings.IndexByte(id, ' ')]
+ if strings.HasPrefix(g, "goroutine ") {
+ id, _, _ := strings.Cut(strings.TrimPrefix(g, "goroutine "), " ")
if ignoreGoroutines[id] {
- tb = tb[:pos] + tb[next:]
- next = pos
+ continue
}
}
- pos = next
+ if saved != "" {
+ saved += "\n\n"
+ }
+ saved += g
}
- fmt.Print(tb)
+ fmt.Print(saved)
return
}
buf = make([]byte, 2*len(buf))
@@ -89,11 +86,10 @@ func recurseThenCallGo(w chan struct{}, frames int, goroutines int, main bool) {
func goroutineID() string {
buf := make([]byte, 128)
runtime.Stack(buf, false)
- const prefix = "goroutine "
- if !bytes.HasPrefix(buf, []byte(prefix)) {
+ prefix := []byte("goroutine ")
+ if !bytes.HasPrefix(buf, prefix) {
panic(fmt.Sprintf("expected %q at beginning of traceback:\n%s", prefix, buf))
}
- buf = buf[len(prefix):]
- n := bytes.IndexByte(buf, ' ')
- return string(buf[:n])
+ id, _, _ := bytes.Cut(bytes.TrimPrefix(buf, prefix), []byte(" "))
+ return string(id)
}
diff --git a/libgo/go/runtime/testdata/testprogcgo/callback.go b/libgo/go/runtime/testdata/testprogcgo/callback.go
index 2f7568c..45baeb1 100644
--- a/libgo/go/runtime/testdata/testprogcgo/callback.go
+++ b/libgo/go/runtime/testdata/testprogcgo/callback.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !plan9 && !windows
// +build !plan9,!windows
package main
@@ -70,7 +71,7 @@ func grow1(x, sum *int) int {
func CgoCallbackGC() {
P := 100
- if os.Getenv("RUNTIME_TESTING_SHORT") != "" {
+ if os.Getenv("RUNTIME_TEST_SHORT") != "" {
P = 10
}
done := make(chan bool)
diff --git a/libgo/go/runtime/testdata/testprogcgo/catchpanic.go b/libgo/go/runtime/testdata/testprogcgo/catchpanic.go
index 55a606d..c722d40 100644
--- a/libgo/go/runtime/testdata/testprogcgo/catchpanic.go
+++ b/libgo/go/runtime/testdata/testprogcgo/catchpanic.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !plan9 && !windows
// +build !plan9,!windows
package main
diff --git a/libgo/go/runtime/testdata/testprogcgo/dropm.go b/libgo/go/runtime/testdata/testprogcgo/dropm.go
index 9e782f5..700b7fa 100644
--- a/libgo/go/runtime/testdata/testprogcgo/dropm.go
+++ b/libgo/go/runtime/testdata/testprogcgo/dropm.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !plan9 && !windows
// +build !plan9,!windows
// Test that a sequence of callbacks from C to Go get the same m.
diff --git a/libgo/go/runtime/testdata/testprogcgo/eintr.go b/libgo/go/runtime/testdata/testprogcgo/eintr.go
index 1722a75..b35b280 100644
--- a/libgo/go/runtime/testdata/testprogcgo/eintr.go
+++ b/libgo/go/runtime/testdata/testprogcgo/eintr.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !plan9 && !windows
// +build !plan9,!windows
package main
diff --git a/libgo/go/runtime/testdata/testprogcgo/exec.go b/libgo/go/runtime/testdata/testprogcgo/exec.go
index 15723c7..c268bcd 100644
--- a/libgo/go/runtime/testdata/testprogcgo/exec.go
+++ b/libgo/go/runtime/testdata/testprogcgo/exec.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !plan9 && !windows
// +build !plan9,!windows
package main
diff --git a/libgo/go/runtime/testdata/testprogcgo/gprof.go b/libgo/go/runtime/testdata/testprogcgo/gprof.go
new file mode 100644
index 0000000..85986cc
--- /dev/null
+++ b/libgo/go/runtime/testdata/testprogcgo/gprof.go
@@ -0,0 +1,49 @@
+// Copyright 2021 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 !gccgo
+// +build !gccgo
+
+package main
+
+// Test taking a goroutine profile with C traceback.
+
+/*
+// Defined in gprof_c.c.
+void CallGoSleep(void);
+void gprofCgoTraceback(void* parg);
+void gprofCgoContext(void* parg);
+*/
+import "C"
+
+import (
+ "fmt"
+ "io"
+ "runtime"
+ "runtime/pprof"
+ "time"
+ "unsafe"
+)
+
+func init() {
+ register("GoroutineProfile", GoroutineProfile)
+}
+
+func GoroutineProfile() {
+ runtime.SetCgoTraceback(0, unsafe.Pointer(C.gprofCgoTraceback), unsafe.Pointer(C.gprofCgoContext), nil)
+
+ go C.CallGoSleep()
+ go C.CallGoSleep()
+ go C.CallGoSleep()
+ time.Sleep(1 * time.Second)
+
+ prof := pprof.Lookup("goroutine")
+ prof.WriteTo(io.Discard, 1)
+ fmt.Println("OK")
+}
+
+//export GoSleep
+func GoSleep() {
+ time.Sleep(time.Hour)
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/gprof_c.c b/libgo/go/runtime/testdata/testprogcgo/gprof_c.c
new file mode 100644
index 0000000..11b0649
--- /dev/null
+++ b/libgo/go/runtime/testdata/testprogcgo/gprof_c.c
@@ -0,0 +1,33 @@
+// Copyright 2021 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 !gccgo
+// +build !gccgo
+
+// The C definitions for gprof.go. That file uses //export so
+// it can't put function definitions in the "C" import comment.
+
+#include <stdint.h>
+#include <stdlib.h>
+
+// Functions exported from Go.
+extern void GoSleep();
+
+struct cgoContextArg {
+ uintptr_t context;
+};
+
+void gprofCgoContext(void *arg) {
+ ((struct cgoContextArg*)arg)->context = 1;
+}
+
+void gprofCgoTraceback(void *arg) {
+ // spend some time here so the P is more likely to be retaken.
+ volatile int i;
+ for (i = 0; i < 123456789; i++);
+}
+
+void CallGoSleep() {
+ GoSleep();
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/lockosthread.go b/libgo/go/runtime/testdata/testprogcgo/lockosthread.go
index 36423d9..8fcea35 100644
--- a/libgo/go/runtime/testdata/testprogcgo/lockosthread.go
+++ b/libgo/go/runtime/testdata/testprogcgo/lockosthread.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !plan9 && !windows
// +build !plan9,!windows
package main
diff --git a/libgo/go/runtime/testdata/testprogcgo/needmdeadlock.go b/libgo/go/runtime/testdata/testprogcgo/needmdeadlock.go
index 5a9c359..b95ec77 100644
--- a/libgo/go/runtime/testdata/testprogcgo/needmdeadlock.go
+++ b/libgo/go/runtime/testdata/testprogcgo/needmdeadlock.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !plan9 && !windows
// +build !plan9,!windows
package main
diff --git a/libgo/go/runtime/testdata/testprogcgo/numgoroutine.go b/libgo/go/runtime/testdata/testprogcgo/numgoroutine.go
index b7134a4..e09706d 100644
--- a/libgo/go/runtime/testdata/testprogcgo/numgoroutine.go
+++ b/libgo/go/runtime/testdata/testprogcgo/numgoroutine.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !plan9 && !windows
// +build !plan9,!windows
package main
diff --git a/libgo/go/runtime/testdata/testprogcgo/panic.c b/libgo/go/runtime/testdata/testprogcgo/panic.c
new file mode 100644
index 0000000..deb5ed5
--- /dev/null
+++ b/libgo/go/runtime/testdata/testprogcgo/panic.c
@@ -0,0 +1,9 @@
+// Copyright 2021 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.
+
+extern void panic_callback();
+
+void call_callback(void) {
+ panic_callback();
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/panic.go b/libgo/go/runtime/testdata/testprogcgo/panic.go
new file mode 100644
index 0000000..57ac895
--- /dev/null
+++ b/libgo/go/runtime/testdata/testprogcgo/panic.go
@@ -0,0 +1,23 @@
+package main
+
+// This program will crash.
+// We want to test unwinding from a cgo callback.
+
+/*
+void call_callback(void);
+*/
+import "C"
+
+func init() {
+ register("PanicCallback", PanicCallback)
+}
+
+//export panic_callback
+func panic_callback() {
+ var i *int
+ *i = 42
+}
+
+func PanicCallback() {
+ C.call_callback()
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/pprof.go b/libgo/go/runtime/testdata/testprogcgo/pprof.go
index 668d4e0..bbf93c4 100644
--- a/libgo/go/runtime/testdata/testprogcgo/pprof.go
+++ b/libgo/go/runtime/testdata/testprogcgo/pprof.go
@@ -32,8 +32,6 @@ void cpuHog() {
void cpuHog2() {
}
-static int cpuHogCount;
-
struct cgoTracebackArg {
uintptr_t context;
uintptr_t sigContext;
@@ -50,13 +48,6 @@ void pprofCgoTraceback(void* parg) {
arg->buf[0] = (uintptr_t)(cpuHog) + 0x10;
arg->buf[1] = (uintptr_t)(cpuHog2) + 0x4;
arg->buf[2] = 0;
- ++cpuHogCount;
-}
-
-// getCpuHogCount fetches the number of times we've seen cpuHog in the
-// traceback.
-int getCpuHogCount() {
- return cpuHogCount;
}
*/
import "C"
@@ -89,7 +80,7 @@ func CgoPprof() {
}
t0 := time.Now()
- for C.getCpuHogCount() < 2 && time.Since(t0) < time.Second {
+ for time.Since(t0) < time.Second {
C.cpuHog()
}
diff --git a/libgo/go/runtime/testdata/testprogcgo/raceprof.go b/libgo/go/runtime/testdata/testprogcgo/raceprof.go
index c17bb39..3329139 100644
--- a/libgo/go/runtime/testdata/testprogcgo/raceprof.go
+++ b/libgo/go/runtime/testdata/testprogcgo/raceprof.go
@@ -3,8 +3,6 @@
// license that can be found in the LICENSE file.
//go:build ((linux && amd64) || (freebsd && amd64)) && !gccgo
-// +build linux,amd64 freebsd,amd64
-// +build !gccgo
package main
diff --git a/libgo/go/runtime/testdata/testprogcgo/racesig.go b/libgo/go/runtime/testdata/testprogcgo/racesig.go
index a079b3f..9352679 100644
--- a/libgo/go/runtime/testdata/testprogcgo/racesig.go
+++ b/libgo/go/runtime/testdata/testprogcgo/racesig.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build (linux && amd64) || (freebsd && amd64)
// +build linux,amd64 freebsd,amd64
package main
diff --git a/libgo/go/runtime/testdata/testprogcgo/segv.go b/libgo/go/runtime/testdata/testprogcgo/segv.go
index 3237a8c..0632475 100644
--- a/libgo/go/runtime/testdata/testprogcgo/segv.go
+++ b/libgo/go/runtime/testdata/testprogcgo/segv.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !plan9 && !windows
// +build !plan9,!windows
package main
diff --git a/libgo/go/runtime/testdata/testprogcgo/sigstack.go b/libgo/go/runtime/testdata/testprogcgo/sigstack.go
index 21b668d..12ca661 100644
--- a/libgo/go/runtime/testdata/testprogcgo/sigstack.go
+++ b/libgo/go/runtime/testdata/testprogcgo/sigstack.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !plan9 && !windows
// +build !plan9,!windows
// Test handling of Go-allocated signal stacks when calling from
diff --git a/libgo/go/runtime/testdata/testprogcgo/sigthrow.go b/libgo/go/runtime/testdata/testprogcgo/sigthrow.go
new file mode 100644
index 0000000..665e3b0
--- /dev/null
+++ b/libgo/go/runtime/testdata/testprogcgo/sigthrow.go
@@ -0,0 +1,20 @@
+// Copyright 2021 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 will abort.
+
+/*
+#include <stdlib.h>
+*/
+import "C"
+
+func init() {
+ register("Abort", Abort)
+}
+
+func Abort() {
+ C.abort()
+}
diff --git a/libgo/go/runtime/testdata/testprogcgo/threadpanic.go b/libgo/go/runtime/testdata/testprogcgo/threadpanic.go
index f9b48a9..2d24fe6 100644
--- a/libgo/go/runtime/testdata/testprogcgo/threadpanic.go
+++ b/libgo/go/runtime/testdata/testprogcgo/threadpanic.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !plan9
// +build !plan9
package main
diff --git a/libgo/go/runtime/testdata/testprogcgo/threadpprof.go b/libgo/go/runtime/testdata/testprogcgo/threadpprof.go
index ed3faed..ec83d2d 100644
--- a/libgo/go/runtime/testdata/testprogcgo/threadpprof.go
+++ b/libgo/go/runtime/testdata/testprogcgo/threadpprof.go
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build !plan9 && !windows && !gccgo
-// +build !plan9,!windows,!gccgo
package main
@@ -34,8 +33,6 @@ void cpuHogThread() {
void cpuHogThread2() {
}
-static int cpuHogThreadCount;
-
struct cgoTracebackArg {
uintptr_t context;
uintptr_t sigContext;
@@ -50,13 +47,6 @@ void pprofCgoThreadTraceback(void* parg) {
arg->buf[0] = (uintptr_t)(cpuHogThread) + 0x10;
arg->buf[1] = (uintptr_t)(cpuHogThread2) + 0x4;
arg->buf[2] = 0;
- __sync_add_and_fetch(&cpuHogThreadCount, 1);
-}
-
-// getCPUHogThreadCount fetches the number of times we've seen cpuHogThread
-// in the traceback.
-int getCPUHogThreadCount() {
- return __sync_add_and_fetch(&cpuHogThreadCount, 0);
}
static void* cpuHogDriver(void* arg __attribute__ ((unused))) {
@@ -74,6 +64,7 @@ void runCPUHogThread(void) {
import "C"
import (
+ "context"
"fmt"
"os"
"runtime"
@@ -108,12 +99,16 @@ func pprofThread() {
os.Exit(2)
}
- C.runCPUHogThread()
+ // This goroutine may receive a profiling signal while creating the C-owned
+ // thread. If it does, the SetCgoTraceback handler will make the leaf end of
+ // the stack look almost (but not exactly) like the stacks the test case is
+ // trying to find. Attach a profiler label so the test can filter out those
+ // confusing samples.
+ pprof.Do(context.Background(), pprof.Labels("ignore", "ignore"), func(ctx context.Context) {
+ C.runCPUHogThread()
+ })
- t0 := time.Now()
- for C.getCPUHogThreadCount() < 2 && time.Since(t0) < time.Second {
- time.Sleep(100 * time.Millisecond)
- }
+ time.Sleep(1 * time.Second)
pprof.StopCPUProfile()
diff --git a/libgo/go/runtime/testdata/testprogcgo/threadprof.go b/libgo/go/runtime/testdata/testprogcgo/threadprof.go
index 2d4c103..d62d4b4 100644
--- a/libgo/go/runtime/testdata/testprogcgo/threadprof.go
+++ b/libgo/go/runtime/testdata/testprogcgo/threadprof.go
@@ -2,21 +2,22 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// We only build this file with the tag "threadprof", since it starts
-// a thread running a busy loop at constructor time.
-
+//go:build !plan9 && !windows
// +build !plan9,!windows
-// +build threadprof
package main
/*
#include <stdint.h>
+#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
volatile int32_t spinlock;
+// Note that this thread is only started if GO_START_SIGPROF_THREAD
+// is set in the environment, which is only done when running the
+// CgoExternalThreadSIGPROF test.
static void *thread1(void *p) {
(void)p;
while (spinlock == 0)
@@ -26,9 +27,13 @@ static void *thread1(void *p) {
return NULL;
}
+// This constructor function is run when the program starts.
+// It is used for the CgoExternalThreadSIGPROF test.
__attribute__((constructor)) void issue9456() {
- pthread_t tid;
- pthread_create(&tid, 0, thread1, NULL);
+ if (getenv("GO_START_SIGPROF_THREAD") != NULL) {
+ pthread_t tid;
+ pthread_create(&tid, 0, thread1, NULL);
+ }
}
void **nullptr;
diff --git a/libgo/go/runtime/testdata/testprognet/signal.go b/libgo/go/runtime/testdata/testprognet/signal.go
index 4d2de79..dfa2e10 100644
--- a/libgo/go/runtime/testdata/testprognet/signal.go
+++ b/libgo/go/runtime/testdata/testprognet/signal.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !windows && !plan9
// +build !windows,!plan9
// This is in testprognet instead of testprog because testprog
diff --git a/libgo/go/runtime/testdata/testprognet/signalexec.go b/libgo/go/runtime/testdata/testprognet/signalexec.go
index 4a988ef..62ebce7 100644
--- a/libgo/go/runtime/testdata/testprognet/signalexec.go
+++ b/libgo/go/runtime/testdata/testprognet/signalexec.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd
// +build darwin dragonfly freebsd linux netbsd openbsd
// This is in testprognet instead of testprog because testprog
diff --git a/libgo/go/runtime/testdata/testwinlib/main.c b/libgo/go/runtime/testdata/testwinlib/main.c
index e84a32f..c3fe3cb 100644
--- a/libgo/go/runtime/testdata/testwinlib/main.c
+++ b/libgo/go/runtime/testdata/testwinlib/main.c
@@ -41,17 +41,20 @@ int main()
if (NULL == exceptionHandlerHandle)
{
printf("cannot add vectored exception handler\n");
+ fflush(stdout);
return 2;
}
void *continueHandlerHandle = AddVectoredContinueHandler(0, customContinueHandlder);
if (NULL == continueHandlerHandle)
{
printf("cannot add vectored continue handler\n");
+ fflush(stdout);
return 2;
}
CallMeBack(throwFromC);
RemoveVectoredContinueHandler(continueHandlerHandle);
RemoveVectoredExceptionHandler(exceptionHandlerHandle);
printf("exceptionCount: %d\ncontinueCount: %d\n", exceptionCount, continueCount);
+ fflush(stdout);
return 0;
-} \ No newline at end of file
+}
diff --git a/libgo/go/runtime/testdata/testwinlib/main.go b/libgo/go/runtime/testdata/testwinlib/main.go
index 400eaa1..025ef91 100644
--- a/libgo/go/runtime/testdata/testwinlib/main.go
+++ b/libgo/go/runtime/testdata/testwinlib/main.go
@@ -1,3 +1,4 @@
+//go:build windows && cgo
// +build windows,cgo
package main