// The original parcel-sent handler is wrapped to keep the parcel alive // until after the data has been reliably sent (which is needed for zero // copy serialization). void parcel_sent_handler(parcelset::parcelhandler& ph, boost::system::error_code const& ec, parcelset::parcel const& p) { // invoke the original handler ph.invoke_write_handler(ec, p); // inform termination detection of a sent message if (!p.does_termination_detection()) hpx::detail::dijkstra_make_black(); }
// schedule threads based on given parcel void applier::schedule_action(parcelset::parcel const& p) { // decode the action-type in the parcel actions::continuation_type cont = p.get_continuation(); actions::action_type act = p.get_action(); #if defined(HPX_HAVE_SECURITY) // we look up the certificate of the originating locality, no matter // whether this parcel was routed through another locality or not boost::uint32_t locality_id = naming::get_locality_id_from_gid(p.get_parcel_id()); error_code ec(lightweight); components::security::signed_certificate const& cert = get_locality_certificate(locality_id, ec); if (verify_capabilities_ && ec) { // we should have received the sender's certificate by now HPX_THROW_EXCEPTION(security_error, "applier::schedule_action", boost::str(boost::format("couldn't extract sender's " "certificate (sender locality id: %1%)") % locality_id)); return; } components::security::capability caps_sender; if (verify_capabilities_) caps_sender = cert.get_type().get_capability(); #endif int comptype = act->get_component_type(); naming::locality dest = p.get_destination_locality(); // fetch the set of destinations std::size_t size = p.size(); naming::id_type const* ids = p.get_destinations(); naming::address const* addrs = p.get_destination_addrs(); // if the parcel carries a continuation it should be directed to a // single destination HPX_ASSERT(!cont || size == 1); // schedule a thread for each of the destinations for (std::size_t i = 0; i != size; ++i) { naming::address const& addr = addrs[i]; // make sure this parcel destination matches the proper locality HPX_ASSERT(dest == addr.locality_); // decode the local virtual address of the parcel naming::address::address_type lva = addr.address_; // by convention, a zero address references the local runtime // support component if (0 == lva) { lva = get_runtime_support_raw_gid().get_lsb(); } else if (comptype == components::component_memory) { HPX_ASSERT(naming::refers_to_virtual_memory(ids[i].get_gid())); lva = get_memory_raw_gid().get_lsb(); } #if defined(HPX_HAVE_SECURITY) if (verify_capabilities_) { components::security::capability caps_action = act->get_required_capabilities(lva); if (caps_action.verify(caps_sender) == false) { HPX_THROW_EXCEPTION(security_error, "applier::schedule_action", boost::str(boost::format("sender has insufficient capabilities " "to execute the action (%1%, sender: %2%, action %3%)") % act->get_action_name() % caps_sender % caps_action)); return; } } #endif // make sure the component_type of the action matches the // component type in the destination address if (HPX_UNLIKELY(!components::types_are_compatible( addr.type_, comptype))) { hpx::util::osstream strm; strm << " types are not compatible: destination_type(" << addr.type_ << ") action_type(" << comptype << ") parcel (" << p << ")"; HPX_THROW_EXCEPTION(bad_component_type, "action_manager::fetch_parcel", hpx::util::osstream_get_string(strm)); } // dispatch action, register work item either with or without // continuation support if (!cont) { // No continuation is to be executed, register the plain // action and the local-virtual address. act->schedule_thread(ids[i], lva, threads::pending); } else { // This parcel carries a continuation, register a wrapper // which first executes the original thread function as // required by the action and triggers the continuations // afterwards. act->schedule_thread(cont, ids[i], lva, threads::pending); } } }
// schedule threads based on given parcel void applier::schedule_action(parcelset::parcel p, std::size_t num_thread) { // fetch the set of destinations #if !defined(HPX_SUPPORT_MULTIPLE_PARCEL_DESTINATIONS) std::size_t const size = 1ul; #else std::size_t const size = p.size(); #endif naming::id_type const* ids = p.destinations(); naming::address const* addrs = p.addrs(); // decode the action-type in the parcel std::unique_ptr<actions::continuation> cont = p.get_continuation(); actions::base_action * act = p.get_action(); #if defined(HPX_HAVE_SECURITY) // we look up the certificate of the originating locality, no matter // whether this parcel was routed through another locality or not boost::uint32_t locality_id = naming::get_locality_id_from_gid(p.get_parcel_id()); error_code ec(lightweight); components::security::signed_certificate const& cert = get_locality_certificate(locality_id, ec); if (verify_capabilities_ && ec) { // we should have received the sender's certificate by now HPX_THROW_EXCEPTION(security_error, "applier::schedule_action", boost::str(boost::format("couldn't extract sender's " "certificate (sender locality id: %1%)") % locality_id)); return; } components::security::capability caps_sender; if (verify_capabilities_) caps_sender = cert.get_type().get_capability(); #endif int comptype = act->get_component_type(); naming::gid_type dest = p.destination_locality(); // if the parcel carries a continuation it should be directed to a // single destination HPX_ASSERT(!cont || size == 1); naming::resolver_client& client = hpx::naming::get_agas_client(); // schedule a thread for each of the destinations for (std::size_t i = 0; i != size; ++i) { naming::address const& addr = addrs[i]; // make sure this parcel destination matches the proper locality HPX_ASSERT(dest == addr.locality_); // decode the local virtual address of the parcel naming::address::address_type lva = addr.address_; // by convention, a zero address references either the local // runtime support component or one of the AGAS components if (0 == lva) { switch(comptype) { case components::component_runtime_support: lva = get_runtime_support_raw_gid().get_lsb(); break; case components::component_agas_primary_namespace: lva = get_agas_client().get_primary_ns_lva(); break; case components::component_agas_symbol_namespace: lva = get_agas_client().get_symbol_ns_lva(); break; case components::component_plain_function: break; default: HPX_ASSERT(false); } } else if (comptype == components::component_memory) { HPX_ASSERT(naming::refers_to_virtual_memory(ids[i].get_gid())); lva = get_memory_raw_gid().get_lsb(); } // make sure the target has not been migrated away auto r = act->was_object_migrated(ids[i], lva); if (r.first) { #if defined(HPX_SUPPORT_MULTIPLE_PARCEL_DESTINATIONS) // it's unclear at this point what could be done if there is // more than one destination HPX_ASSERT(size == 1); #endif // set continuation in outgoing parcel if (cont) p.set_continuation(std::move(cont)); // route parcel to new locality of target client.route( std::move(p), util::bind(&detail::parcel_sent_handler, boost::ref(parcel_handler_), util::placeholders::_1, util::placeholders::_2), threads::thread_priority_normal); break; } #if defined(HPX_HAVE_SECURITY) if (verify_capabilities_) { components::security::capability caps_action = act->get_required_capabilities(lva); if (caps_action.verify(caps_sender) == false) { HPX_THROW_EXCEPTION(security_error, "applier::schedule_action", boost::str(boost::format("sender has insufficient capabilities " "to execute the action (%1%, sender: %2%, action %3%)") % act->get_action_name() % caps_sender % caps_action)); return; } } #endif // make sure the component_type of the action matches the // component type in the destination address if (HPX_UNLIKELY(!components::types_are_compatible( addr.type_, comptype))) { std::ostringstream strm; strm << " types are not compatible: destination_type(" << addr.type_ << ") action_type(" << comptype << ") parcel (" << p << ")"; HPX_THROW_EXCEPTION(bad_component_type, "applier::schedule_action", strm.str()); } // dispatch action, register work item either with or without // continuation support if (!cont) { // No continuation is to be executed, register the plain // action and the local-virtual address. act->schedule_thread(ids[i], lva, threads::pending, num_thread); } else { // This parcel carries a continuation, register a wrapper // which first executes the original thread function as // required by the action and triggers the continuations // afterwards. act->schedule_thread(std::move(cont), ids[i], lva, threads::pending, num_thread); } } }