void downstream_manager::close(stream_slot slot) {
  CAF_LOG_TRACE(CAF_ARG(slot));
  auto ptr = path(slot);
  if (ptr == nullptr) {
    CAF_LOG_DEBUG("cannot close unknown slot:" << slot);
    return;
  }
  if (buffered(slot) == 0 && ptr->clean()) {
    CAF_LOG_DEBUG("path clean, remove immediately;" << CAF_ARG(slot));
    remove_path(slot, none, false);
    return;
  }
  CAF_LOG_DEBUG("path not clean, set to closing;" << CAF_ARG(slot));
  ptr->closing = true;
}
Esempio n. 2
0
bool monitorable_actor::cleanup(error&& reason, execution_unit* host) {
  CAF_LOG_TRACE(CAF_ARG(reason));
  attachable_ptr head;
  bool set_fail_state = exclusive_critical_section([&]() -> bool {
    if (!getf(is_cleaned_up_flag)) {
      // local actors pass fail_state_ as first argument
      if (&fail_state_ != &reason)
        fail_state_ = std::move(reason);
      attachables_head_.swap(head);
      flags(flags() | is_terminated_flag | is_cleaned_up_flag);
      on_cleanup();
      return true;
    }
    return false;
  });
  if (!set_fail_state)
    return false;
  CAF_LOG_DEBUG("cleanup" << CAF_ARG(id())
                << CAF_ARG(node()) << CAF_ARG(reason));
  // send exit messages
  for (attachable* i = head.get(); i != nullptr; i = i->next.get())
    i->actor_exited(reason, host);
  // tell printer to purge its state for us if we ever used aout()
  if (getf(abstract_actor::has_used_aout_flag)) {
    auto pr = home_system().scheduler().printer();
    pr->enqueue(make_mailbox_element(nullptr, make_message_id(), {},
                                      delete_atom::value, id()),
                nullptr);
  }
  return true;
}
Esempio n. 3
0
void manager::detach(execution_unit*, bool invoke_disconnect_message) {
  CAF_LOG_TRACE(CAF_ARG(invoke_disconnect_message));
  // This function gets called from the multiplexer when an error occurs or
  // from the broker when closing this manager. In both cases, we need to make
  // sure this manager does not receive further socket events.
  remove_from_loop();
  // Disconnect from the broker if not already detached.
  if (!detached()) {
    CAF_LOG_DEBUG("disconnect servant from broker");
    auto raw_ptr = parent();
    // Keep a strong reference to our parent until we go out of scope.
    strong_actor_ptr ptr;
    ptr.swap(parent_);
    detach_from(raw_ptr);
    if (invoke_disconnect_message) {
      auto mptr = make_mailbox_element(nullptr, invalid_message_id,
                                       {}, detach_message());
      switch (raw_ptr->consume(*mptr)) {
        case im_success:
          raw_ptr->finalize();
          break;
        case im_skipped:
          raw_ptr->push_to_cache(std::move(mptr));
          break;
        case im_dropped:
          CAF_LOG_INFO("broker dropped disconnect message");
          break;
      }
    }
  }
}
 void deliver(response_promise& rp, message& x) {
   CAF_LOG_DEBUG("respond via response_promise");
   // suppress empty messages for asynchronous messages
   if (x.empty() && rp.async())
     return;
   rp.deliver(std::move(x));
 }
Esempio n. 5
0
  void stop() override {
    CAF_LOG_TRACE("");
    // shutdown workers
    class shutdown_helper : public resumable, public ref_counted {
    public:
      resumable::resume_result resume(execution_unit* ptr, size_t) override {
        CAF_LOG_DEBUG("shutdown_helper::resume => shutdown worker");
        CAF_ASSERT(ptr != nullptr);
        std::unique_lock<std::mutex> guard(mtx);
        last_worker = ptr;
        cv.notify_all();
        return resumable::shutdown_execution_unit;
      }
      void intrusive_ptr_add_ref_impl() override {
        intrusive_ptr_add_ref(this);
      }

      void intrusive_ptr_release_impl() override {
        intrusive_ptr_release(this);
      }
      shutdown_helper() : last_worker(nullptr) {
        // nop
      }
      std::mutex mtx;
      std::condition_variable cv;
      execution_unit* last_worker;
    };
    // use a set to keep track of remaining workers
    shutdown_helper sh;
    std::set<worker_type*> alive_workers;
    auto num = num_workers();
    for (size_t i = 0; i < num; ++i) {
      alive_workers.insert(worker_by_id(i));
      sh.ref(); // make sure reference count is high enough
    }
    CAF_LOG_DEBUG("enqueue shutdown_helper into each worker");
    while (!alive_workers.empty()) {
      (*alive_workers.begin())->external_enqueue(&sh);
      // since jobs can be stolen, we cannot assume that we have
      // actually shut down the worker we've enqueued sh to
      { // lifetime scope of guard
        std::unique_lock<std::mutex> guard(sh.mtx);
        sh.cv.wait(guard, [&] { return sh.last_worker != nullptr; });
      }
      alive_workers.erase(static_cast<worker_type*>(sh.last_worker));
      sh.last_worker = nullptr;
    }
    // shutdown utility actors
    stop_actors();
    // wait until all workers are done
    for (auto& w : workers_) {
      w->get_thread().join();
    }
    // run cleanup code for each resumable
    auto f = &abstract_coordinator::cleanup_and_release;
    for (auto& w : workers_)
      policy_.foreach_resumable(w.get(), f);
    policy_.foreach_central_resumable(this, f);
  }
Esempio n. 6
0
 resumable::resume_result resume(execution_unit* ptr, size_t) override {
   CAF_LOG_DEBUG("shutdown_helper::resume => shutdown worker");
   CAF_ASSERT(ptr != nullptr);
   std::unique_lock<std::mutex> guard(mtx);
   last_worker = ptr;
   cv.notify_all();
   return resumable::shutdown_execution_unit;
 }
Esempio n. 7
0
strong_actor_ptr actor_registry::get_impl(actor_id key) const {
  shared_guard guard(instances_mtx_);
  auto i = entries_.find(key);
  if (i != entries_.end())
    return i->second;
  CAF_LOG_DEBUG("key invalid, assume actor no longer exists:" << CAF_ARG(key));
  return nullptr;
}
Esempio n. 8
0
void actor_registry::dec_running() {
  size_t new_val = --running_;
  if (new_val <= 1) {
    std::unique_lock<std::mutex> guard(running_mtx_);
    running_cv_.notify_all();
  }
  CAF_LOG_DEBUG(CAF_ARG(new_val));
}
Esempio n. 9
0
void actor_registry::inc_running() {
# if CAF_LOG_LEVEL >= CAF_LOG_LEVEL_DEBUG
  auto value = ++running_;
  CAF_LOG_DEBUG(CAF_ARG(value));
# else
  ++running_;
# endif
}
 void delegate(T& x) {
   auto rp = self_->make_response_promise();
   if (! rp.pending()) {
     CAF_LOG_DEBUG("suppress response message: invalid response promise");
     return;
   }
   deliver(rp, x);
 }
Esempio n. 11
0
void actor_registry::await_running_count_equal(size_t expected) const {
  CAF_ASSERT(expected == 0 || expected == 1);
  CAF_LOG_TRACE(CAF_ARG(expected));
  std::unique_lock<std::mutex> guard{running_mtx_};
  while (running_ != expected) {
    CAF_LOG_DEBUG(CAF_ARG(running_.load()));
    running_cv_.wait(guard);
  }
}
Esempio n. 12
0
 void send_to_acquaintances(const message& what) {
   // send to all remote subscribers
   auto sender = current_sender();
   CAF_LOG_DEBUG("forward message to " << m_acquaintances.size()
                 << " acquaintances; " << CAF_TSARG(sender) << ", "
                 << CAF_TSARG(what));
   for (auto& acquaintance : m_acquaintances) {
     acquaintance->enqueue(sender, invalid_message_id, what, host());
   }
 }
