runtime: cleanup chan code

Move type definitions from chan1.go to chan.go and select.go.
Remove underscores from names.
Make c.buf unsafe.Pointer instead of *uint8.

Change-Id: I75cf8385bdb9f79eb5a7f7ad319495abbacbe942
Reviewed-on: https://go-review.googlesource.com/4900
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Dmitry Vyukov <dvyukov@google.com>
This commit is contained in:
Dmitry Vyukov 2015-02-14 16:42:51 +03:00
parent 04a3a74456
commit fcc164d783
3 changed files with 93 additions and 108 deletions

View File

@ -14,7 +14,24 @@ const (
debugChan = false debugChan = false
) )
// TODO(khr): make hchan.buf an unsafe.Pointer, not a *uint8 type hchan struct {
qcount uint // total data in the queue
dataqsiz uint // size of the circular queue
buf unsafe.Pointer // points to an array of dataqsiz elements
elemsize uint16
closed uint32
elemtype *_type // element type
sendx uint // send index
recvx uint // receive index
recvq waitq // list of recv waiters
sendq waitq // list of send waiters
lock mutex
}
type waitq struct {
first *sudog
last *sudog
}
//go:linkname reflect_makechan reflect.makechan //go:linkname reflect_makechan reflect.makechan
func reflect_makechan(t *chantype, size int64) *hchan { func reflect_makechan(t *chantype, size int64) *hchan {
@ -44,15 +61,15 @@ func makechan(t *chantype, size int64) *hchan {
// TODO(dvyukov,rlh): Rethink when collector can move allocated objects. // TODO(dvyukov,rlh): Rethink when collector can move allocated objects.
c = (*hchan)(mallocgc(hchanSize+uintptr(size)*uintptr(elem.size), nil, flagNoScan)) c = (*hchan)(mallocgc(hchanSize+uintptr(size)*uintptr(elem.size), nil, flagNoScan))
if size > 0 && elem.size != 0 { if size > 0 && elem.size != 0 {
c.buf = (*uint8)(add(unsafe.Pointer(c), hchanSize)) c.buf = add(unsafe.Pointer(c), hchanSize)
} else { } else {
// race detector uses this location for synchronization // race detector uses this location for synchronization
// Also prevents us from pointing beyond the allocation (see issue 9401). // Also prevents us from pointing beyond the allocation (see issue 9401).
c.buf = (*uint8)(unsafe.Pointer(c)) c.buf = unsafe.Pointer(c)
} }
} else { } else {
c = new(hchan) c = new(hchan)
c.buf = (*uint8)(newarray(elem, uintptr(size))) c.buf = newarray(elem, uintptr(size))
} }
c.elemsize = uint16(elem.size) c.elemsize = uint16(elem.size)
c.elemtype = elem c.elemtype = elem
@ -66,7 +83,7 @@ func makechan(t *chantype, size int64) *hchan {
// chanbuf(c, i) is pointer to the i'th slot in the buffer. // chanbuf(c, i) is pointer to the i'th slot in the buffer.
func chanbuf(c *hchan, i uint) unsafe.Pointer { func chanbuf(c *hchan, i uint) unsafe.Pointer {
return add(unsafe.Pointer(c.buf), uintptr(i)*uintptr(c.elemsize)) return add(c.buf, uintptr(i)*uintptr(c.elemsize))
} }
// entry point for c <- x from compiled code // entry point for c <- x from compiled code

View File

@ -1,61 +0,0 @@
// Copyright 2009 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 runtime
import "unsafe"
//#define MAXALIGN 8
type waitq struct {
first *sudog
last *sudog
}
type hchan struct {
qcount uint // total data in the q
dataqsiz uint // size of the circular q
buf *byte
elemsize uint16
closed uint32
elemtype *_type // element type
sendx uint // send index
recvx uint // receive index
recvq waitq // list of recv waiters
sendq waitq // list of send waiters
lock mutex
}
// Buffer follows Hchan immediately in memory.
// chanbuf(c, i) is pointer to the i'th slot in the buffer.
// #define chanbuf(c, i) ((byte*)((c)->buf)+(uintptr)(c)->elemsize*(i))
const (
// scase.kind
_CaseRecv = iota
_CaseSend
_CaseDefault
)
// Known to compiler.
// Changes here must also be made in src/cmd/gc/select.c's selecttype.
type scase struct {
elem unsafe.Pointer // data element
_chan *hchan // chan
pc uintptr // return pc
kind uint16
so uint16 // vararg of selected bool
receivedp *bool // pointer to received bool (recv2)
releasetime int64
}
// Known to compiler.
// Changes here must also be made in src/cmd/gc/select.c's selecttype.
type _select struct {
tcase uint16 // total count of scase[]
ncase uint16 // currently filled scase[]
pollorder *uint16 // case poll order
lockorder **hchan // channel lock order
scase [1]scase // one per case (in order of appearance)
}

View File

@ -10,30 +10,59 @@ import "unsafe"
const ( const (
debugSelect = false debugSelect = false
// scase.kind
caseRecv = iota
caseSend
caseDefault
) )
// Select statement header.
// Known to compiler.
// Changes here must also be made in src/cmd/internal/gc/select.go's selecttype.
type hselect struct {
tcase uint16 // total count of scase[]
ncase uint16 // currently filled scase[]
pollorder *uint16 // case poll order
lockorder **hchan // channel lock order
scase [1]scase // one per case (in order of appearance)
}
// Select case descriptor.
// Known to compiler.
// Changes here must also be made in src/cmd/internal/gc/select.go's selecttype.
type scase struct {
elem unsafe.Pointer // data element
c *hchan // chan
pc uintptr // return pc
kind uint16
so uint16 // vararg of selected bool
receivedp *bool // pointer to received bool (recv2)
releasetime int64
}
var ( var (
chansendpc = funcPC(chansend) chansendpc = funcPC(chansend)
chanrecvpc = funcPC(chanrecv) chanrecvpc = funcPC(chanrecv)
) )
func selectsize(size uintptr) uintptr { func selectsize(size uintptr) uintptr {
selsize := unsafe.Sizeof(_select{}) + selsize := unsafe.Sizeof(hselect{}) +
(size-1)*unsafe.Sizeof(_select{}.scase[0]) + (size-1)*unsafe.Sizeof(hselect{}.scase[0]) +
size*unsafe.Sizeof(*_select{}.lockorder) + size*unsafe.Sizeof(*hselect{}.lockorder) +
size*unsafe.Sizeof(*_select{}.pollorder) size*unsafe.Sizeof(*hselect{}.pollorder)
return round(selsize, _Int64Align) return round(selsize, _Int64Align)
} }
func newselect(sel *_select, selsize int64, size int32) { func newselect(sel *hselect, selsize int64, size int32) {
if selsize != int64(selectsize(uintptr(size))) { if selsize != int64(selectsize(uintptr(size))) {
print("runtime: bad select size ", selsize, ", want ", selectsize(uintptr(size)), "\n") print("runtime: bad select size ", selsize, ", want ", selectsize(uintptr(size)), "\n")
throw("bad select size") throw("bad select size")
} }
sel.tcase = uint16(size) sel.tcase = uint16(size)
sel.ncase = 0 sel.ncase = 0
sel.lockorder = (**hchan)(add(unsafe.Pointer(&sel.scase), uintptr(size)*unsafe.Sizeof(_select{}.scase[0]))) sel.lockorder = (**hchan)(add(unsafe.Pointer(&sel.scase), uintptr(size)*unsafe.Sizeof(hselect{}.scase[0])))
sel.pollorder = (*uint16)(add(unsafe.Pointer(sel.lockorder), uintptr(size)*unsafe.Sizeof(*_select{}.lockorder))) sel.pollorder = (*uint16)(add(unsafe.Pointer(sel.lockorder), uintptr(size)*unsafe.Sizeof(*hselect{}.lockorder)))
if debugSelect { if debugSelect {
print("newselect s=", sel, " size=", size, "\n") print("newselect s=", sel, " size=", size, "\n")
@ -41,7 +70,7 @@ func newselect(sel *_select, selsize int64, size int32) {
} }
//go:nosplit //go:nosplit
func selectsend(sel *_select, c *hchan, elem unsafe.Pointer) (selected bool) { func selectsend(sel *hselect, c *hchan, elem unsafe.Pointer) (selected bool) {
// nil cases do not compete // nil cases do not compete
if c != nil { if c != nil {
selectsendImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel))) selectsendImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel)))
@ -50,7 +79,7 @@ func selectsend(sel *_select, c *hchan, elem unsafe.Pointer) (selected bool) {
} }
// cut in half to give stack a chance to split // cut in half to give stack a chance to split
func selectsendImpl(sel *_select, c *hchan, pc uintptr, elem unsafe.Pointer, so uintptr) { func selectsendImpl(sel *hselect, c *hchan, pc uintptr, elem unsafe.Pointer, so uintptr) {
i := sel.ncase i := sel.ncase
if i >= sel.tcase { if i >= sel.tcase {
throw("selectsend: too many cases") throw("selectsend: too many cases")
@ -59,18 +88,18 @@ func selectsendImpl(sel *_select, c *hchan, pc uintptr, elem unsafe.Pointer, so
cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0]))) cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
cas.pc = pc cas.pc = pc
cas._chan = c cas.c = c
cas.so = uint16(so) cas.so = uint16(so)
cas.kind = _CaseSend cas.kind = caseSend
cas.elem = elem cas.elem = elem
if debugSelect { if debugSelect {
print("selectsend s=", sel, " pc=", hex(cas.pc), " chan=", cas._chan, " so=", cas.so, "\n") print("selectsend s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, " so=", cas.so, "\n")
} }
} }
//go:nosplit //go:nosplit
func selectrecv(sel *_select, c *hchan, elem unsafe.Pointer) (selected bool) { func selectrecv(sel *hselect, c *hchan, elem unsafe.Pointer) (selected bool) {
// nil cases do not compete // nil cases do not compete
if c != nil { if c != nil {
selectrecvImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, nil, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel))) selectrecvImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, nil, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel)))
@ -79,7 +108,7 @@ func selectrecv(sel *_select, c *hchan, elem unsafe.Pointer) (selected bool) {
} }
//go:nosplit //go:nosplit
func selectrecv2(sel *_select, c *hchan, elem unsafe.Pointer, received *bool) (selected bool) { func selectrecv2(sel *hselect, c *hchan, elem unsafe.Pointer, received *bool) (selected bool) {
// nil cases do not compete // nil cases do not compete
if c != nil { if c != nil {
selectrecvImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, received, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel))) selectrecvImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, received, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel)))
@ -87,7 +116,7 @@ func selectrecv2(sel *_select, c *hchan, elem unsafe.Pointer, received *bool) (s
return return
} }
func selectrecvImpl(sel *_select, c *hchan, pc uintptr, elem unsafe.Pointer, received *bool, so uintptr) { func selectrecvImpl(sel *hselect, c *hchan, pc uintptr, elem unsafe.Pointer, received *bool, so uintptr) {
i := sel.ncase i := sel.ncase
if i >= sel.tcase { if i >= sel.tcase {
throw("selectrecv: too many cases") throw("selectrecv: too many cases")
@ -95,24 +124,24 @@ func selectrecvImpl(sel *_select, c *hchan, pc uintptr, elem unsafe.Pointer, rec
sel.ncase = i + 1 sel.ncase = i + 1
cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0]))) cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
cas.pc = pc cas.pc = pc
cas._chan = c cas.c = c
cas.so = uint16(so) cas.so = uint16(so)
cas.kind = _CaseRecv cas.kind = caseRecv
cas.elem = elem cas.elem = elem
cas.receivedp = received cas.receivedp = received
if debugSelect { if debugSelect {
print("selectrecv s=", sel, " pc=", hex(cas.pc), " chan=", cas._chan, " so=", cas.so, "\n") print("selectrecv s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, " so=", cas.so, "\n")
} }
} }
//go:nosplit //go:nosplit
func selectdefault(sel *_select) (selected bool) { func selectdefault(sel *hselect) (selected bool) {
selectdefaultImpl(sel, getcallerpc(unsafe.Pointer(&sel)), uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel))) selectdefaultImpl(sel, getcallerpc(unsafe.Pointer(&sel)), uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel)))
return return
} }
func selectdefaultImpl(sel *_select, callerpc uintptr, so uintptr) { func selectdefaultImpl(sel *hselect, callerpc uintptr, so uintptr) {
i := sel.ncase i := sel.ncase
if i >= sel.tcase { if i >= sel.tcase {
throw("selectdefault: too many cases") throw("selectdefault: too many cases")
@ -120,16 +149,16 @@ func selectdefaultImpl(sel *_select, callerpc uintptr, so uintptr) {
sel.ncase = i + 1 sel.ncase = i + 1
cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0]))) cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
cas.pc = callerpc cas.pc = callerpc
cas._chan = nil cas.c = nil
cas.so = uint16(so) cas.so = uint16(so)
cas.kind = _CaseDefault cas.kind = caseDefault
if debugSelect { if debugSelect {
print("selectdefault s=", sel, " pc=", hex(cas.pc), " so=", cas.so, "\n") print("selectdefault s=", sel, " pc=", hex(cas.pc), " so=", cas.so, "\n")
} }
} }
func sellock(sel *_select) { func sellock(sel *hselect) {
lockslice := sliceStruct{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)} lockslice := sliceStruct{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)}
lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice)) lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice))
var c *hchan var c *hchan
@ -141,7 +170,7 @@ func sellock(sel *_select) {
} }
} }
func selunlock(sel *_select) { func selunlock(sel *hselect) {
// We must be very careful here to not touch sel after we have unlocked // We must be very careful here to not touch sel after we have unlocked
// the last lock, because sel can be freed right after the last unlock. // the last lock, because sel can be freed right after the last unlock.
// Consider the following situation. // Consider the following situation.
@ -168,7 +197,7 @@ func selunlock(sel *_select) {
} }
func selparkcommit(gp *g, sel unsafe.Pointer) bool { func selparkcommit(gp *g, sel unsafe.Pointer) bool {
selunlock((*_select)(sel)) selunlock((*hselect)(sel))
return true return true
} }
@ -179,7 +208,7 @@ func block() {
// overwrites return pc on stack to signal which case of the select // overwrites return pc on stack to signal which case of the select
// to run, so cannot appear at the top of a split stack. // to run, so cannot appear at the top of a split stack.
//go:nosplit //go:nosplit
func selectgo(sel *_select) { func selectgo(sel *hselect) {
pc, offset := selectgoImpl(sel) pc, offset := selectgoImpl(sel)
*(*bool)(add(unsafe.Pointer(&sel), uintptr(offset))) = true *(*bool)(add(unsafe.Pointer(&sel), uintptr(offset))) = true
setcallerpc(unsafe.Pointer(&sel), pc) setcallerpc(unsafe.Pointer(&sel), pc)
@ -187,7 +216,7 @@ func selectgo(sel *_select) {
// selectgoImpl returns scase.pc and scase.so for the select // selectgoImpl returns scase.pc and scase.so for the select
// case which fired. // case which fired.
func selectgoImpl(sel *_select) (uintptr, uint16) { func selectgoImpl(sel *hselect) (uintptr, uint16) {
if debugSelect { if debugSelect {
print("select: sel=", sel, "\n") print("select: sel=", sel, "\n")
} }
@ -230,7 +259,7 @@ func selectgoImpl(sel *_select) (uintptr, uint16) {
lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice)) lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice))
for i := 0; i < int(sel.ncase); i++ { for i := 0; i < int(sel.ncase); i++ {
j := i j := i
c := scases[j]._chan c := scases[j].c
for j > 0 && lockorder[(j-1)/2].sortkey() < c.sortkey() { for j > 0 && lockorder[(j-1)/2].sortkey() < c.sortkey() {
k := (j - 1) / 2 k := (j - 1) / 2
lockorder[j] = lockorder[k] lockorder[j] = lockorder[k]
@ -287,10 +316,10 @@ loop:
var cas *scase var cas *scase
for i := 0; i < int(sel.ncase); i++ { for i := 0; i < int(sel.ncase); i++ {
cas = &scases[pollorder[i]] cas = &scases[pollorder[i]]
c = cas._chan c = cas.c
switch cas.kind { switch cas.kind {
case _CaseRecv: case caseRecv:
if c.dataqsiz > 0 { if c.dataqsiz > 0 {
if c.qcount > 0 { if c.qcount > 0 {
goto asyncrecv goto asyncrecv
@ -305,7 +334,7 @@ loop:
goto rclose goto rclose
} }
case _CaseSend: case caseSend:
if raceenabled { if raceenabled {
racereadpc(unsafe.Pointer(c), cas.pc, chansendpc) racereadpc(unsafe.Pointer(c), cas.pc, chansendpc)
} }
@ -323,7 +352,7 @@ loop:
} }
} }
case _CaseDefault: case caseDefault:
dfl = cas dfl = cas
} }
} }
@ -339,7 +368,7 @@ loop:
done = 0 done = 0
for i := 0; i < int(sel.ncase); i++ { for i := 0; i < int(sel.ncase); i++ {
cas = &scases[pollorder[i]] cas = &scases[pollorder[i]]
c = cas._chan c = cas.c
sg := acquireSudog() sg := acquireSudog()
sg.g = gp sg.g = gp
// Note: selectdone is adjusted for stack copies in stack.c:adjustsudogs // Note: selectdone is adjusted for stack copies in stack.c:adjustsudogs
@ -353,10 +382,10 @@ loop:
gp.waiting = sg gp.waiting = sg
switch cas.kind { switch cas.kind {
case _CaseRecv: case caseRecv:
c.recvq.enqueue(sg) c.recvq.enqueue(sg)
case _CaseSend: case caseSend:
c.sendq.enqueue(sg) c.sendq.enqueue(sg)
} }
} }
@ -392,8 +421,8 @@ loop:
// sg has already been dequeued by the G that woke us up. // sg has already been dequeued by the G that woke us up.
cas = k cas = k
} else { } else {
c = k._chan c = k.c
if k.kind == _CaseSend { if k.kind == caseSend {
c.sendq.dequeueSudoG(sglist) c.sendq.dequeueSudoG(sglist)
} else { } else {
c.recvq.dequeueSudoG(sglist) c.recvq.dequeueSudoG(sglist)
@ -409,7 +438,7 @@ loop:
goto loop goto loop
} }
c = cas._chan c = cas.c
if c.dataqsiz > 0 { if c.dataqsiz > 0 {
throw("selectgo: shouldn't happen") throw("selectgo: shouldn't happen")
@ -419,16 +448,16 @@ loop:
print("wait-return: sel=", sel, " c=", c, " cas=", cas, " kind=", cas.kind, "\n") print("wait-return: sel=", sel, " c=", c, " cas=", cas, " kind=", cas.kind, "\n")
} }
if cas.kind == _CaseRecv { if cas.kind == caseRecv {
if cas.receivedp != nil { if cas.receivedp != nil {
*cas.receivedp = true *cas.receivedp = true
} }
} }
if raceenabled { if raceenabled {
if cas.kind == _CaseRecv && cas.elem != nil { if cas.kind == caseRecv && cas.elem != nil {
raceWriteObjectPC(c.elemtype, cas.elem, cas.pc, chanrecvpc) raceWriteObjectPC(c.elemtype, cas.elem, cas.pc, chanrecvpc)
} else if cas.kind == _CaseSend { } else if cas.kind == caseSend {
raceReadObjectPC(c.elemtype, cas.elem, cas.pc, chansendpc) raceReadObjectPC(c.elemtype, cas.elem, cas.pc, chansendpc)
} }
} }
@ -599,7 +628,7 @@ const (
func reflect_rselect(cases []runtimeSelect) (chosen int, recvOK bool) { func reflect_rselect(cases []runtimeSelect) (chosen int, recvOK bool) {
// flagNoScan is safe here, because all objects are also referenced from cases. // flagNoScan is safe here, because all objects are also referenced from cases.
size := selectsize(uintptr(len(cases))) size := selectsize(uintptr(len(cases)))
sel := (*_select)(mallocgc(size, nil, flagNoScan)) sel := (*hselect)(mallocgc(size, nil, flagNoScan))
newselect(sel, int64(size), int32(len(cases))) newselect(sel, int64(size), int32(len(cases)))
r := new(bool) r := new(bool)
for i := range cases { for i := range cases {