mirror of
https://github.com/golang/go
synced 2024-11-26 02:57:57 -07:00
[dev.cc] all: merge default (8d42099cdc23) into dev.cc
TBR=austin CC=golang-codereviews https://golang.org/cl/178700044
This commit is contained in:
commit
829b286f2c
1
.hgtags
1
.hgtags
@ -137,3 +137,4 @@ f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 go1.3.3
|
||||
f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 release
|
||||
1fdfd7dfaedb1b7702141617e621ab7328a236a1 go1.4beta1
|
||||
bffdd0cae380ce1ccf3e98ed6b6cd53fece7ba72 go1.4rc1
|
||||
6c4e66ae713704840fcea78c8055b44ba86ae5ea go1.4rc2
|
||||
|
@ -30,21 +30,16 @@ We encourage all Go users to subscribe to
|
||||
<h2 id="go1">Version history</h2>
|
||||
|
||||
<h3 id="release"><a href="/doc/devel/release.html">Release History</a></h3>
|
||||
<p>A summary of the changes between Go releases.</p>
|
||||
|
||||
<h4 id="go1notes"><a href="/doc/go1">Go 1 Release Notes</a></h4>
|
||||
<p>
|
||||
A guide for updating your code to work with Go 1.
|
||||
</p>
|
||||
<p>A <a href="/doc/devel/release.html">summary</a> of the changes between Go releases. Notes for the major releases:</p>
|
||||
|
||||
<h4 id="release notes"><a href="/doc/go1.1">Go 1.1 Release Notes</a></h4>
|
||||
<p>
|
||||
A list of significant changes in Go 1.1, with instructions for updating
|
||||
your code where necessary.
|
||||
Each point release includes a similar document appropriate for that
|
||||
release: <a href="/doc/go1.2">Go 1.2</a>, <a href="/doc/go1.3">Go 1.3</a>,
|
||||
and so on.
|
||||
</p>
|
||||
<ul>
|
||||
<li><a href="/doc/go1.4">Go 1.4</a> <small>(December 2014)</small></li>
|
||||
<li><a href="/doc/go1.3">Go 1.3</a> <small>(June 2014)</small></li>
|
||||
<li><a href="/doc/go1.2">Go 1.2</a> <small>(December 2013)</small></li>
|
||||
<li><a href="/doc/go1.1">Go 1.1</a> <small>(May 2013)</small></li>
|
||||
<li><a href="/doc/go1">Go 1</a> <small>(March 2012)</small></li>
|
||||
</ul>
|
||||
|
||||
<h3 id="go1compat"><a href="/doc/go1compat">Go 1 and the Future of Go Programs</a></h3>
|
||||
<p>
|
||||
|
@ -5579,7 +5579,7 @@ s3 := append(s2, s0...) // append a slice s3 == []int{0,
|
||||
s4 := append(s3[3:6], s3[2:]...) // append overlapping slice s4 == []int{3, 5, 7, 2, 3, 5, 7, 0, 0}
|
||||
|
||||
var t []interface{}
|
||||
t = append(t, 42, 3.1415, "foo") t == []interface{}{42, 3.1415, "foo"}
|
||||
t = append(t, 42, 3.1415, "foo") // t == []interface{}{42, 3.1415, "foo"}
|
||||
|
||||
var b []byte
|
||||
b = append(b, "bar"...) // append string contents b == []byte{'b', 'a', 'r' }
|
||||
|
@ -7,8 +7,8 @@
|
||||
# downloaded from the ICANN/IANA distribution.
|
||||
|
||||
# Versions to use.
|
||||
CODE=2014d
|
||||
DATA=2014d
|
||||
CODE=2014j
|
||||
DATA=2014j
|
||||
|
||||
set -e
|
||||
rm -rf work
|
||||
|
Binary file not shown.
@ -234,17 +234,24 @@ create or update Go source files, for instance by running yacc.
|
||||
Go generate is never run automatically by go build, go get, go test,
|
||||
and so on. It must be run explicitly.
|
||||
|
||||
Directives are written as a whole-line comment of the form
|
||||
Go generate scans the file for directives, which are lines of
|
||||
the form,
|
||||
|
||||
//go:generate command argument...
|
||||
|
||||
(note: no space in "//go") where command is the generator to be
|
||||
run, corresponding to an executable file that can be run locally.
|
||||
It must either be in the shell path (gofmt), a fully qualified path
|
||||
(/usr/you/bin/mytool), or a command alias, described below.
|
||||
(note: no leading spaces and no space in "//go") where command
|
||||
is the generator to be run, corresponding to an executable file
|
||||
that can be run locally. It must either be in the shell path
|
||||
(gofmt), a fully qualified path (/usr/you/bin/mytool), or a
|
||||
command alias, described below.
|
||||
|
||||
The arguments are space-separated tokens or double-quoted strings
|
||||
passed to the generator as individual arguments when it is run.
|
||||
Note that go generate does not parse the file, so lines that look
|
||||
like directives in comments or multiline strings will be treated
|
||||
as directives.
|
||||
|
||||
The arguments to the directive are space-separated tokens or
|
||||
double-quoted strings passed to the generator as individual
|
||||
arguments when it is run.
|
||||
|
||||
Quoted strings use Go syntax and are evaluated before execution; a
|
||||
quoted string appears as a single argument to the generator.
|
||||
@ -317,7 +324,7 @@ Download and install packages and dependencies
|
||||
|
||||
Usage:
|
||||
|
||||
go get [-d] [-fix] [-t] [-u] [build flags] [packages]
|
||||
go get [-d] [-f] [-fix] [-t] [-u] [build flags] [packages]
|
||||
|
||||
Get downloads and installs the packages named by the import paths,
|
||||
along with their dependencies.
|
||||
@ -325,6 +332,11 @@ along with their dependencies.
|
||||
The -d flag instructs get to stop after downloading the packages; that is,
|
||||
it instructs get not to install the packages.
|
||||
|
||||
The -f flag, valid only when -u is set, forces get -u not to verify that
|
||||
each package has been checked out from the source control repository
|
||||
implied by its import path. This can be useful if the source is a local fork
|
||||
of the original.
|
||||
|
||||
The -fix flag instructs get to run the fix tool on the downloaded packages
|
||||
before resolving dependencies or building the code.
|
||||
|
||||
|
@ -32,20 +32,27 @@ create or update Go source files, for instance by running yacc.
|
||||
Go generate is never run automatically by go build, go get, go test,
|
||||
and so on. It must be run explicitly.
|
||||
|
||||
Directives are written as a whole-line comment of the form
|
||||
Go generate scans the file for directives, which are lines of
|
||||
the form,
|
||||
|
||||
//go:generate command argument...
|
||||
|
||||
(note: no space in "//go") where command is the generator to be
|
||||
run, corresponding to an executable file that can be run locally.
|
||||
It must either be in the shell path (gofmt), a fully qualified path
|
||||
(/usr/you/bin/mytool), or a command alias, described below.
|
||||
(note: no leading spaces and no space in "//go") where command
|
||||
is the generator to be run, corresponding to an executable file
|
||||
that can be run locally. It must either be in the shell path
|
||||
(gofmt), a fully qualified path (/usr/you/bin/mytool), or a
|
||||
command alias, described below.
|
||||
|
||||
The arguments are space-separated tokens or double-quoted strings
|
||||
passed to the generator as individual arguments when it is run.
|
||||
Note that go generate does not parse the file, so lines that look
|
||||
like directives in comments or multiline strings will be treated
|
||||
as directives.
|
||||
|
||||
The arguments to the directive are space-separated tokens or
|
||||
double-quoted strings passed to the generator as individual
|
||||
arguments when it is run.
|
||||
|
||||
Quoted strings use Go syntax and are evaluated before execution; a
|
||||
quoted string appears a single argument to the generator.
|
||||
quoted string appears as a single argument to the generator.
|
||||
|
||||
Go generate sets several variables when it runs the generator:
|
||||
|
||||
@ -178,13 +185,43 @@ func (g *Generator) run() (ok bool) {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", shortPath(g.path))
|
||||
}
|
||||
|
||||
s := bufio.NewScanner(g.r)
|
||||
for s.Scan() {
|
||||
g.lineNum++
|
||||
if !bytes.HasPrefix(s.Bytes(), []byte("//go:generate ")) && !bytes.HasPrefix(s.Bytes(), []byte("//go:generate\t")) {
|
||||
// Scan for lines that start "//go:generate".
|
||||
// Can't use bufio.Scanner because it can't handle long lines,
|
||||
// which are likely to appear when using generate.
|
||||
input := bufio.NewReader(g.r)
|
||||
var err error
|
||||
// One line per loop.
|
||||
for {
|
||||
g.lineNum++ // 1-indexed.
|
||||
var buf []byte
|
||||
buf, err = input.ReadSlice('\n')
|
||||
if err == bufio.ErrBufferFull {
|
||||
// Line too long - consume and ignore.
|
||||
if isGoGenerate(buf) {
|
||||
g.errorf("directive too long")
|
||||
}
|
||||
for err == bufio.ErrBufferFull {
|
||||
_, err = input.ReadSlice('\n')
|
||||
}
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
words := g.split(s.Text())
|
||||
|
||||
if err != nil {
|
||||
// Check for marker at EOF without final \n.
|
||||
if err == io.EOF && isGoGenerate(buf) {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if !isGoGenerate(buf) {
|
||||
continue
|
||||
}
|
||||
|
||||
words := g.split(string(buf))
|
||||
if len(words) == 0 {
|
||||
g.errorf("no arguments to directive")
|
||||
}
|
||||
@ -201,19 +238,23 @@ func (g *Generator) run() (ok bool) {
|
||||
}
|
||||
g.exec(words)
|
||||
}
|
||||
if s.Err() != nil {
|
||||
g.errorf("error reading %s: %s", shortPath(g.path), s.Err())
|
||||
if err != nil && err != io.EOF {
|
||||
g.errorf("error reading %s: %s", shortPath(g.path), err)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func isGoGenerate(buf []byte) bool {
|
||||
return bytes.HasPrefix(buf, []byte("//go:generate ")) || bytes.HasPrefix(buf, []byte("//go:generate\t"))
|
||||
}
|
||||
|
||||
// split breaks the line into words, evaluating quoted
|
||||
// strings and evaluating environment variables.
|
||||
// The initial //go:generate element is dropped.
|
||||
// The initial //go:generate element is present in line.
|
||||
func (g *Generator) split(line string) []string {
|
||||
// Parse line, obeying quoted strings.
|
||||
var words []string
|
||||
line = line[len("//go:generate "):]
|
||||
line = line[len("//go:generate ") : len(line)-1] // Drop preamble and final newline.
|
||||
// One (possibly quoted) word per iteration.
|
||||
Words:
|
||||
for {
|
||||
|
@ -40,7 +40,7 @@ func TestGenerateCommandParse(t *testing.T) {
|
||||
}
|
||||
g.setShorthand([]string{"-command", "yacc", "go", "tool", "yacc"})
|
||||
for _, test := range splitTests {
|
||||
got := g.split("//go:generate " + test.in)
|
||||
got := g.split("//go:generate " + test.in + "\n")
|
||||
if !reflect.DeepEqual(got, test.out) {
|
||||
t.Errorf("split(%q): got %q expected %q", test.in, got, test.out)
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"cmd/pprof/internal/plugin"
|
||||
@ -71,15 +72,27 @@ func PProf(c Completer, interactive **bool, svgpan **string) Commands {
|
||||
"eog": {c, report.Dot, invokeVisualizer(interactive, invokeDot("svg"), "svg", []string{"eog"}), false, "Visualize graph through eog"},
|
||||
"evince": {c, report.Dot, invokeVisualizer(interactive, invokeDot("pdf"), "pdf", []string{"evince"}), false, "Visualize graph through evince"},
|
||||
"gv": {c, report.Dot, invokeVisualizer(interactive, invokeDot("ps"), "ps", []string{"gv --noantialias"}), false, "Visualize graph through gv"},
|
||||
"web": {c, report.Dot, invokeVisualizer(interactive, saveSVGToFile(svgpan), "svg", browsers), false, "Visualize graph through web browser"},
|
||||
"web": {c, report.Dot, invokeVisualizer(interactive, saveSVGToFile(svgpan), "svg", browsers()), false, "Visualize graph through web browser"},
|
||||
|
||||
// Visualize HTML directly generated by report.
|
||||
"weblist": {c, report.WebList, invokeVisualizer(interactive, awayFromTTY("html"), "html", browsers), true, "Output annotated source in HTML for functions matching regexp or address"},
|
||||
"weblist": {c, report.WebList, invokeVisualizer(interactive, awayFromTTY("html"), "html", browsers()), true, "Output annotated source in HTML for functions matching regexp or address"},
|
||||
}
|
||||
}
|
||||
|
||||
// List of web browsers to attempt for web visualization
|
||||
var browsers = []string{"chrome", "google-chrome", "firefox", "/usr/bin/open"}
|
||||
// browsers returns a list of commands to attempt for web visualization
|
||||
// on the current platform
|
||||
func browsers() []string {
|
||||
cmds := []string{"chrome", "google-chrome", "firefox"}
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
cmds = append(cmds, "/usr/bin/open")
|
||||
case "windows":
|
||||
cmds = append(cmds, "cmd /c start")
|
||||
default:
|
||||
cmds = append(cmds, "xdg-open")
|
||||
}
|
||||
return cmds
|
||||
}
|
||||
|
||||
// NewCompleter creates an autocompletion function for a set of commands.
|
||||
func NewCompleter(cs Commands) Completer {
|
||||
@ -142,6 +155,10 @@ func awayFromTTY(format string) PostProcessor {
|
||||
func invokeDot(format string) PostProcessor {
|
||||
divert := awayFromTTY(format)
|
||||
return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error {
|
||||
if _, err := exec.LookPath("dot"); err != nil {
|
||||
ui.PrintErr("Cannot find dot, have you installed Graphviz?")
|
||||
return err
|
||||
}
|
||||
cmd := exec.Command("dot", "-T"+format)
|
||||
var buf bytes.Buffer
|
||||
cmd.Stdin, cmd.Stdout, cmd.Stderr = input, &buf, os.Stderr
|
||||
@ -174,6 +191,7 @@ func invokeVisualizer(interactive **bool, format PostProcessor, suffix string, v
|
||||
if err = format(input, tempFile, ui); err != nil {
|
||||
return err
|
||||
}
|
||||
tempFile.Close() // on windows, if the file is Open, start cannot access it.
|
||||
// Try visualizers until one is successful
|
||||
for _, v := range visualizers {
|
||||
// Separate command and arguments for exec.Command.
|
||||
|
@ -32,6 +32,10 @@ func Symbolize(mode string, prof *profile.Profile, obj plugin.ObjTool, ui plugin
|
||||
}
|
||||
}
|
||||
|
||||
if len(prof.Mapping) == 0 {
|
||||
return fmt.Errorf("no known mappings")
|
||||
}
|
||||
|
||||
mt, err := newMapping(prof, obj, ui, force)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1310,11 +1310,13 @@ func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool {
|
||||
// auto-tagging to apply only to files with a non-empty prefix, so
|
||||
// "foo_linux.go" is tagged but "linux.go" is not. This allows new operating
|
||||
// sytems, such as android, to arrive without breaking existing code with
|
||||
// innocuous source code in "android.go". The easiest fix: files without
|
||||
// underscores are always included.
|
||||
if !strings.ContainsRune(name, '_') {
|
||||
// innocuous source code in "android.go". The easiest fix: cut everything
|
||||
// in the name before the initial _.
|
||||
i := strings.Index(name, "_")
|
||||
if i < 0 {
|
||||
return true
|
||||
}
|
||||
name = name[i:] // ignore everything before first _
|
||||
|
||||
l := strings.Split(name, "_")
|
||||
if n := len(l); n > 0 && l[n-1] == "test" {
|
||||
|
@ -189,6 +189,7 @@ var matchFileTests = []struct {
|
||||
{ctxtAndroid, "foo_plan9.go", "", false},
|
||||
{ctxtAndroid, "android.go", "", true},
|
||||
{ctxtAndroid, "plan9.go", "", true},
|
||||
{ctxtAndroid, "plan9_test.go", "", true},
|
||||
{ctxtAndroid, "arm.s", "", true},
|
||||
{ctxtAndroid, "amd64.s", "", true},
|
||||
}
|
||||
|
@ -4060,3 +4060,104 @@ func TestLargeGCProg(t *testing.T) {
|
||||
fv := ValueOf(func([256]*byte) {})
|
||||
fv.Call([]Value{ValueOf([256]*byte{})})
|
||||
}
|
||||
|
||||
// Issue 9179.
|
||||
func TestCallGC(t *testing.T) {
|
||||
f := func(a, b, c, d, e string) {
|
||||
}
|
||||
g := func(in []Value) []Value {
|
||||
runtime.GC()
|
||||
return nil
|
||||
}
|
||||
typ := ValueOf(f).Type()
|
||||
f2 := MakeFunc(typ, g).Interface().(func(string, string, string, string, string))
|
||||
f2("four", "five5", "six666", "seven77", "eight888")
|
||||
}
|
||||
|
||||
type funcLayoutTest struct {
|
||||
rcvr, t Type
|
||||
argsize, retOffset uintptr
|
||||
stack []byte
|
||||
}
|
||||
|
||||
var funcLayoutTests []funcLayoutTest
|
||||
|
||||
func init() {
|
||||
var argAlign = PtrSize
|
||||
if runtime.GOARCH == "amd64p32" {
|
||||
argAlign = 2 * PtrSize
|
||||
}
|
||||
roundup := func(x uintptr, a uintptr) uintptr {
|
||||
return (x + a - 1) / a * a
|
||||
}
|
||||
|
||||
funcLayoutTests = append(funcLayoutTests,
|
||||
funcLayoutTest{
|
||||
nil,
|
||||
ValueOf(func(a, b string) string { return "" }).Type(),
|
||||
4 * PtrSize,
|
||||
4 * PtrSize,
|
||||
[]byte{BitsPointer, BitsScalar, BitsPointer},
|
||||
})
|
||||
|
||||
var r []byte
|
||||
if PtrSize == 4 {
|
||||
r = []byte{BitsScalar, BitsScalar, BitsScalar, BitsPointer}
|
||||
} else {
|
||||
r = []byte{BitsScalar, BitsScalar, BitsPointer}
|
||||
}
|
||||
funcLayoutTests = append(funcLayoutTests,
|
||||
funcLayoutTest{
|
||||
nil,
|
||||
ValueOf(func(a, b, c uint32, p *byte, d uint16) {}).Type(),
|
||||
roundup(3*4, PtrSize) + PtrSize + 2,
|
||||
roundup(roundup(3*4, PtrSize)+PtrSize+2, argAlign),
|
||||
r,
|
||||
})
|
||||
|
||||
funcLayoutTests = append(funcLayoutTests,
|
||||
funcLayoutTest{
|
||||
nil,
|
||||
ValueOf(func(a map[int]int, b uintptr, c interface{}) {}).Type(),
|
||||
4 * PtrSize,
|
||||
4 * PtrSize,
|
||||
[]byte{BitsPointer, BitsScalar, BitsPointer, BitsPointer},
|
||||
})
|
||||
|
||||
type S struct {
|
||||
a, b uintptr
|
||||
c, d *byte
|
||||
}
|
||||
funcLayoutTests = append(funcLayoutTests,
|
||||
funcLayoutTest{
|
||||
nil,
|
||||
ValueOf(func(a S) {}).Type(),
|
||||
4 * PtrSize,
|
||||
4 * PtrSize,
|
||||
[]byte{BitsScalar, BitsScalar, BitsPointer, BitsPointer},
|
||||
})
|
||||
|
||||
funcLayoutTests = append(funcLayoutTests,
|
||||
funcLayoutTest{
|
||||
ValueOf((*byte)(nil)).Type(),
|
||||
ValueOf(func(a uintptr, b *int) {}).Type(),
|
||||
3 * PtrSize,
|
||||
roundup(3*PtrSize, argAlign),
|
||||
[]byte{BitsPointer, BitsScalar, BitsPointer},
|
||||
})
|
||||
}
|
||||
|
||||
func TestFuncLayout(t *testing.T) {
|
||||
for _, lt := range funcLayoutTests {
|
||||
_, argsize, retOffset, stack := FuncLayout(lt.t, lt.rcvr)
|
||||
if argsize != lt.argsize {
|
||||
t.Errorf("funcLayout(%v, %v).argsize=%d, want %d", lt.t, lt.rcvr, argsize, lt.argsize)
|
||||
}
|
||||
if retOffset != lt.retOffset {
|
||||
t.Errorf("funcLayout(%v, %v).retOffset=%d, want %d", lt.t, lt.rcvr, retOffset, lt.retOffset)
|
||||
}
|
||||
if !bytes.Equal(stack, lt.stack) {
|
||||
t.Errorf("funcLayout(%v, %v).stack=%v, want %v", lt.t, lt.rcvr, stack, lt.stack)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,3 +17,22 @@ func IsRO(v Value) bool {
|
||||
|
||||
var ArrayOf = arrayOf
|
||||
var CallGC = &callGC
|
||||
|
||||
const PtrSize = ptrSize
|
||||
const BitsPointer = bitsPointer
|
||||
const BitsScalar = bitsScalar
|
||||
|
||||
func FuncLayout(t Type, rcvr Type) (frametype Type, argSize, retOffset uintptr, stack []byte) {
|
||||
var ft *rtype
|
||||
var s *bitVector
|
||||
if rcvr != nil {
|
||||
ft, argSize, retOffset, s = funcLayout(t.(*rtype), rcvr.(*rtype))
|
||||
} else {
|
||||
ft, argSize, retOffset, s = funcLayout(t.(*rtype), nil)
|
||||
}
|
||||
frametype = ft
|
||||
for i := uint32(0); i < s.n; i += 2 {
|
||||
stack = append(stack, s.data[i/8]>>(i%8)&3)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -1889,14 +1889,14 @@ func addTypeBits(bv *bitVector, offset *uintptr, t *rtype) {
|
||||
switch Kind(t.kind & kindMask) {
|
||||
case Chan, Func, Map, Ptr, Slice, String, UnsafePointer:
|
||||
// 1 pointer at start of representation
|
||||
for bv.n < uint32(*offset/uintptr(ptrSize)) {
|
||||
for bv.n < 2*uint32(*offset/uintptr(ptrSize)) {
|
||||
bv.append2(bitsScalar)
|
||||
}
|
||||
bv.append2(bitsPointer)
|
||||
|
||||
case Interface:
|
||||
// 2 pointers
|
||||
for bv.n < uint32(*offset/uintptr(ptrSize)) {
|
||||
for bv.n < 2*uint32(*offset/uintptr(ptrSize)) {
|
||||
bv.append2(bitsScalar)
|
||||
}
|
||||
bv.append2(bitsPointer)
|
||||
|
@ -371,6 +371,11 @@ func casgstatus(gp *g, oldval, newval uint32) {
|
||||
// loop if gp->atomicstatus is in a scan state giving
|
||||
// GC time to finish and change the state to oldval.
|
||||
for !cas(&gp.atomicstatus, oldval, newval) {
|
||||
if oldval == _Gwaiting && gp.atomicstatus == _Grunnable {
|
||||
systemstack(func() {
|
||||
gothrow("casgstatus: waiting for Gwaiting but is Grunnable")
|
||||
})
|
||||
}
|
||||
// Help GC if needed.
|
||||
if gp.preemptscan && !gp.gcworkdone && (oldval == _Grunning || oldval == _Gsyscall) {
|
||||
gp.preemptscan = false
|
||||
@ -381,6 +386,24 @@ func casgstatus(gp *g, oldval, newval uint32) {
|
||||
}
|
||||
}
|
||||
|
||||
// casgstatus(gp, oldstatus, Gcopystack), assuming oldstatus is Gwaiting or Grunnable.
|
||||
// Returns old status. Cannot call casgstatus directly, because we are racing with an
|
||||
// async wakeup that might come in from netpoll. If we see Gwaiting from the readgstatus,
|
||||
// it might have become Grunnable by the time we get to the cas. If we called casgstatus,
|
||||
// it would loop waiting for the status to go back to Gwaiting, which it never will.
|
||||
//go:nosplit
|
||||
func casgcopystack(gp *g) uint32 {
|
||||
for {
|
||||
oldstatus := readgstatus(gp) &^ _Gscan
|
||||
if oldstatus != _Gwaiting && oldstatus != _Grunnable {
|
||||
gothrow("copystack: bad status, not Gwaiting or Grunnable")
|
||||
}
|
||||
if cas(&gp.atomicstatus, oldstatus, _Gcopystack) {
|
||||
return oldstatus
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// stopg ensures that gp is stopped at a GC safe point where its stack can be scanned
|
||||
// or in the context of a moving collector the pointers can be flipped from pointing
|
||||
// to old object to pointing to new objects.
|
||||
|
@ -563,13 +563,7 @@ func copystack(gp *g, newsize uintptr) {
|
||||
}
|
||||
memmove(unsafe.Pointer(new.hi-used), unsafe.Pointer(old.hi-used), used)
|
||||
|
||||
oldstatus := readgstatus(gp)
|
||||
oldstatus &^= _Gscan
|
||||
if oldstatus == _Gwaiting || oldstatus == _Grunnable {
|
||||
casgstatus(gp, oldstatus, _Gcopystack) // oldstatus is Gwaiting or Grunnable
|
||||
} else {
|
||||
gothrow("copystack: bad status, not Gwaiting or Grunnable")
|
||||
}
|
||||
oldstatus := casgcopystack(gp) // cas from Gwaiting or Grunnable to Gcopystack, return old status
|
||||
|
||||
// Swap out old stack for new one
|
||||
gp.stack = new
|
||||
|
Loading…
Reference in New Issue
Block a user