void abstract_broker::servant::disconnect(bool invoke_disconnect_message) {
  CAF_LOG_TRACE("");
  if (! disconnected_) {
    CAF_LOG_DEBUG("disconnect servant from broker");
    disconnected_ = true;
    remove_from_broker();
    if (invoke_disconnect_message) {
      auto msg = disconnect_message();
      broker_->invoke_message(broker_->address(),invalid_message_id, msg);
    }
  }
}
Esempio n. 14
0
 void initialize() override {
   CAF_LOG_TRACE("");
   this->init_broker();
   auto bhvr = make_behavior();
   CAF_LOG_DEBUG_IF(!bhvr, "make_behavior() did not return a behavior:"
                            << CAF_ARG(this->has_behavior()));
   if (bhvr) {
     // make_behavior() did return a behavior instead of using become()
     CAF_LOG_DEBUG("make_behavior() did return a valid behavior");
     this->do_become(std::move(bhvr.unbox()), true);
   }
 }
Esempio n. 15
0
void event_based_actor::initialize() {
  is_initialized(true);
  auto bhvr = make_behavior();
  CAF_LOG_DEBUG_IF(!bhvr, "make_behavior() did not return a behavior, "
                          << "has_behavior() = "
                          << std::boolalpha << this->has_behavior());
  if (bhvr) {
    // make_behavior() did return a behavior instead of using become()
    CAF_LOG_DEBUG("make_behavior() did return a valid behavior");
    become(std::move(bhvr));
  }
}
 void initialize() override {
   CAF_LOG_TRACE("");
   super::initialize();
   this->setf(abstract_actor::is_initialized_flag);
   auto bhvr = make_behavior();
   CAF_LOG_DEBUG_IF(!bhvr, "make_behavior() did not return a behavior:"
                           << CAF_ARG2("alive", this->alive()));
   if (bhvr) {
     // make_behavior() did return a behavior instead of using become()
     CAF_LOG_DEBUG("make_behavior() did return a valid behavior");
     this->do_become(std::move(bhvr.unbox()), true);
   }
 }
 bool generate_messages() override {
   CAF_LOG_TRACE("");
   if (at_end_)
     return false;
   auto hint = this->out_.capacity();
   CAF_LOG_DEBUG(CAF_ARG(hint));
   if (hint == 0)
     return false;
   downstream<typename Driver::output_type> ds{this->out_.buf()};
   driver_.pull(ds, hint);
   if (driver_.done())
     at_end_ = true;
   return hint != this->out_.capacity();
 }
