]> Cypherpunks.ru repositories - gostls13.git/commitdiff
runtime: make NumGoroutine and Stack agree not to include system goroutines
authorRuss Cox <rsc@golang.org>
Thu, 7 Jan 2016 02:16:01 +0000 (21:16 -0500)
committerRuss Cox <rsc@golang.org>
Wed, 13 Jan 2016 01:46:01 +0000 (01:46 +0000)
[Repeat of CL 18343 with build fixes.]

Before, NumGoroutine counted system goroutines and Stack (usually) didn't show them,
which was inconsistent and confusing.

To resolve which way they should be consistent, it seems like

package main
import "runtime"
func main() { println(runtime.NumGoroutine()) }

should print 1 regardless of internal runtime details. Make it so.

Fixes #11706.

Change-Id: If26749fec06aa0ff84311f7941b88d140552e81d
Reviewed-on: https://go-review.googlesource.com/18432
Reviewed-by: Austin Clements <austin@google.com>
Run-TryBot: Russ Cox <rsc@golang.org>

misc/cgo/test/issue7978.go
src/runtime/mprof.go
src/runtime/proc.go
src/runtime/proc_test.go
src/runtime/runtime2.go
src/runtime/testdata/testprog/misc.go [new file with mode: 0644]

index 094ccc18397114d17c01ab058e2eb2db8fdb03f5..e8f340f8b8d3ce7f35545f659feff5181ab04798 100644 (file)
@@ -110,13 +110,13 @@ func test7978(t *testing.T) {
        go issue7978go()
        // test in c code, before callback
        issue7978wait(0, 1)
-       issue7978check(t, "runtime.cgocall(", "", 1)
+       issue7978check(t, "_Cfunc_issue7978c(", "", 1)
        // test in go code, during callback
        issue7978wait(2, 3)
        issue7978check(t, "test.issue7978cb(", "test.issue7978go", 3)
        // test in c code, after callback
        issue7978wait(4, 5)
-       issue7978check(t, "runtime.cgocall(", "runtime.cgocallback", 1)
+       issue7978check(t, "_Cfunc_issue7978c(", "_cgoexpwrap", 1)
        // test in go code, after return from cgo
        issue7978wait(6, 7)
        issue7978check(t, "test.issue7978go(", "", 3)
index 684ab0b0551eef8ff7f92b599e971deb3622c6b0..eb7231aec22142d05abf28c80ce6367010b836ab 100644 (file)
@@ -576,12 +576,17 @@ func Stack(buf []byte, all bool) int {
                pc := getcallerpc(unsafe.Pointer(&buf))
                systemstack(func() {
                        g0 := getg()
+                       // Force traceback=1 to override GOTRACEBACK setting,
+                       // so that Stack's results are consistent.
+                       // GOTRACEBACK is only about crash dumps.
+                       g0.m.traceback = 1
                        g0.writebuf = buf[0:0:len(buf)]
                        goroutineheader(gp)
                        traceback(pc, sp, 0, gp)
                        if all {
                                tracebackothers(gp)
                        }
+                       g0.m.traceback = 0
                        n = len(g0.writebuf)
                        g0.writebuf = nil
                })
index 545e134cc2104e637297c3b9882ac072fe420af3..be1bb815d5f7bc4ec968f322723e134c376f564c 100644 (file)
@@ -2167,6 +2167,9 @@ func goexit0(gp *g) {
        _g_ := getg()
 
        casgstatus(gp, _Grunning, _Gdead)
+       if isSystemGoroutine(gp) {
+               atomic.Xadd(&sched.ngsys, -1)
+       }
        gp.m = nil
        gp.lockedm = nil
        _g_.m.lockedg = nil
@@ -2698,6 +2701,9 @@ func newproc1(fn *funcval, argp *uint8, narg int32, nret int32, callerpc uintptr
        gostartcallfn(&newg.sched, fn)
        newg.gopc = callerpc
        newg.startpc = fn.fn
+       if isSystemGoroutine(newg) {
+               atomic.Xadd(&sched.ngsys, +1)
+       }
        casgstatus(newg, _Gdead, _Grunnable)
 
        if _p_.goidcache == _p_.goidcacheend {
@@ -2890,7 +2896,7 @@ func badunlockosthread() {
 }
 
 func gcount() int32 {
-       n := int32(allglen) - sched.ngfree
+       n := int32(allglen) - sched.ngfree - int32(atomic.Load(&sched.ngsys))
        for i := 0; ; i++ {
                _p_ := allp[i]
                if _p_ == nil {
index 30798f723dc6ad5d7fa7fb494573f00efc6fd2c7..f3e90bcbd76b4ea7dc33dc38cbd466e92581cbb2 100644 (file)
@@ -9,6 +9,7 @@ import (
        "net"
        "runtime"
        "runtime/debug"
+       "strings"
        "sync"
        "sync/atomic"
        "syscall"
@@ -336,6 +337,23 @@ func TestGCFairness(t *testing.T) {
        }
 }
 
+func TestNumGoroutine(t *testing.T) {
+       output := runTestProg(t, "testprog", "NumGoroutine")
+       want := "1\n"
+       if output != want {
+               t.Fatalf("want %q, got %q", want, output)
+       }
+
+       buf := make([]byte, 1<<20)
+       buf = buf[:runtime.Stack(buf, true)]
+
+       n := runtime.NumGoroutine()
+
+       if nstk := strings.Count(string(buf), "goroutine "); n != nstk {
+               t.Fatalf("NumGoroutine=%d, but found %d goroutines in stack dump", n, nstk)
+       }
+}
+
 func TestPingPongHog(t *testing.T) {
        if testing.Short() {
                t.Skip("skipping in -short mode")
index d9a449b68b45d72d38956406a737170bf482fa3e..54c4686f7991fd185016fe28a5a04d12e8090a4e 100644 (file)
@@ -408,9 +408,11 @@ const (
 )
 
 type schedt struct {
-       lock mutex
+       // accessed atomically. keep at top to ensure alignment on 32-bit systems.
+       goidgen  uint64
+       lastpoll uint64
 
-       goidgen uint64
+       lock mutex
 
        midle        muintptr // idle m's waiting for work
        nmidle       int32    // number of idle m's waiting for work
@@ -418,6 +420,8 @@ type schedt struct {
        mcount       int32    // number of m's that have been created
        maxmcount    int32    // maximum number of m's allowed (or die)
 
+       ngsys uint32 // number of system goroutines; updated atomically
+
        pidle      puintptr // idle p's
        npidle     uint32
        nmspinning uint32 // See "Worker thread parking/unparking" comment in proc.go.
@@ -445,7 +449,6 @@ type schedt struct {
        stopnote   note
        sysmonwait uint32
        sysmonnote note
-       lastpoll   uint64
 
        // safepointFn should be called on each P at the next GC
        // safepoint if p.runSafePointFn is set.
diff --git a/src/runtime/testdata/testprog/misc.go b/src/runtime/testdata/testprog/misc.go
new file mode 100644 (file)
index 0000000..237680f
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2016 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"
+
+func init() {
+       register("NumGoroutine", NumGoroutine)
+}
+
+func NumGoroutine() {
+       println(runtime.NumGoroutine())
+}