Commit 6a76bca3 authored by Keith Randall's avatar Keith Randall

runtime: convert closechan/chanlen/chancap to Go

LGTM=bradfitz, rsc
R=golang-codereviews, bradfitz, rsc
CC=golang-codereviews
https://golang.org/cl/135150043
parent b930b433
......@@ -150,12 +150,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
memmove(unsafe.Pointer(sg.elem), ep, uintptr(c.elemsize))
}
if sg.releasetime != 0 {
// Yes, this is ugly. On 64-bit sg.releasetime has type
// int. On 32-bit it has type int64. There's no easy way
// to assign to both types in Go. At some point we'll
// write the Go types directly instead of generating them
// via the C types. At that point, this nastiness goes away.
*(*int64)(unsafe.Pointer(&sg.releasetime)) = cputicks()
sg.releasetime = cputicks()
}
goready(recvg)
return true
......@@ -248,7 +243,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
recvg := sg.g
unlock(&c.lock)
if sg.releasetime != 0 {
*(*int64)(unsafe.Pointer(&sg.releasetime)) = cputicks()
sg.releasetime = cputicks()
}
goready(recvg)
} else {
......@@ -260,6 +255,72 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
return true
}
func closechan(c *hchan) {
if c == nil {
panic("close of nil channel")
}
lock(&c.lock)
if c.closed != 0 {
unlock(&c.lock)
panic("close of closed channel")
}
if raceenabled {
callerpc := getcallerpc(unsafe.Pointer(&c))
fn := closechan
pc := **(**uintptr)(unsafe.Pointer(&fn))
racewritepc(unsafe.Pointer(c), callerpc, pc)
racerelease(unsafe.Pointer(c))
}
c.closed = 1
// release all readers
for {
sg := c.recvq.dequeue()
if sg == nil {
break
}
gp := sg.g
gp.param = nil
if sg.releasetime != 0 {
sg.releasetime = cputicks()
}
goready(gp)
}
// release all writers
for {
sg := c.sendq.dequeue()
if sg == nil {
break
}
gp := sg.g
gp.param = nil
if sg.releasetime != 0 {
sg.releasetime = cputicks()
}
goready(gp)
}
unlock(&c.lock)
}
func reflect_chanlen(c *hchan) int {
if c == nil {
return 0
}
return int(c.qcount)
}
func reflect_chancap(c *hchan) int {
if c == nil {
return 0
}
return int(c.dataqsiz)
}
func (q *waitq) enqueue(sgp *sudog) {
sgp.next = nil
if q.first == nil {
......
......@@ -1005,81 +1005,6 @@ func reflect·rselect(cases Slice) (chosen int, recvOK bool) {
chosen = (intgo)(uintptr)selectgo(&sel);
}
static void closechan(Hchan *c, void *pc);
#pragma textflag NOSPLIT
func closechan(c *Hchan) {
closechan(c, runtime·getcallerpc(&c));
}
#pragma textflag NOSPLIT
func reflect·chanclose(c *Hchan) {
closechan(c, runtime·getcallerpc(&c));
}
static void
closechan(Hchan *c, void *pc)
{
SudoG *sg;
G* gp;
if(c == nil)
runtime·panicstring("close of nil channel");
runtime·lock(&c->lock);
if(c->closed) {
runtime·unlock(&c->lock);
runtime·panicstring("close of closed channel");
}
if(raceenabled) {
runtime·racewritepc(c, pc, runtime·closechan);
runtime·racerelease(c);
}
c->closed = true;
// release all readers
for(;;) {
sg = dequeue(&c->recvq);
if(sg == nil)
break;
gp = sg->g;
gp->param = nil;
if(sg->releasetime)
sg->releasetime = runtime·cputicks();
runtime·ready(gp);
}
// release all writers
for(;;) {
sg = dequeue(&c->sendq);
if(sg == nil)
break;
gp = sg->g;
gp->param = nil;
if(sg->releasetime)
sg->releasetime = runtime·cputicks();
runtime·ready(gp);
}
runtime·unlock(&c->lock);
}
func reflect·chanlen(c *Hchan) (len int) {
if(c == nil)
len = 0;
else
len = c->qcount;
}
func reflect·chancap(c *Hchan) (cap int) {
if(c == nil)
cap = 0;
else
cap = c->dataqsiz;
}
static SudoG*
dequeue(WaitQ *q)
{
......
......@@ -52,3 +52,12 @@ TEXT bytes·Compare(SB),NOSPLIT,$0-0
TEXT runtime·reflectcall(SB), NOSPLIT, $0-0
JMP reflect·call(SB)
TEXT reflect·chanclose(SB), NOSPLIT, $0-0
JMP runtime·closechan(SB)
TEXT reflect·chanlen(SB), NOSPLIT, $0-0
JMP runtime·reflect_chanlen(SB)
TEXT reflect·chancap(SB), NOSPLIT, $0-0
JMP runtime·reflect_chancap(SB)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment