+ /* Answer all simcalls associated with the synchro */
+ finish();
+}
+
+void CommImpl::finish()
+{
+ XBT_DEBUG("CommImpl::finish() in state %s", to_c_str(state_));
+
+ /* If the synchro is still in a rendez-vous point then remove from it */
+ if (mbox_)
+ mbox_->remove(this);
+
+ if (state_ == State::DONE)
+ copy_data();
+
+ while (not simcalls_.empty()) {
+ smx_simcall_t simcall = simcalls_.front();
+ simcalls_.pop_front();
+
+ /* If a waitany simcall is waiting for this synchro to finish, then remove it from the other synchros in the waitany
+ * list. Afterwards, get the position of the actual synchro in the waitany list and return it as the result of the
+ * simcall */
+
+ if (simcall->call_ == simix::Simcall::NONE) // FIXME: maybe a better way to handle this case
+ continue; // if actor handling comm is killed
+ if (simcall->call_ == simix::Simcall::COMM_WAITANY) {
+ CommImpl** comms = simcall_comm_waitany__get__comms(simcall);
+ size_t count = simcall_comm_waitany__get__count(simcall);
+ for (size_t i = 0; i < count; i++)
+ comms[i]->unregister_simcall(simcall);
+ if (simcall->timeout_cb_) {
+ simcall->timeout_cb_->remove();
+ simcall->timeout_cb_ = nullptr;
+ }
+ if (not MC_is_active() && not MC_record_replay_is_active()) {
+ CommImpl** element = std::find(comms, comms + count, this);
+ ssize_t rank = (element != comms + count) ? element - comms : -1;
+ simcall_comm_waitany__set__result(simcall, rank);
+ }
+ }
+
+ /* Check out for errors */
+
+ if (not simcall->issuer_->get_host()->is_on()) {
+ simcall->issuer_->context_->set_wannadie();
+ } else {
+ switch (state_) {
+ case State::FAILED:
+ simcall->issuer_->exception_ =
+ std::make_exception_ptr(NetworkFailureException(XBT_THROW_POINT, "Remote peer failed"));
+ break;
+ case State::SRC_TIMEOUT:
+ simcall->issuer_->exception_ = std::make_exception_ptr(
+ TimeoutException(XBT_THROW_POINT, "Communication timeouted because of the sender"));
+ break;
+
+ case State::DST_TIMEOUT:
+ simcall->issuer_->exception_ = std::make_exception_ptr(
+ TimeoutException(XBT_THROW_POINT, "Communication timeouted because of the receiver"));
+ break;
+
+ case State::SRC_HOST_FAILURE:
+ if (simcall->issuer_ == src_actor_)
+ simcall->issuer_->context_->set_wannadie();
+ else {
+ state_ = kernel::activity::State::FAILED;
+ simcall->issuer_->exception_ =
+ std::make_exception_ptr(NetworkFailureException(XBT_THROW_POINT, "Remote peer failed"));
+ }
+ break;
+
+ case State::DST_HOST_FAILURE:
+ if (simcall->issuer_ == dst_actor_)
+ simcall->issuer_->context_->set_wannadie();
+ else {
+ state_ = kernel::activity::State::FAILED;
+ simcall->issuer_->exception_ =
+ std::make_exception_ptr(NetworkFailureException(XBT_THROW_POINT, "Remote peer failed"));
+ }
+ break;
+
+ case State::LINK_FAILURE:
+ XBT_DEBUG("Link failure in synchro %p between '%s' and '%s': posting an exception to the issuer: %s (%p) "
+ "detached:%d",
+ this, src_actor_ ? src_actor_->get_host()->get_cname() : nullptr,
+ dst_actor_ ? dst_actor_->get_host()->get_cname() : nullptr, simcall->issuer_->get_cname(),
+ simcall->issuer_, detached_);
+ if (src_actor_ == simcall->issuer_) {
+ XBT_DEBUG("I'm source");
+ } else if (dst_actor_ == simcall->issuer_) {
+ XBT_DEBUG("I'm dest");
+ } else {
+ XBT_DEBUG("I'm neither source nor dest");
+ }
+ state_ = kernel::activity::State::FAILED;
+ simcall->issuer_->throw_exception(
+ std::make_exception_ptr(NetworkFailureException(XBT_THROW_POINT, "Link failure")));
+ break;
+
+ case State::CANCELED:
+ if (simcall->issuer_ == dst_actor_)
+ simcall->issuer_->exception_ =
+ std::make_exception_ptr(CancelException(XBT_THROW_POINT, "Communication canceled by the sender"));
+ else
+ simcall->issuer_->exception_ =
+ std::make_exception_ptr(CancelException(XBT_THROW_POINT, "Communication canceled by the receiver"));
+ break;
+
+ default:
+ xbt_assert(state_ == State::DONE, "Internal error in CommImpl::finish(): unexpected synchro state %s",
+ to_c_str(state_));
+ }
+ simcall->issuer_->simcall_answer();
+ }
+ /* if there is an exception during a waitany or a testany, indicate the position of the failed communication */
+ if (simcall->issuer_->exception_ &&
+ (simcall->call_ == simix::Simcall::COMM_WAITANY || simcall->call_ == simix::Simcall::COMM_TESTANY)) {
+ // First retrieve the rank of our failing synchro
+ CommImpl** comms;
+ size_t count;
+ if (simcall->call_ == simix::Simcall::COMM_WAITANY) {
+ comms = simcall_comm_waitany__get__comms(simcall);
+ count = simcall_comm_waitany__get__count(simcall);
+ } else {
+ /* simcall->call_ == simix::Simcall::COMM_TESTANY */
+ comms = simcall_comm_testany__get__comms(simcall);
+ count = simcall_comm_testany__get__count(simcall);
+ }
+ CommImpl** element = std::find(comms, comms + count, this);
+ ssize_t rank = (element != comms + count) ? element - comms : -1;
+ // In order to modify the exception we have to rethrow it:
+ try {
+ std::rethrow_exception(simcall->issuer_->exception_);
+ } catch (Exception& e) {
+ e.set_value(rank);
+ }
+ }
+
+ simcall->issuer_->waiting_synchro_ = nullptr;
+ simcall->issuer_->activities_.remove(this);
+ if (detached_) {
+ if (simcall->issuer_ != dst_actor_ && dst_actor_ != nullptr)
+ dst_actor_->activities_.remove(this);
+ if (simcall->issuer_ != src_actor_ && src_actor_ != nullptr)
+ src_actor_->activities_.remove(this);
+ }