Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions compiler/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,17 @@ func (b *builder) createChanSend(instr *ssa.Send) {
valueAlloca, valueAllocaCast, valueAllocaSize := b.createTemporaryAlloca(valueType, "chan.value")
b.CreateStore(chanValue, valueAlloca)

// Allocate blockedlist buffer.
channelBlockedList := b.mod.GetTypeByName("runtime.channelBlockedList")
channelBlockedListAlloca, channelBlockedListAllocaCast, channelBlockedListAllocaSize := b.createTemporaryAlloca(channelBlockedList, "chan.blockedList")

// Do the send.
b.createRuntimeCall("chanSend", []llvm.Value{ch, valueAllocaCast}, "")
b.createRuntimeCall("chanSend", []llvm.Value{ch, valueAllocaCast, channelBlockedListAlloca}, "")

// End the lifetime of the alloca.
// End the lifetime of the allocas.
// This also works around a bug in CoroSplit, at least in LLVM 8:
// https://bugs.llvm.org/show_bug.cgi?id=41742
b.emitLifetimeEnd(channelBlockedListAllocaCast, channelBlockedListAllocaSize)
b.emitLifetimeEnd(valueAllocaCast, valueAllocaSize)
}

Expand All @@ -53,9 +58,14 @@ func (b *builder) createChanRecv(unop *ssa.UnOp) llvm.Value {
// Allocate memory to receive into.
valueAlloca, valueAllocaCast, valueAllocaSize := b.createTemporaryAlloca(valueType, "chan.value")

// Allocate blockedlist buffer.
channelBlockedList := b.mod.GetTypeByName("runtime.channelBlockedList")
channelBlockedListAlloca, channelBlockedListAllocaCast, channelBlockedListAllocaSize := b.createTemporaryAlloca(channelBlockedList, "chan.blockedList")

// Do the receive.
commaOk := b.createRuntimeCall("chanRecv", []llvm.Value{ch, valueAllocaCast}, "")
commaOk := b.createRuntimeCall("chanRecv", []llvm.Value{ch, valueAllocaCast, channelBlockedListAlloca}, "")
received := b.CreateLoad(valueAlloca, "chan.received")
b.emitLifetimeEnd(channelBlockedListAllocaCast, channelBlockedListAllocaSize)
b.emitLifetimeEnd(valueAllocaCast, valueAllocaSize)

if unop.CommaOk {
Expand Down
10 changes: 6 additions & 4 deletions src/runtime/chan.go
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ type chanSelectState struct {
// chanSend sends a single value over the channel.
// This operation will block unless a value is immediately available.
// May panic if the channel is closed.
func chanSend(ch *channel, value unsafe.Pointer) {
func chanSend(ch *channel, value unsafe.Pointer, blockedlist *channelBlockedList) {
if ch.trySend(value) {
// value immediately sent
chanDebug(ch)
Expand All @@ -462,10 +462,11 @@ func chanSend(ch *channel, value unsafe.Pointer) {
sender := task.Current()
ch.state = chanStateSend
sender.Ptr = value
ch.blocked = &channelBlockedList{
*blockedlist = channelBlockedList{
next: ch.blocked,
t: sender,
}
ch.blocked = blockedlist
chanDebug(ch)
task.Pause()
sender.Ptr = nil
Expand All @@ -475,7 +476,7 @@ func chanSend(ch *channel, value unsafe.Pointer) {
// It blocks if there is no available value to recieve.
// The recieved value is copied into the value pointer.
// Returns the comma-ok value.
func chanRecv(ch *channel, value unsafe.Pointer) bool {
func chanRecv(ch *channel, value unsafe.Pointer, blockedlist *channelBlockedList) bool {
if rx, ok := ch.tryRecv(value); rx {
// value immediately available
chanDebug(ch)
Expand All @@ -491,10 +492,11 @@ func chanRecv(ch *channel, value unsafe.Pointer) bool {
receiver := task.Current()
ch.state = chanStateRecv
receiver.Ptr, receiver.Data = value, 1
ch.blocked = &channelBlockedList{
*blockedlist = channelBlockedList{
next: ch.blocked,
t: receiver,
}
ch.blocked = blockedlist
chanDebug(ch)
task.Pause()
ok := receiver.Data == 1
Expand Down