Esempio n. 18
0
void monitorable_actor::attach(attachable_ptr ptr) {
  CAF_LOG_TRACE("");
  CAF_ASSERT(ptr != nullptr);
  error fail_state;
  auto attached = exclusive_critical_section([&] {
    if (getf(is_terminated_flag)) {
      fail_state = fail_state_;
      return false;
    }
    attach_impl(ptr);
    return true;
  });
  CAF_LOG_DEBUG("cannot attach functor to terminated actor: call immediately");
  if (!attached)
    ptr->actor_exited(fail_state, nullptr);
}
Esempio n. 19
0
void basp_broker_state::purge_state(const node_id& nid) {
  CAF_LOG_TRACE(CAF_ARG(nid));
  auto hdl = instance.tbl().lookup_direct(nid);
  if (hdl == invalid_connection_handle)
    return;
  auto i = ctx.find(hdl);
  if (i != ctx.end()) {
    auto& ref = i->second;
    if (ref.callback) {
      CAF_LOG_DEBUG("connection closed during handshake");
      ref.callback->deliver(sec::disconnect_during_handshake);
    }
    ctx.erase(i);
  }
  proxies().erase(nid);
}
Esempio n. 20
0
void abstract_actor::attach(attachable_ptr ptr) {
  CAF_LOG_TRACE("");
  if (ptr == nullptr) {
    return;
  }
  uint32_t reason;
  { // lifetime scope of guard
    guard_type guard{mtx_};
    reason = exit_reason_;
    if (reason == exit_reason::not_exited) {
      attach_impl(ptr);
      return;
    }
  }
  CAF_LOG_DEBUG("cannot attach functor to terminated actor: call immediately");
  ptr->actor_exited(this, reason);
}
error load_actor(strong_actor_ptr& storage, execution_unit* ctx,
                 actor_id aid, const node_id& nid) {
  if (!ctx)
    return sec::no_context;
  auto& sys = ctx->system();
  if (sys.node() == nid) {
    storage = sys.registry().get(aid);
    CAF_LOG_DEBUG("fetch actor handle from local actor registry: "
                  << (storage ? "found" : "not found"));
    return none;
  }
  auto prp = ctx->proxy_registry_ptr();
  if (!prp)
    return sec::no_proxy_registry;
  // deal with (proxies for) remote actors
  storage = prp->get_or_put(nid, aid);
  return none;
}
Esempio n. 22
0
void basp_broker_state::proxy_announced(const node_id& nid, actor_id aid) {
  CAF_LOG_TRACE(CAF_ARG(nid) << CAF_ARG(aid));
  // source node has created a proxy for one of our actors
  auto entry = system().registry().get(aid);
  auto send_kill_proxy_instance = [=](error rsn) {
    if (!rsn)
      rsn = exit_reason::unknown;
    auto path = instance.tbl().lookup(nid);
    if (!path) {
      CAF_LOG_INFO("cannot send exit message for proxy, no route to host:"
                   << CAF_ARG(nid));
      return;
    }
    instance.write_kill_proxy(self->context(), path->wr_buf,
                                       nid, aid, rsn);
    instance.tbl().flush(*path);
  };
  auto ptr = actor_cast<strong_actor_ptr>(entry);
  if (!ptr) {
    CAF_LOG_DEBUG("kill proxy immediately");
    // kill immediately if actor has already terminated
    send_kill_proxy_instance(exit_reason::unknown);
  } else {
    strong_actor_ptr tmp{self->ctrl()};
    auto mm = &system().middleman();
    ptr->get()->attach_functor([=](const error& fail_state) {
      mm->backend().dispatch([=] {
        CAF_LOG_TRACE(CAF_ARG(fail_state));
        auto bptr = static_cast<basp_broker*>(tmp->get());
        // ... to make sure this is safe
        if (bptr == mm->named_broker<basp_broker>(atom("BASP"))
            && !bptr->getf(abstract_actor::is_terminated_flag))
          send_kill_proxy_instance(fail_state);
      });
    });
  }
}
Esempio n. 23
0
 void run() {
   CAF_SET_LOGGER_SYS(&system());
   CAF_LOG_TRACE(CAF_ARG(id_));
   // scheduling loop
   for (;;) {
     auto job = policy_.dequeue(this);
     CAF_ASSERT(job != nullptr);
     CAF_ASSERT(job->subtype() != resumable::io_actor);
     CAF_LOG_DEBUG("resume actor:" << CAF_ARG(id_of(job)));
     CAF_PUSH_AID_FROM_PTR(dynamic_cast<abstract_actor*>(job));
     policy_.before_resume(this, job);
     auto res = job->resume(this, max_throughput_);
     policy_.after_resume(this, job);
     switch (res) {
       case resumable::resume_later: {
         // keep reference to this actor, as it remains in the "loop"
         policy_.resume_job_later(this, job);
         break;
       }
       case resumable::done: {
         policy_.after_completion(this, job);
         intrusive_ptr_release(job);
         break;
       }
       case resumable::awaiting_message: {
         // resumable will maybe be enqueued again later, deref it for now
         intrusive_ptr_release(job);
         break;
       }
       case resumable::shutdown_execution_unit: {
         policy_.after_completion(this, job);
         policy_.before_shutdown(this);
         return;
       }
     }
   }
 }
