runtime: close(chan)
This commit is contained in:
@@ -24,4 +24,26 @@ func doChan(cap int) {
|
|||||||
func main() {
|
func main() {
|
||||||
doChan(10)
|
doChan(10)
|
||||||
doChan(0)
|
doChan(0)
|
||||||
|
|
||||||
|
c := runtime.NewChan(eltSize, 3)
|
||||||
|
|
||||||
|
v := 1
|
||||||
|
runtime.ChanSend(c, unsafe.Pointer(&v), eltSize)
|
||||||
|
v = 2
|
||||||
|
runtime.ChanSend(c, unsafe.Pointer(&v), eltSize)
|
||||||
|
v = 3
|
||||||
|
runtime.ChanSend(c, unsafe.Pointer(&v), eltSize)
|
||||||
|
runtime.ChanClose(c)
|
||||||
|
|
||||||
|
v = 10
|
||||||
|
if runtime.ChanTrySend(c, unsafe.Pointer(&v), eltSize) {
|
||||||
|
println("error: chan send to closed chan")
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
if ok := runtime.ChanRecv(c, unsafe.Pointer(&v), eltSize); !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
println(v)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,9 @@ import (
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
const chanFull = 1
|
const (
|
||||||
|
chanFull = 1
|
||||||
|
)
|
||||||
|
|
||||||
type Chan struct {
|
type Chan struct {
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
@@ -34,6 +36,7 @@ type Chan struct {
|
|||||||
getp int
|
getp int
|
||||||
len int
|
len int
|
||||||
cap int
|
cap int
|
||||||
|
close bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewChan(eltSize, cap int) *Chan {
|
func NewChan(eltSize, cap int) *Chan {
|
||||||
@@ -57,18 +60,25 @@ func ChanCap(p *Chan) int {
|
|||||||
return p.cap
|
return p.cap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ChanClose(p *Chan) {
|
||||||
|
p.mutex.Lock()
|
||||||
|
p.close = true
|
||||||
|
p.mutex.Unlock()
|
||||||
|
p.cond.Broadcast()
|
||||||
|
}
|
||||||
|
|
||||||
func ChanTrySend(p *Chan, v unsafe.Pointer, eltSize int) bool {
|
func ChanTrySend(p *Chan, v unsafe.Pointer, eltSize int) bool {
|
||||||
n := p.cap
|
n := p.cap
|
||||||
p.mutex.Lock()
|
p.mutex.Lock()
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
if p.getp == chanFull {
|
if p.getp == chanFull || p.close {
|
||||||
p.mutex.Unlock()
|
p.mutex.Unlock()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
p.data = v
|
p.data = v
|
||||||
p.getp = chanFull
|
p.getp = chanFull
|
||||||
} else {
|
} else {
|
||||||
if p.len == n {
|
if p.len == n || p.close {
|
||||||
p.mutex.Unlock()
|
p.mutex.Unlock()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -81,25 +91,34 @@ func ChanTrySend(p *Chan, v unsafe.Pointer, eltSize int) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func ChanSend(p *Chan, v unsafe.Pointer, eltSize int) {
|
func ChanSend(p *Chan, v unsafe.Pointer, eltSize int) bool {
|
||||||
n := p.cap
|
n := p.cap
|
||||||
p.mutex.Lock()
|
p.mutex.Lock()
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
for p.getp == chanFull {
|
for p.getp == chanFull {
|
||||||
p.cond.Wait(&p.mutex)
|
p.cond.Wait(&p.mutex)
|
||||||
}
|
}
|
||||||
|
if p.close {
|
||||||
|
p.mutex.Unlock()
|
||||||
|
return false
|
||||||
|
}
|
||||||
p.data = v
|
p.data = v
|
||||||
p.getp = chanFull
|
p.getp = chanFull
|
||||||
} else {
|
} else {
|
||||||
for p.len == n {
|
for p.len == n {
|
||||||
p.cond.Wait(&p.mutex)
|
p.cond.Wait(&p.mutex)
|
||||||
}
|
}
|
||||||
|
if p.close {
|
||||||
|
p.mutex.Unlock()
|
||||||
|
return false
|
||||||
|
}
|
||||||
off := (p.getp + p.len) % n
|
off := (p.getp + p.len) % n
|
||||||
c.Memcpy(c.Advance(p.data, off*eltSize), v, uintptr(eltSize))
|
c.Memcpy(c.Advance(p.data, off*eltSize), v, uintptr(eltSize))
|
||||||
p.len++
|
p.len++
|
||||||
}
|
}
|
||||||
p.mutex.Unlock()
|
p.mutex.Unlock()
|
||||||
p.cond.Broadcast()
|
p.cond.Broadcast()
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func ChanTryRecv(p *Chan, v unsafe.Pointer, eltSize int) bool {
|
func ChanTryRecv(p *Chan, v unsafe.Pointer, eltSize int) bool {
|
||||||
@@ -126,17 +145,25 @@ func ChanTryRecv(p *Chan, v unsafe.Pointer, eltSize int) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func ChanRecv(p *Chan, v unsafe.Pointer, eltSize int) {
|
func ChanRecv(p *Chan, v unsafe.Pointer, eltSize int) bool {
|
||||||
n := p.cap
|
n := p.cap
|
||||||
p.mutex.Lock()
|
p.mutex.Lock()
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
for p.getp == 0 {
|
for p.getp == 0 {
|
||||||
|
if p.close {
|
||||||
|
p.mutex.Unlock()
|
||||||
|
return false
|
||||||
|
}
|
||||||
p.cond.Wait(&p.mutex)
|
p.cond.Wait(&p.mutex)
|
||||||
}
|
}
|
||||||
c.Memcpy(v, p.data, uintptr(eltSize))
|
c.Memcpy(v, p.data, uintptr(eltSize))
|
||||||
p.getp = 0
|
p.getp = 0
|
||||||
} else {
|
} else {
|
||||||
for p.len == 0 {
|
for p.len == 0 {
|
||||||
|
if p.close {
|
||||||
|
p.mutex.Unlock()
|
||||||
|
return false
|
||||||
|
}
|
||||||
p.cond.Wait(&p.mutex)
|
p.cond.Wait(&p.mutex)
|
||||||
}
|
}
|
||||||
c.Memcpy(v, c.Advance(p.data, p.getp*eltSize), uintptr(eltSize))
|
c.Memcpy(v, c.Advance(p.data, p.getp*eltSize), uintptr(eltSize))
|
||||||
@@ -145,6 +172,7 @@ func ChanRecv(p *Chan, v unsafe.Pointer, eltSize int) {
|
|||||||
}
|
}
|
||||||
p.mutex.Unlock()
|
p.mutex.Unlock()
|
||||||
p.cond.Broadcast()
|
p.cond.Broadcast()
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user