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
)
// 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
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.
c = (*hchan)(mallocgc(hchanSize+uintptr(size)*uintptr(elem.size), nil, flagNoScan))
if size > 0 && elem.size != 0 {
c.buf = (*uint8)(add(unsafe.Pointer(c), hchanSize))
c.buf = add(unsafe.Pointer(c), hchanSize)
} else {
// race detector uses this location for synchronization
// Also prevents us from pointing beyond the allocation (see issue 9401).
c.buf = (*uint8)(unsafe.Pointer(c))
c.buf = unsafe.Pointer(c)
}
} else {
c = new(hchan)
c.buf = (*uint8)(newarray(elem, uintptr(size)))
c.buf = newarray(elem, uintptr(size))
}
c.elemsize = uint16(elem.size)
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.
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

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 (
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 (
chansendpc = funcPC(chansend)
chanrecvpc = funcPC(chanrecv)
)
func selectsize(size uintptr) uintptr {
selsize := unsafe.Sizeof(_select{}) +
(size-1)*unsafe.Sizeof(_select{}.scase[0]) +
size*unsafe.Sizeof(*_select{}.lockorder) +
size*unsafe.Sizeof(*_select{}.pollorder)
selsize := unsafe.Sizeof(hselect{}) +
(size-1)*unsafe.Sizeof(hselect{}.scase[0]) +
size*unsafe.Sizeof(*hselect{}.lockorder) +
size*unsafe.Sizeof(*hselect{}.pollorder)
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))) {
print("runtime: bad select size ", selsize, ", want ", selectsize(uintptr(size)), "\n")
throw("bad select size")
}
sel.tcase = uint16(size)
sel.ncase = 0
sel.lockorder = (**hchan)(add(unsafe.Pointer(&sel.scase), uintptr(size)*unsafe.Sizeof(_select{}.scase[0])))
sel.pollorder = (*uint16)(add(unsafe.Pointer(sel.lockorder), uintptr(size)*unsafe.Sizeof(*_select{}.lockorder)))
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(*hselect{}.lockorder)))
if debugSelect {
print("newselect s=", sel, " size=", size, "\n")
@ -41,7 +70,7 @@ func newselect(sel *_select, selsize int64, size int32) {
}
//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
if c != nil {
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
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
if i >= sel.tcase {
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.pc = pc
cas._chan = c
cas.c = c
cas.so = uint16(so)
cas.kind = _CaseSend
cas.kind = caseSend
cas.elem = elem
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
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
if c != nil {
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
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
if c != nil {
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
}
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
if i >= sel.tcase {
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
cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
cas.pc = pc
cas._chan = c
cas.c = c
cas.so = uint16(so)
cas.kind = _CaseRecv
cas.kind = caseRecv
cas.elem = elem
cas.receivedp = received
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
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)))
return
}
func selectdefaultImpl(sel *_select, callerpc uintptr, so uintptr) {
func selectdefaultImpl(sel *hselect, callerpc uintptr, so uintptr) {
i := sel.ncase
if i >= sel.tcase {
throw("selectdefault: too many cases")
@ -120,16 +149,16 @@ func selectdefaultImpl(sel *_select, callerpc uintptr, so uintptr) {
sel.ncase = i + 1
cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
cas.pc = callerpc
cas._chan = nil
cas.c = nil
cas.so = uint16(so)
cas.kind = _CaseDefault
cas.kind = caseDefault
if debugSelect {
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)}
lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice))
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
// the last lock, because sel can be freed right after the last unlock.
// Consider the following situation.
@ -168,7 +197,7 @@ func selunlock(sel *_select) {
}
func selparkcommit(gp *g, sel unsafe.Pointer) bool {
selunlock((*_select)(sel))
selunlock((*hselect)(sel))
return true
}
@ -179,7 +208,7 @@ func block() {
// overwrites return pc on stack to signal which case of the select
// to run, so cannot appear at the top of a split stack.
//go:nosplit
func selectgo(sel *_select) {
func selectgo(sel *hselect) {
pc, offset := selectgoImpl(sel)
*(*bool)(add(unsafe.Pointer(&sel), uintptr(offset))) = true
setcallerpc(unsafe.Pointer(&sel), pc)
@ -187,7 +216,7 @@ func selectgo(sel *_select) {
// selectgoImpl returns scase.pc and scase.so for the select
// case which fired.
func selectgoImpl(sel *_select) (uintptr, uint16) {
func selectgoImpl(sel *hselect) (uintptr, uint16) {
if debugSelect {
print("select: sel=", sel, "\n")
}
@ -230,7 +259,7 @@ func selectgoImpl(sel *_select) (uintptr, uint16) {
lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice))
for i := 0; i < int(sel.ncase); i++ {
j := i
c := scases[j]._chan
c := scases[j].c
for j > 0 && lockorder[(j-1)/2].sortkey() < c.sortkey() {
k := (j - 1) / 2
lockorder[j] = lockorder[k]
@ -287,10 +316,10 @@ loop:
var cas *scase
for i := 0; i < int(sel.ncase); i++ {
cas = &scases[pollorder[i]]
c = cas._chan
c = cas.c
switch cas.kind {
case _CaseRecv:
case caseRecv:
if c.dataqsiz > 0 {
if c.qcount > 0 {
goto asyncrecv
@ -305,7 +334,7 @@ loop:
goto rclose
}
case _CaseSend:
case caseSend:
if raceenabled {
racereadpc(unsafe.Pointer(c), cas.pc, chansendpc)
}
@ -323,7 +352,7 @@ loop:
}
}
case _CaseDefault:
case caseDefault:
dfl = cas
}
}
@ -339,7 +368,7 @@ loop:
done = 0
for i := 0; i < int(sel.ncase); i++ {
cas = &scases[pollorder[i]]
c = cas._chan
c = cas.c
sg := acquireSudog()
sg.g = gp
// Note: selectdone is adjusted for stack copies in stack.c:adjustsudogs
@ -353,10 +382,10 @@ loop:
gp.waiting = sg
switch cas.kind {
case _CaseRecv:
case caseRecv:
c.recvq.enqueue(sg)
case _CaseSend:
case caseSend:
c.sendq.enqueue(sg)
}
}
@ -392,8 +421,8 @@ loop:
// sg has already been dequeued by the G that woke us up.
cas = k
} else {
c = k._chan
if k.kind == _CaseSend {
c = k.c
if k.kind == caseSend {
c.sendq.dequeueSudoG(sglist)
} else {
c.recvq.dequeueSudoG(sglist)
@ -409,7 +438,7 @@ loop:
goto loop
}
c = cas._chan
c = cas.c
if c.dataqsiz > 0 {
throw("selectgo: shouldn't happen")
@ -419,16 +448,16 @@ loop:
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 {
*cas.receivedp = true
}
}
if raceenabled {
if cas.kind == _CaseRecv && cas.elem != nil {
if cas.kind == caseRecv && cas.elem != nil {
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)
}
}
@ -599,7 +628,7 @@ const (
func reflect_rselect(cases []runtimeSelect) (chosen int, recvOK bool) {
// flagNoScan is safe here, because all objects are also referenced from 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)))
r := new(bool)
for i := range cases {