Esempio n. 24
0
 void run() {
   CAF_LOG_TRACE("worker with ID " << m_id);
   // scheduling loop
   for (;;) {
     auto job = m_queue_policy.internal_dequeue(this);
     CAF_REQUIRE(job != nullptr);
     CAF_LOG_DEBUG("resume actor " << id_of(job));
     CAF_PUSH_AID_FROM_PTR(dynamic_cast<abstract_actor*>(job));
     switch (job->resume(this)) {
       case resumable::done: {
         job->detach_from_scheduler();
         break;
       }
       case resumable::resume_later: {
         break;
       }
       case resumable::shutdown_execution_unit: {
         m_queue_policy.clear_internal_queue(this);
         return;
       }
     }
     m_queue_policy.assert_stealable(this);
   }
 }
Esempio n. 25
0
size_t monitorable_actor::detach_impl(const attachable::token& what,
                                      bool stop_on_hit, bool dry_run) {
  CAF_LOG_TRACE(CAF_ARG(stop_on_hit) << CAF_ARG(dry_run));
  size_t count = 0;
  auto i = &attachables_head_;
  while (*i != nullptr) {
    if ((*i)->matches(what)) {
      ++count;
      if (!dry_run) {
        CAF_LOG_DEBUG("removed element");
        attachable_ptr next;
        next.swap((*i)->next);
        (*i).swap(next);
      } else {
        i = &((*i)->next);
      }
      if (stop_on_hit)
        return count;
    } else {
      i = &((*i)->next);
    }
  }
  return count;
}
 resumable::resume_result resume(execution_unit* new_host,
                                 size_t max_throughput) override {
   CAF_REQUIRE(max_throughput > 0);
   auto d = static_cast<Derived*>(this);
   CAF_LOG_TRACE("id = " << d->id());
   d->host(new_host);
   auto done_cb = [&]() -> bool {
     CAF_LOG_TRACE("");
     d->bhvr_stack().clear();
     d->bhvr_stack().cleanup();
     d->on_exit();
     if (!d->bhvr_stack().empty()) {
       CAF_LOG_DEBUG("on_exit did set a new behavior");
       d->planned_exit_reason(exit_reason::not_exited);
       return false; // on_exit did set a new behavior
     }
     auto rsn = d->planned_exit_reason();
     if (rsn == exit_reason::not_exited) {
       rsn = exit_reason::normal;
       d->planned_exit_reason(rsn);
     }
     d->cleanup(rsn);
     return true;
   };
   auto actor_done = [&]() -> bool {
     if (d->bhvr_stack().empty()
         || d->planned_exit_reason() != exit_reason::not_exited) {
       return done_cb();
     }
     return false;
   };
   // actors without behavior or that have already defined
   // an exit reason must not be resumed
   CAF_REQUIRE(!d->is_initialized()
               || (!d->bhvr_stack().empty()
                   && d->planned_exit_reason() == exit_reason::not_exited));
   std::exception_ptr eptr = nullptr;
   try {
     if (!d->is_initialized()) {
       CAF_LOG_DEBUG("initialize actor");
       d->is_initialized(true);
       auto bhvr = d->make_behavior();
       CAF_LOG_DEBUG_IF(!bhvr, "make_behavior() did not return a behavior, "
                               << "bhvr_stack().empty() = "
                               << std::boolalpha << d->bhvr_stack().empty());
       if (bhvr) {
         // make_behavior() did return a behavior instead of using become()
         CAF_LOG_DEBUG("make_behavior() did return a valid behavior");
         d->become(std::move(bhvr));
       }
       if (actor_done()) {
         CAF_LOG_DEBUG("actor_done() returned true right "
                       << "after make_behavior()");
         return resume_result::done;
       }
     }
     // max_throughput = 0 means infinite
     for (size_t i = 0; i < max_throughput; ++i) {
       auto ptr = d->next_message();
       if (ptr) {
         if (d->invoke_message(ptr)) {
           if (actor_done()) {
             CAF_LOG_DEBUG("actor exited");
             return resume_result::done;
           }
           // continue from cache if current message was
           // handled, because the actor might have changed
           // its behavior to match 'old' messages now
           while (d->invoke_message_from_cache()) {
             if (actor_done()) {
               CAF_LOG_DEBUG("actor exited");
               return resume_result::done;
             }
           }
         }
         // add ptr to cache if invoke_message
         // did not reset it (i.e. skipped, but not dropped)
         if (ptr) {
           CAF_LOG_DEBUG("add message to cache");
           d->push_to_cache(std::move(ptr));
         }
       } else {
         CAF_LOG_DEBUG("no more element in mailbox; going to block");
         if (d->mailbox().try_block()) {
           return resumable::awaiting_message;
         }
         CAF_LOG_DEBUG("try_block() interrupted by new message");
       }
     }
     if (!d->has_next_message() && d->mailbox().try_block()) {
       return resumable::awaiting_message;
     }
     // time's up
     return resumable::resume_later;
   }
   catch (actor_exited& what) {
     CAF_LOG_INFO("actor died because of exception: actor_exited, "
                  "reason = " << what.reason());
     if (d->exit_reason() == exit_reason::not_exited) {
       d->quit(what.reason());
     }
   }
   catch (std::exception& e) {
     CAF_LOG_INFO("actor died because of an exception: "
                  << detail::demangle(typeid(e))
                  << ", what() = " << e.what());
     if (d->exit_reason() == exit_reason::not_exited) {
       d->quit(exit_reason::unhandled_exception);
     }
     eptr = std::current_exception();
   }
   catch (...) {
     CAF_LOG_INFO("actor died because of an unknown exception");
     if (d->exit_reason() == exit_reason::not_exited) {
       d->quit(exit_reason::unhandled_exception);
     }
     eptr = std::current_exception();
   }
   if (eptr) {
     auto opt_reason = d->handle(eptr);
     if (opt_reason) {
       // use exit reason defined by custom handler
       d->planned_exit_reason(*opt_reason);
     }
   }
   if (!actor_done()) {
     // actor has been "revived", try running it again later
     return resumable::resume_later;
   }
   return resumable::done;
 }
