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; }
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; }
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)); }
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); }
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; }
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; }
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)); }
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); }
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); } }
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); } } }
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); } }
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(); }
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); }
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); }
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; }
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); }); }); } }
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; } } } }
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); } }
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; }
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)); }
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"); }
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)); } }