Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
runtime: get map of args of unstarted goroutines like we do for defers
Normally, reflect.makeFuncStub records the context value at a known point in the stack frame, so that the runtime can get the argument map for reflect.makeFuncStub from that known location. This doesn't work for defers or goroutines that haven't started yet, because they haven't allocated a frame or run an instruction yet. The argument map must be extracted from the context value. We already do this for defers (the non-nil ctxt arg to getArgInfo), we just need to do it for unstarted goroutines as well. When we traceback a goroutine, remember the context value from g.sched. Use it for the first frame we find. (We never need it for deeper frames, because we normally don't stop at the start of reflect.makeFuncStub, as it is nosplit. With this CL we could allow makeFuncStub to no longer be nosplit.) Fixes #25897 Change-Id: I427abf332a741a80728cdc0b8412aa8f37e7c418 Reviewed-on: https://go-review.googlesource.com/c/go/+/180258 Reviewed-by: Cherry Zhang <cherryyz@google.com>
- Loading branch information
Showing
3 changed files
with
82 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// run | ||
|
||
// Copyright 2019 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. | ||
|
||
// Make sure the runtime can scan args of an unstarted goroutine | ||
// which starts with a reflect-generated function. | ||
|
||
package main | ||
|
||
import ( | ||
"reflect" | ||
"runtime" | ||
) | ||
|
||
const N = 100 | ||
|
||
func main() { | ||
runtime.GOMAXPROCS(1) | ||
c := make(chan bool, N) | ||
for i := 0; i < N; i++ { | ||
f := reflect.MakeFunc(reflect.TypeOf(((func(*int))(nil))), | ||
func(args []reflect.Value) []reflect.Value { | ||
c <- true | ||
return nil | ||
}).Interface().(func(*int)) | ||
go f(nil) | ||
} | ||
runtime.GC() | ||
for i := 0; i < N; i++ { | ||
<-c | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// run | ||
|
||
// Copyright 2019 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. | ||
|
||
// Make sure the runtime can scan args of an unstarted goroutine | ||
// which starts with a reflect-generated function. | ||
|
||
package main | ||
|
||
import ( | ||
"reflect" | ||
"runtime" | ||
) | ||
|
||
const N = 100 | ||
|
||
type T struct { | ||
} | ||
|
||
func (t *T) Foo(c chan bool) { | ||
c <- true | ||
} | ||
|
||
func main() { | ||
t := &T{} | ||
runtime.GOMAXPROCS(1) | ||
c := make(chan bool, N) | ||
for i := 0; i < N; i++ { | ||
f := reflect.ValueOf(t).MethodByName("Foo").Interface().(func(chan bool)) | ||
go f(c) | ||
} | ||
runtime.GC() | ||
for i := 0; i < N; i++ { | ||
<-c | ||
} | ||
} |