Esempio n. 27
0
  optional<message> invoke_fun(Actor* self, message& msg, message_id& mid,
                               Fun& fun,
                               MaybeResponseHdl hdl = MaybeResponseHdl{}) {
#   ifdef CAF_LOG_LEVEL
      auto msg_str = to_string(msg);
#   endif
    CAF_LOG_TRACE(CAF_MARG(mid, integer_value) << ", msg = " << msg_str);
    auto res = fun(msg); // might change mid
    CAF_LOG_DEBUG_IF(res, "actor did consume message: " << msg_str);
    CAF_LOG_DEBUG_IF(!res, "actor did ignore message: " << msg_str);
    if (!res) {
      return none;
    }
    if (res->empty()) {
      // make sure synchronous requests
      // always receive a response
      if (mid.is_request() && !mid.is_answered()) {
        CAF_LOG_WARNING("actor with ID " << self->id()
                        << " did not reply to a synchronous request message");
        auto fhdl = fetch_response_promise(self, hdl);
        if (fhdl) {
          fhdl.deliver(make_message(unit));
        }
      }
    } else {
      CAF_LOGF_DEBUG("res = " << to_string(*res));
      if (res->template has_types<atom_value, uint64_t>()
          && res->template get_as<atom_value>(0) == atom("MESSAGE_ID")) {
        CAF_LOG_DEBUG("message handler returned a message id wrapper");
        auto id = res->template get_as<uint64_t>(1);
        auto msg_id = message_id::from_integer_value(id);
        auto ref_opt = self->sync_handler(msg_id);
        // calls self->response_promise() if hdl is a dummy
        // argument, forwards hdl otherwise to reply to the
        // original request message
        auto fhdl = fetch_response_promise(self, hdl);
        if (ref_opt) {
          behavior cpy = *ref_opt;
          *ref_opt =
            cpy.add_continuation([=](message & intermediate)
                         ->optional<message> {
              if (!intermediate.empty()) {
                // do no use lamba expresion type to
                // avoid recursive template instantiaton
                behavior::continuation_fun f2 = [=](
                  message & m)->optional<message> {
                  return std::move(m);

                };
                auto mutable_mid = mid;
                // recursively call invoke_fun on the
                // result to correctly handle stuff like
                // sync_send(...).then(...).then(...)...
                return this->invoke_fun(self, intermediate,
                             mutable_mid, f2, fhdl);
              }
              return none;
            });
        }
        // reset res to prevent "outer" invoke_fun
        // from handling the result again
        res->reset();
      } else {
        // respond by using the result of 'fun'
        CAF_LOG_DEBUG("respond via response_promise");
        auto fhdl = fetch_response_promise(self, hdl);
        if (fhdl) {
          fhdl.deliver(std::move(*res));
          // inform caller about success
          return message{};
        }
      }
    }
    return res;
  }
 void deliver(response_promise& rp, error& x) {
   CAF_LOG_DEBUG("report error back to requesting actor");
   rp.deliver(std::move(x));
 }
