diff --git a/_demo/chandemo/chan.go b/_demo/chandemo/chan.go new file mode 100644 index 00000000..e94a3997 --- /dev/null +++ b/_demo/chandemo/chan.go @@ -0,0 +1,21 @@ +package main + +func main() { + c1 := make(chan string) + c2 := make(chan string, 1) + go func() { + c1 <- "ch1" + }() + go func() { + c2 <- "ch2" + }() + + for i := 0; i < 2; i++ { + select { + case msg1 := <-c1: + println(msg1) + case msg2 := <-c2: + println(msg2) + } + } +} diff --git a/internal/runtime/z_chan.go b/internal/runtime/z_chan.go index 2438b8b0..9bf5fefa 100644 --- a/internal/runtime/z_chan.go +++ b/internal/runtime/z_chan.go @@ -38,6 +38,7 @@ type Chan struct { len int cap int sops *selectOp + sends uint16 close bool } @@ -108,7 +109,9 @@ func ChanSend(p *Chan, v unsafe.Pointer, eltSize int) bool { p.mutex.Lock() if n == 0 { for p.getp != chanHasRecv && !p.close { + p.sends++ p.cond.Wait(&p.mutex) + p.sends-- } if p.close { p.mutex.Unlock() @@ -140,9 +143,13 @@ func ChanTryRecv(p *Chan, v unsafe.Pointer, eltSize int) (recvOK bool, tryOK boo n := p.cap p.mutex.Lock() if n == 0 { - tryOK = p.close - p.mutex.Unlock() - return + if p.sends == 0 || p.getp == chanHasRecv || p.close { + tryOK = p.close + p.mutex.Unlock() + return + } + p.getp = chanHasRecv + p.data = v } else { if p.len == 0 { tryOK = p.close @@ -158,7 +165,18 @@ func ChanTryRecv(p *Chan, v unsafe.Pointer, eltSize int) (recvOK bool, tryOK boo notifyOps(p) p.mutex.Unlock() p.cond.Broadcast() - return true, true + if n == 0 { + p.mutex.Lock() + if p.getp == chanHasRecv { + p.cond.Wait(&p.mutex) + } + recvOK = (p.getp != chanHasRecv) + tryOK = recvOK + p.mutex.Unlock() + } else { + recvOK, tryOK = true, true + } + return } func ChanRecv(p *Chan, v unsafe.Pointer, eltSize int) (recvOK bool) {