mirror of
https://github.com/golang/go.git
synced 2025-05-11 02:23:00 +00:00
runtime: eliminate scase.kind field
Currently, we include a "kind" field on scase to distinguish the three kinds of cases in a select statement: sends, receives, and defaults. This commit removes by kind field by instead arranging for the compiler to always place sends before receives, and to provide their counts separately. It also passes an explicit "block bool" parameter to avoid needing to include a default case in the array. It's safe to shuffle cases like this because the runtime will randomize the order they're polled in anyway. Fixes #40410. Change-Id: Iaeaed4cf7bddd576d78f2c863bd91a03a5c82df2 Reviewed-on: https://go-review.googlesource.com/c/go/+/245125 Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
d36bc7d78a
commit
fe23ba4a14
@ -302,7 +302,7 @@ func runtimeTypes() []*types.Type {
|
|||||||
typs[96] = types.NewPtr(typs[6])
|
typs[96] = types.NewPtr(typs[6])
|
||||||
typs[97] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[96]), anonfield(typs[84])}, []*Node{anonfield(typs[6])})
|
typs[97] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[96]), anonfield(typs[84])}, []*Node{anonfield(typs[6])})
|
||||||
typs[98] = functype(nil, []*Node{anonfield(typs[63])}, nil)
|
typs[98] = functype(nil, []*Node{anonfield(typs[63])}, nil)
|
||||||
typs[99] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[63]), anonfield(typs[15])}, []*Node{anonfield(typs[15]), anonfield(typs[6])})
|
typs[99] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[63]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[6])}, []*Node{anonfield(typs[15]), anonfield(typs[6])})
|
||||||
typs[100] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[7])})
|
typs[100] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[7])})
|
||||||
typs[101] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[7])})
|
typs[101] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[7])})
|
||||||
typs[102] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[7])}, []*Node{anonfield(typs[7])})
|
typs[102] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[7])}, []*Node{anonfield(typs[7])})
|
||||||
|
@ -170,7 +170,7 @@ func selectnbrecv(elem *any, hchan <-chan any) bool
|
|||||||
func selectnbrecv2(elem *any, received *bool, hchan <-chan any) bool
|
func selectnbrecv2(elem *any, received *bool, hchan <-chan any) bool
|
||||||
|
|
||||||
func selectsetpc(pc *uintptr)
|
func selectsetpc(pc *uintptr)
|
||||||
func selectgo(cas0 *byte, order0 *byte, pc0 *uintptr, ncases int) (int, bool)
|
func selectgo(cas0 *byte, order0 *byte, pc0 *uintptr, nsends int, nrecvs int, block bool) (int, bool)
|
||||||
func block()
|
func block()
|
||||||
|
|
||||||
func makeslice(typ *byte, len int, cap int) unsafe.Pointer
|
func makeslice(typ *byte, len int, cap int) unsafe.Pointer
|
||||||
|
@ -106,18 +106,16 @@ func walkselect(sel *Node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func walkselectcases(cases *Nodes) []*Node {
|
func walkselectcases(cases *Nodes) []*Node {
|
||||||
n := cases.Len()
|
ncas := cases.Len()
|
||||||
sellineno := lineno
|
sellineno := lineno
|
||||||
|
|
||||||
// optimization: zero-case select
|
// optimization: zero-case select
|
||||||
if n == 0 {
|
if ncas == 0 {
|
||||||
return []*Node{mkcall("block", nil, nil)}
|
return []*Node{mkcall("block", nil, nil)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// optimization: one-case select: single op.
|
// optimization: one-case select: single op.
|
||||||
// TODO(rsc): Reenable optimization once order.go can handle it.
|
if ncas == 1 {
|
||||||
// golang.org/issue/7672.
|
|
||||||
if n == 1 {
|
|
||||||
cas := cases.First()
|
cas := cases.First()
|
||||||
setlineno(cas)
|
setlineno(cas)
|
||||||
l := cas.Ninit.Slice()
|
l := cas.Ninit.Slice()
|
||||||
@ -178,10 +176,12 @@ func walkselectcases(cases *Nodes) []*Node {
|
|||||||
|
|
||||||
// convert case value arguments to addresses.
|
// convert case value arguments to addresses.
|
||||||
// this rewrite is used by both the general code and the next optimization.
|
// this rewrite is used by both the general code and the next optimization.
|
||||||
|
var dflt *Node
|
||||||
for _, cas := range cases.Slice() {
|
for _, cas := range cases.Slice() {
|
||||||
setlineno(cas)
|
setlineno(cas)
|
||||||
n := cas.Left
|
n := cas.Left
|
||||||
if n == nil {
|
if n == nil {
|
||||||
|
dflt = cas
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
switch n.Op {
|
switch n.Op {
|
||||||
@ -202,15 +202,10 @@ func walkselectcases(cases *Nodes) []*Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// optimization: two-case select but one is default: single non-blocking op.
|
// optimization: two-case select but one is default: single non-blocking op.
|
||||||
if n == 2 && (cases.First().Left == nil || cases.Second().Left == nil) {
|
if ncas == 2 && dflt != nil {
|
||||||
var cas *Node
|
cas := cases.First()
|
||||||
var dflt *Node
|
if cas == dflt {
|
||||||
if cases.First().Left == nil {
|
|
||||||
cas = cases.Second()
|
cas = cases.Second()
|
||||||
dflt = cases.First()
|
|
||||||
} else {
|
|
||||||
dflt = cases.Second()
|
|
||||||
cas = cases.First()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
n := cas.Left
|
n := cas.Left
|
||||||
@ -257,74 +252,73 @@ func walkselectcases(cases *Nodes) []*Node {
|
|||||||
return []*Node{r, nod(OBREAK, nil, nil)}
|
return []*Node{r, nod(OBREAK, nil, nil)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if dflt != nil {
|
||||||
|
ncas--
|
||||||
|
}
|
||||||
|
casorder := make([]*Node, ncas)
|
||||||
|
nsends, nrecvs := 0, 0
|
||||||
|
|
||||||
var init []*Node
|
var init []*Node
|
||||||
|
|
||||||
// generate sel-struct
|
// generate sel-struct
|
||||||
lineno = sellineno
|
lineno = sellineno
|
||||||
selv := temp(types.NewArray(scasetype(), int64(n)))
|
selv := temp(types.NewArray(scasetype(), int64(ncas)))
|
||||||
r := nod(OAS, selv, nil)
|
r := nod(OAS, selv, nil)
|
||||||
r = typecheck(r, ctxStmt)
|
r = typecheck(r, ctxStmt)
|
||||||
init = append(init, r)
|
init = append(init, r)
|
||||||
|
|
||||||
order := temp(types.NewArray(types.Types[TUINT16], 2*int64(n)))
|
order := temp(types.NewArray(types.Types[TUINT16], 2*int64(ncas)))
|
||||||
r = nod(OAS, order, nil)
|
r = nod(OAS, order, nil)
|
||||||
r = typecheck(r, ctxStmt)
|
r = typecheck(r, ctxStmt)
|
||||||
init = append(init, r)
|
init = append(init, r)
|
||||||
|
|
||||||
var pc0, pcs *Node
|
var pc0, pcs *Node
|
||||||
if flag_race {
|
if flag_race {
|
||||||
pcs = temp(types.NewArray(types.Types[TUINTPTR], int64(n)))
|
pcs = temp(types.NewArray(types.Types[TUINTPTR], int64(ncas)))
|
||||||
pc0 = typecheck(nod(OADDR, nod(OINDEX, pcs, nodintconst(0)), nil), ctxExpr)
|
pc0 = typecheck(nod(OADDR, nod(OINDEX, pcs, nodintconst(0)), nil), ctxExpr)
|
||||||
} else {
|
} else {
|
||||||
pc0 = nodnil()
|
pc0 = nodnil()
|
||||||
}
|
}
|
||||||
|
|
||||||
// register cases
|
// register cases
|
||||||
for i, cas := range cases.Slice() {
|
for _, cas := range cases.Slice() {
|
||||||
setlineno(cas)
|
setlineno(cas)
|
||||||
|
|
||||||
init = append(init, cas.Ninit.Slice()...)
|
init = append(init, cas.Ninit.Slice()...)
|
||||||
cas.Ninit.Set(nil)
|
cas.Ninit.Set(nil)
|
||||||
|
|
||||||
// Keep in sync with runtime/select.go.
|
n := cas.Left
|
||||||
const (
|
if n == nil { // default:
|
||||||
caseNil = iota
|
continue
|
||||||
caseRecv
|
|
||||||
caseSend
|
|
||||||
caseDefault
|
|
||||||
)
|
|
||||||
|
|
||||||
var c, elem *Node
|
|
||||||
var kind int64 = caseDefault
|
|
||||||
|
|
||||||
if n := cas.Left; n != nil {
|
|
||||||
init = append(init, n.Ninit.Slice()...)
|
|
||||||
|
|
||||||
switch n.Op {
|
|
||||||
default:
|
|
||||||
Fatalf("select %v", n.Op)
|
|
||||||
case OSEND:
|
|
||||||
kind = caseSend
|
|
||||||
c = n.Left
|
|
||||||
elem = n.Right
|
|
||||||
case OSELRECV, OSELRECV2:
|
|
||||||
kind = caseRecv
|
|
||||||
c = n.Right.Left
|
|
||||||
elem = n.Left
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var i int
|
||||||
|
var c, elem *Node
|
||||||
|
switch n.Op {
|
||||||
|
default:
|
||||||
|
Fatalf("select %v", n.Op)
|
||||||
|
case OSEND:
|
||||||
|
i = nsends
|
||||||
|
nsends++
|
||||||
|
c = n.Left
|
||||||
|
elem = n.Right
|
||||||
|
case OSELRECV, OSELRECV2:
|
||||||
|
nrecvs++
|
||||||
|
i = ncas - nrecvs
|
||||||
|
c = n.Right.Left
|
||||||
|
elem = n.Left
|
||||||
|
}
|
||||||
|
|
||||||
|
casorder[i] = cas
|
||||||
|
|
||||||
setField := func(f string, val *Node) {
|
setField := func(f string, val *Node) {
|
||||||
r := nod(OAS, nodSym(ODOT, nod(OINDEX, selv, nodintconst(int64(i))), lookup(f)), val)
|
r := nod(OAS, nodSym(ODOT, nod(OINDEX, selv, nodintconst(int64(i))), lookup(f)), val)
|
||||||
r = typecheck(r, ctxStmt)
|
r = typecheck(r, ctxStmt)
|
||||||
init = append(init, r)
|
init = append(init, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
setField("kind", nodintconst(kind))
|
c = convnop(c, types.Types[TUNSAFEPTR])
|
||||||
if c != nil {
|
setField("c", c)
|
||||||
c = convnop(c, types.Types[TUNSAFEPTR])
|
|
||||||
setField("c", c)
|
|
||||||
}
|
|
||||||
if elem != nil {
|
if elem != nil {
|
||||||
elem = convnop(elem, types.Types[TUNSAFEPTR])
|
elem = convnop(elem, types.Types[TUNSAFEPTR])
|
||||||
setField("elem", elem)
|
setField("elem", elem)
|
||||||
@ -337,6 +331,9 @@ func walkselectcases(cases *Nodes) []*Node {
|
|||||||
init = append(init, r)
|
init = append(init, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if nsends+nrecvs != ncas {
|
||||||
|
Fatalf("walkselectcases: miscount: %v + %v != %v", nsends, nrecvs, ncas)
|
||||||
|
}
|
||||||
|
|
||||||
// run the select
|
// run the select
|
||||||
lineno = sellineno
|
lineno = sellineno
|
||||||
@ -345,7 +342,7 @@ func walkselectcases(cases *Nodes) []*Node {
|
|||||||
r = nod(OAS2, nil, nil)
|
r = nod(OAS2, nil, nil)
|
||||||
r.List.Set2(chosen, recvOK)
|
r.List.Set2(chosen, recvOK)
|
||||||
fn := syslook("selectgo")
|
fn := syslook("selectgo")
|
||||||
r.Rlist.Set1(mkcall1(fn, fn.Type.Results(), nil, bytePtrToIndex(selv, 0), bytePtrToIndex(order, 0), pc0, nodintconst(int64(n))))
|
r.Rlist.Set1(mkcall1(fn, fn.Type.Results(), nil, bytePtrToIndex(selv, 0), bytePtrToIndex(order, 0), pc0, nodintconst(int64(nsends)), nodintconst(int64(nrecvs)), nodbool(dflt == nil)))
|
||||||
r = typecheck(r, ctxStmt)
|
r = typecheck(r, ctxStmt)
|
||||||
init = append(init, r)
|
init = append(init, r)
|
||||||
|
|
||||||
@ -357,14 +354,11 @@ func walkselectcases(cases *Nodes) []*Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// dispatch cases
|
// dispatch cases
|
||||||
for i, cas := range cases.Slice() {
|
dispatch := func(cond, cas *Node) {
|
||||||
setlineno(cas)
|
|
||||||
|
|
||||||
cond := nod(OEQ, chosen, nodintconst(int64(i)))
|
|
||||||
cond = typecheck(cond, ctxExpr)
|
cond = typecheck(cond, ctxExpr)
|
||||||
cond = defaultlit(cond, nil)
|
cond = defaultlit(cond, nil)
|
||||||
|
|
||||||
r = nod(OIF, cond, nil)
|
r := nod(OIF, cond, nil)
|
||||||
|
|
||||||
if n := cas.Left; n != nil && n.Op == OSELRECV2 {
|
if n := cas.Left; n != nil && n.Op == OSELRECV2 {
|
||||||
x := nod(OAS, n.List.First(), recvOK)
|
x := nod(OAS, n.List.First(), recvOK)
|
||||||
@ -377,6 +371,15 @@ func walkselectcases(cases *Nodes) []*Node {
|
|||||||
init = append(init, r)
|
init = append(init, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if dflt != nil {
|
||||||
|
setlineno(dflt)
|
||||||
|
dispatch(nod(OLT, chosen, nodintconst(0)), dflt)
|
||||||
|
}
|
||||||
|
for i, cas := range casorder {
|
||||||
|
setlineno(cas)
|
||||||
|
dispatch(nod(OEQ, chosen, nodintconst(int64(i))), cas)
|
||||||
|
}
|
||||||
|
|
||||||
return init
|
return init
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,7 +398,6 @@ func scasetype() *types.Type {
|
|||||||
scase = tostruct([]*Node{
|
scase = tostruct([]*Node{
|
||||||
namedfield("c", types.Types[TUNSAFEPTR]),
|
namedfield("c", types.Types[TUNSAFEPTR]),
|
||||||
namedfield("elem", types.Types[TUNSAFEPTR]),
|
namedfield("elem", types.Types[TUNSAFEPTR]),
|
||||||
namedfield("kind", types.Types[TUINT16]),
|
|
||||||
})
|
})
|
||||||
scase.SetNoalg(true)
|
scase.SetNoalg(true)
|
||||||
}
|
}
|
||||||
|
@ -1725,6 +1725,14 @@ func TestSelectMaxCases(t *testing.T) {
|
|||||||
_, _, _ = Select(sCases)
|
_, _, _ = Select(sCases)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSelectNop(t *testing.T) {
|
||||||
|
// "select { default: }" should always return the default case.
|
||||||
|
chosen, _, _ := Select([]SelectCase{{Dir: SelectDefault}})
|
||||||
|
if chosen != 0 {
|
||||||
|
t.Fatalf("expected Select to return 0, but got %#v", chosen)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkSelect(b *testing.B) {
|
func BenchmarkSelect(b *testing.B) {
|
||||||
channel := make(chan int)
|
channel := make(chan int)
|
||||||
close(channel)
|
close(channel)
|
||||||
|
@ -12,23 +12,12 @@ import (
|
|||||||
|
|
||||||
const debugSelect = false
|
const debugSelect = false
|
||||||
|
|
||||||
// scase.kind values.
|
|
||||||
// Known to compiler.
|
|
||||||
// Changes here must also be made in src/cmd/compile/internal/gc/select.go's walkselectcases.
|
|
||||||
const (
|
|
||||||
caseNil = iota
|
|
||||||
caseRecv
|
|
||||||
caseSend
|
|
||||||
caseDefault
|
|
||||||
)
|
|
||||||
|
|
||||||
// Select case descriptor.
|
// Select case descriptor.
|
||||||
// Known to compiler.
|
// Known to compiler.
|
||||||
// Changes here must also be made in src/cmd/internal/gc/select.go's scasetype.
|
// Changes here must also be made in src/cmd/internal/gc/select.go's scasetype.
|
||||||
type scase struct {
|
type scase struct {
|
||||||
c *hchan // chan
|
c *hchan // chan
|
||||||
elem unsafe.Pointer // data element
|
elem unsafe.Pointer // data element
|
||||||
kind uint16
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -115,7 +104,7 @@ func block() {
|
|||||||
// ordinal position of its respective select{recv,send,default} call.
|
// ordinal position of its respective select{recv,send,default} call.
|
||||||
// Also, if the chosen scase was a receive operation, it reports whether
|
// Also, if the chosen scase was a receive operation, it reports whether
|
||||||
// a value was received.
|
// a value was received.
|
||||||
func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, ncases int) (int, bool) {
|
func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, nsends, nrecvs int, block bool) (int, bool) {
|
||||||
if debugSelect {
|
if debugSelect {
|
||||||
print("select: cas0=", cas0, "\n")
|
print("select: cas0=", cas0, "\n")
|
||||||
}
|
}
|
||||||
@ -125,6 +114,7 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, ncases int) (int, bool)
|
|||||||
cas1 := (*[1 << 16]scase)(unsafe.Pointer(cas0))
|
cas1 := (*[1 << 16]scase)(unsafe.Pointer(cas0))
|
||||||
order1 := (*[1 << 17]uint16)(unsafe.Pointer(order0))
|
order1 := (*[1 << 17]uint16)(unsafe.Pointer(order0))
|
||||||
|
|
||||||
|
ncases := nsends + nrecvs
|
||||||
scases := cas1[:ncases:ncases]
|
scases := cas1[:ncases:ncases]
|
||||||
pollorder := order1[:ncases:ncases]
|
pollorder := order1[:ncases:ncases]
|
||||||
lockorder := order1[ncases:][:ncases:ncases]
|
lockorder := order1[ncases:][:ncases:ncases]
|
||||||
@ -158,16 +148,12 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, ncases int) (int, bool)
|
|||||||
// optimizing (and needing to test).
|
// optimizing (and needing to test).
|
||||||
|
|
||||||
// generate permuted order
|
// generate permuted order
|
||||||
dfli := -1
|
|
||||||
norder := 0
|
norder := 0
|
||||||
for i := range scases {
|
for i := range scases {
|
||||||
cas := &scases[i]
|
cas := &scases[i]
|
||||||
|
|
||||||
// Omit cases without channels from the poll and lock orders.
|
// Omit cases without channels from the poll and lock orders.
|
||||||
if cas.c == nil {
|
if cas.c == nil {
|
||||||
if cas.kind == caseDefault {
|
|
||||||
dfli = i
|
|
||||||
}
|
|
||||||
cas.elem = nil // allow GC
|
cas.elem = nil // allow GC
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -250,8 +236,7 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, ncases int) (int, bool)
|
|||||||
cas = &scases[casi]
|
cas = &scases[casi]
|
||||||
c = cas.c
|
c = cas.c
|
||||||
|
|
||||||
switch cas.kind {
|
if casi >= nsends {
|
||||||
case caseRecv:
|
|
||||||
sg = c.sendq.dequeue()
|
sg = c.sendq.dequeue()
|
||||||
if sg != nil {
|
if sg != nil {
|
||||||
goto recv
|
goto recv
|
||||||
@ -262,8 +247,7 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, ncases int) (int, bool)
|
|||||||
if c.closed != 0 {
|
if c.closed != 0 {
|
||||||
goto rclose
|
goto rclose
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
case caseSend:
|
|
||||||
if raceenabled {
|
if raceenabled {
|
||||||
racereadpc(c.raceaddr(), casePC(casi), chansendpc)
|
racereadpc(c.raceaddr(), casePC(casi), chansendpc)
|
||||||
}
|
}
|
||||||
@ -280,9 +264,9 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, ncases int) (int, bool)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if dfli >= 0 {
|
if !block {
|
||||||
selunlock(scases, lockorder)
|
selunlock(scases, lockorder)
|
||||||
casi = dfli
|
casi = -1
|
||||||
goto retc
|
goto retc
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,12 +295,10 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, ncases int) (int, bool)
|
|||||||
*nextp = sg
|
*nextp = sg
|
||||||
nextp = &sg.waitlink
|
nextp = &sg.waitlink
|
||||||
|
|
||||||
switch cas.kind {
|
if casi < nsends {
|
||||||
case caseRecv:
|
|
||||||
c.recvq.enqueue(sg)
|
|
||||||
|
|
||||||
case caseSend:
|
|
||||||
c.sendq.enqueue(sg)
|
c.sendq.enqueue(sg)
|
||||||
|
} else {
|
||||||
|
c.recvq.enqueue(sg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,7 +341,7 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, ncases int) (int, bool)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c = k.c
|
c = k.c
|
||||||
if k.kind == caseSend {
|
if int(casei) < nsends {
|
||||||
c.sendq.dequeueSudoG(sglist)
|
c.sendq.dequeueSudoG(sglist)
|
||||||
} else {
|
} else {
|
||||||
c.recvq.dequeueSudoG(sglist)
|
c.recvq.dequeueSudoG(sglist)
|
||||||
@ -378,27 +360,29 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, ncases int) (int, bool)
|
|||||||
c = cas.c
|
c = cas.c
|
||||||
|
|
||||||
if debugSelect {
|
if debugSelect {
|
||||||
print("wait-return: cas0=", cas0, " c=", c, " cas=", cas, " kind=", cas.kind, "\n")
|
print("wait-return: cas0=", cas0, " c=", c, " cas=", cas, " send=", casi < nsends, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
if cas.kind == caseRecv {
|
if casi < nsends {
|
||||||
|
if !caseSuccess {
|
||||||
|
goto sclose
|
||||||
|
}
|
||||||
|
} else {
|
||||||
recvOK = caseSuccess
|
recvOK = caseSuccess
|
||||||
} else if cas.kind == caseSend && !caseSuccess {
|
|
||||||
goto sclose
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if raceenabled {
|
if raceenabled {
|
||||||
if cas.kind == caseRecv && cas.elem != nil {
|
if casi < nsends {
|
||||||
raceWriteObjectPC(c.elemtype, cas.elem, casePC(casi), chanrecvpc)
|
|
||||||
} else if cas.kind == caseSend {
|
|
||||||
raceReadObjectPC(c.elemtype, cas.elem, casePC(casi), chansendpc)
|
raceReadObjectPC(c.elemtype, cas.elem, casePC(casi), chansendpc)
|
||||||
|
} else if cas.elem != nil {
|
||||||
|
raceWriteObjectPC(c.elemtype, cas.elem, casePC(casi), chanrecvpc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if msanenabled {
|
if msanenabled {
|
||||||
if cas.kind == caseRecv && cas.elem != nil {
|
if casi < nsends {
|
||||||
msanwrite(cas.elem, c.elemtype.size)
|
|
||||||
} else if cas.kind == caseSend {
|
|
||||||
msanread(cas.elem, c.elemtype.size)
|
msanread(cas.elem, c.elemtype.size)
|
||||||
|
} else if cas.elem != nil {
|
||||||
|
msanwrite(cas.elem, c.elemtype.size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -526,29 +510,57 @@ func reflect_rselect(cases []runtimeSelect) (int, bool) {
|
|||||||
block()
|
block()
|
||||||
}
|
}
|
||||||
sel := make([]scase, len(cases))
|
sel := make([]scase, len(cases))
|
||||||
order := make([]uint16, 2*len(cases))
|
orig := make([]int, len(cases))
|
||||||
for i := range cases {
|
nsends, nrecvs := 0, 0
|
||||||
rc := &cases[i]
|
dflt := -1
|
||||||
|
for i, rc := range cases {
|
||||||
|
var j int
|
||||||
switch rc.dir {
|
switch rc.dir {
|
||||||
case selectDefault:
|
case selectDefault:
|
||||||
sel[i] = scase{kind: caseDefault}
|
dflt = i
|
||||||
|
continue
|
||||||
case selectSend:
|
case selectSend:
|
||||||
sel[i] = scase{kind: caseSend, c: rc.ch, elem: rc.val}
|
j = nsends
|
||||||
|
nsends++
|
||||||
case selectRecv:
|
case selectRecv:
|
||||||
sel[i] = scase{kind: caseRecv, c: rc.ch, elem: rc.val}
|
nrecvs++
|
||||||
|
j = len(cases) - nrecvs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sel[j] = scase{c: rc.ch, elem: rc.val}
|
||||||
|
orig[j] = i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only a default case.
|
||||||
|
if nsends+nrecvs == 0 {
|
||||||
|
return dflt, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compact sel and orig if necessary.
|
||||||
|
if nsends+nrecvs < len(cases) {
|
||||||
|
copy(sel[nsends:], sel[len(cases)-nrecvs:])
|
||||||
|
copy(orig[nsends:], orig[len(cases)-nrecvs:])
|
||||||
|
}
|
||||||
|
|
||||||
|
order := make([]uint16, 2*(nsends+nrecvs))
|
||||||
var pc0 *uintptr
|
var pc0 *uintptr
|
||||||
if raceenabled {
|
if raceenabled {
|
||||||
pcs := make([]uintptr, len(cases))
|
pcs := make([]uintptr, nsends+nrecvs)
|
||||||
for i := range pcs {
|
for i := range pcs {
|
||||||
selectsetpc(&pcs[i])
|
selectsetpc(&pcs[i])
|
||||||
}
|
}
|
||||||
pc0 = &pcs[0]
|
pc0 = &pcs[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
return selectgo(&sel[0], &order[0], pc0, len(cases))
|
chosen, recvOK := selectgo(&sel[0], &order[0], pc0, nsends, nrecvs, dflt == -1)
|
||||||
|
|
||||||
|
// Translate chosen back to caller's ordering.
|
||||||
|
if chosen < 0 {
|
||||||
|
chosen = dflt
|
||||||
|
} else {
|
||||||
|
chosen = orig[chosen]
|
||||||
|
}
|
||||||
|
return chosen, recvOK
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *waitq) dequeueSudoG(sgp *sudog) {
|
func (q *waitq) dequeueSudoG(sgp *sudog) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user