Esempio n. 29
0
 handle_message_result handle_message(Actor* self, mailbox_element* node,
                                      Fun& fun, message_id awaited_response) {
   bool handle_sync_failure_on_mismatch = true;
   if (dptr()->hm_should_skip(node)) {
     return hm_skip_msg;
   }
   switch (this->filter_msg(self, node)) {
     case msg_type::normal_exit:
       CAF_LOG_DEBUG("dropped normal exit signal");
       return hm_drop_msg;
     case msg_type::expired_sync_response:
       CAF_LOG_DEBUG("dropped expired sync response");
       return hm_drop_msg;
     case msg_type::expired_timeout:
       CAF_LOG_DEBUG("dropped expired timeout message");
       return hm_drop_msg;
     case msg_type::inactive_timeout:
       CAF_LOG_DEBUG("skipped inactive timeout message");
       return hm_skip_msg;
     case msg_type::non_normal_exit:
       CAF_LOG_DEBUG("handled non-normal exit signal");
       // this message was handled
       // by calling self->quit(...)
       return hm_msg_handled;
     case msg_type::timeout: {
       CAF_LOG_DEBUG("handle timeout message");
       auto& tm = node->msg.get_as<timeout_msg>(0);
       self->handle_timeout(fun, tm.timeout_id);
       if (awaited_response.valid()) {
         self->mark_arrived(awaited_response);
         self->remove_handler(awaited_response);
       }
       return hm_msg_handled;
     }
     case msg_type::timeout_response:
       handle_sync_failure_on_mismatch = false;
       CAF_ANNOTATE_FALLTHROUGH;
     case msg_type::sync_response:
       CAF_LOG_DEBUG("handle as synchronous response: "
                << CAF_TARG(node->msg, to_string) << ", "
                << CAF_MARG(node->mid, integer_value) << ", "
                << CAF_MARG(awaited_response, integer_value));
       if (awaited_response.valid() && node->mid == awaited_response) {
         auto previous_node = dptr()->hm_begin(self, node);
         auto res = invoke_fun(self, node->msg, node->mid, fun);
         if (!res && handle_sync_failure_on_mismatch) {
           CAF_LOG_WARNING("sync failure occured in actor "
                    << "with ID " << self->id());
           self->handle_sync_failure();
         }
         self->mark_arrived(awaited_response);
         self->remove_handler(awaited_response);
         dptr()->hm_cleanup(self, previous_node);
         return hm_msg_handled;
       }
       return hm_cache_msg;
     case msg_type::ordinary:
       if (!awaited_response.valid()) {
         auto previous_node = dptr()->hm_begin(self, node);
         auto res = invoke_fun(self, node->msg, node->mid, fun);
         if (res) {
           dptr()->hm_cleanup(self, previous_node);
           return hm_msg_handled;
         }
         // no match (restore self members)
         dptr()->hm_revert(self, previous_node);
       }
       CAF_LOG_DEBUG_IF(awaited_response.valid(),
                 "ignored message; await response: "
                   << awaited_response.integer_value());
       return hm_cache_msg;
   }
   // should be unreachable
   CAF_CRITICAL("invalid message type");
 }
