gc<Object> ChannelObject::receive(VM& vm, gc<Fiber> receiver) { // If the channel is closed, immediately receive 'done'. if (!isOpen_) return vm.getAtom(ATOM_DONE); // If we have a sender, take its value. if (senders_.count() > 0) { gc<Fiber> sender = senders_.removeAt(0); return sender->sendValue(); } // Otherwise, suspend. receivers_.add(receiver); return NULL; }
bool ChannelObject::close(VM& vm, gc<Fiber> sender) { if (!isOpen_) return false; isOpen_ = false; // If nothing is going to receive the "done". Just ignore it and close // immediately. if (receivers_.count() == 0) return false; // Send "done" to all of the receivers. for (int i = 0; i < receivers_.count(); i++) { receivers_[i]->storeReturn(vm.getAtom(ATOM_DONE)); receivers_[i]->ready(); } receivers_.clear(); // Add the sender back to the scheduler after the receiver so it can // continue. sender->ready(); return true; }