Esempio n. 30
0
void opencl_metainfo::initialize() {
  // get number of available platforms
  auto num_platforms = v1get<cl_uint>(CAF_CLF(clGetPlatformIDs));
  // get platform ids
  std::vector<cl_platform_id> platforms(num_platforms);
  v2callcl(CAF_CLF(clGetPlatformIDs), num_platforms, platforms.data());
  if (platforms.empty()) {
    throw std::runtime_error("no OpenCL platform found");
  }
  // support multiple platforms -> "for (auto platform : platforms)"?
  auto platform = platforms.front();
  // detect how many devices we got
  cl_uint num_devs = 0;
  cl_device_type dev_type = CL_DEVICE_TYPE_GPU;
  // try get some GPU devices and try falling back to CPU devices on error
  try {
    num_devs = v1get<cl_uint>(CAF_CLF(clGetDeviceIDs), platform, dev_type);
  }
  catch (std::runtime_error&) {
    dev_type = CL_DEVICE_TYPE_CPU;
    num_devs = v1get<cl_uint>(CAF_CLF(clGetDeviceIDs), platform, dev_type);
  }
  // get available devices
  std::vector<cl_device_id> ds(num_devs);
  v2callcl(CAF_CLF(clGetDeviceIDs), platform, dev_type, num_devs, ds.data());
  std::vector<device_ptr> devices(num_devs);
  // lift raw pointer as returned by OpenCL to C++ smart pointers
  auto lift = [](cl_device_id ptr) { return device_ptr{ptr, false}; };
  std::transform(ds.begin(), ds.end(), devices.begin(), lift);
  // create a context
  context_.reset(v2get(CAF_CLF(clCreateContext), nullptr, num_devs, ds.data(),
                        pfn_notify, nullptr),
                  false);
  for (auto& device : devices) {
    CAF_LOG_DEBUG("creating command queue for device(s)");
    command_queue_ptr cmd_queue;
    try {
      cmd_queue.reset(v2get(CAF_CLF(clCreateCommandQueue),
                            context_.get(), device.get(),
                            unsigned{CL_QUEUE_PROFILING_ENABLE}),
                      false);
    }
    catch (std::runtime_error&) {
      CAF_LOG_DEBUG("unable to create command queue for device");
    }
    if (cmd_queue) {
      auto max_wgs = v3get<size_t>(CAF_CLF(clGetDeviceInfo), device.get(),
                      unsigned{CL_DEVICE_MAX_WORK_GROUP_SIZE});
      auto max_wid = v3get<cl_uint>(CAF_CLF(clGetDeviceInfo), device.get(),
                      unsigned{CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS});
      dim_vec max_wi_per_dim(max_wid);
      v2callcl(CAF_CLF(clGetDeviceInfo), device.get(),
             unsigned{CL_DEVICE_MAX_WORK_ITEM_SIZES},
             sizeof(size_t) * max_wid,
             max_wi_per_dim.data());
      devices_.push_back(device_info{std::move(device), std::move(cmd_queue),
                                      max_wgs, max_wid, max_wi_per_dim});
    }
  }
  if (devices_.empty()) {
    std::string errstr = "could not create a command queue for any device";
    CAF_LOG_ERROR(errstr);
    throw std::runtime_error(std::move(errstr));
  }
}