// depending on whether the main executable defines this symbol or not. int hpx_startup::user_main() { // hpx::util::section const& ini = hpx::get_runtime().get_config(); // std::string cmdline(ini.get_entry("hpx.reconstructed_cmd_line", "")); // // using namespace boost::program_options; // #if defined(BOOST_WINDOWS) // std::vector<std::string> args = split_winmain(cmdline); // #else // std::vector<std::string> args = split_unix(cmdline); // #endif // // // Copy all arguments which are not hpx related to a temporary array // boost::scoped_array<char*> argv(new char*[args.size()]); // std::size_t argcount = 0; // for(std::size_t i = 0; i < args.size(); ++i) // { // if (0 != args[i].find("--hpx:")) // argv[argcount++] = const_cast<char*>(args[i].data()); // } // // // Invoke hpx_main // return user_main(static_cast<int>(argcount), argv.get()); HPX_THROW_EXCEPTION(hpx::not_implemented, "The console locality does not implement any main entry point usable " "as the main HPX thread (e.g. no hpx_main, hpx_startup::user_main, etc.)", "hpx_startup::user_main") }
virtual counter_value get_counter_value(bool /*reset*/) override { HPX_THROW_EXCEPTION(invalid_status, "get_counter_value", "get_counter_value is not implemented for this counter"); return counter_value(); }
binpacking_factory::remote_result_type binpacking_factory::create_components(components::component_type type, std::size_t count) const { // make sure we get localities for derived component type, if any components::component_type prefix_type = type; if (type != components::get_base_type(type)) prefix_type = components::get_derived_type(type); // get list of locality prefixes std::vector<naming::id_type> localities = hpx::find_all_localities(prefix_type); if (localities.empty()) { HPX_THROW_EXCEPTION(bad_component_type, "binpacking_factory::create_components_binpacked", "attempt to create component instance of unknown type: " + components::get_component_type_name(type)); } if (count == std::size_t(-1)) count = localities.size(); // retrieve the current number of instances of the given component std::vector<lcos::future<boost::int32_t> > lazy_counts; for (naming::id_type const& id : localities) { lazy_counts.push_back( stubs::runtime_support::get_instance_count_async(id, type)); } // wait for counts to get back, collect statistics long maxcount = 0; long existing = 0; std::vector<long> counts; counts.reserve(lazy_counts.size()); for (lcos::future<boost::int32_t>& f : lazy_counts) { counts.push_back(f.get()); maxcount = (std::max)(maxcount, counts.back()); existing += counts.back(); } // distribute the number of components to create in a way, so that the // overall number of component instances on all localities is // approximately the same HPX_ASSERT(std::size_t(maxcount) * counts.size() >= std::size_t(existing)); std::size_t missing = std::size_t(maxcount) * counts.size() - std::size_t(existing); if (missing == 0) missing = 1; double hole_ratio = (std::min)(count, missing) / double(missing); HPX_ASSERT(hole_ratio <= 1.); std::size_t overflow_count = (count > missing) ? (count - missing) / counts.size() : 0; std::size_t excess = count - overflow_count * counts.size(); typedef std::vector<lazy_result> future_values_type; typedef server::runtime_support::bulk_create_components_action action_type; std::size_t created_count = 0; future_values_type v; // start an asynchronous operation for each of the localities for (std::size_t i = 0; i < counts.size(); ++i) { std::size_t numcreate = std::size_t((maxcount - counts[i]) * hole_ratio) + overflow_count; if (excess != 0) { --excess; ++numcreate; } if (i == counts.size()-1) { // last bin gets all the rest if (created_count + numcreate < count) numcreate = count - created_count; } if (created_count + numcreate > count) numcreate = count - created_count; if (numcreate == 0) break; // create one component at a time v.push_back(future_values_type::value_type(localities[i].get_gid())); lcos::packaged_action<action_type, std::vector<naming::gid_type> > p; p.apply(launch::async, localities[i], type, numcreate); v.back().gids_ = p.get_future(); created_count += numcreate; if (created_count >= count) break; } // now wait for the results remote_result_type results; for (lazy_result& lr : v) { results.push_back(remote_result_type::value_type(lr.locality_, type)); results.back().gids_ = std::move(lr.gids_.get()); } return results; }
hwloc_topology::hwloc_topology() : topo(0), machine_affinity_mask_(0) { // {{{ int err = hwloc_topology_init(&topo); if (err != 0) { HPX_THROW_EXCEPTION(no_success, "hwloc_topology::hwloc_topology", "Failed to init hwloc topology"); } err = hwloc_topology_load(topo); if (err != 0) { HPX_THROW_EXCEPTION(no_success, "hwloc_topology::hwloc_topology", "Failed to load hwloc topology"); } init_num_of_pus(); socket_numbers_.reserve(num_of_pus_); numa_node_numbers_.reserve(num_of_pus_); core_numbers_.reserve(num_of_pus_); // Initialize each set of data entirely, as some of the initialization // routines rely on access to other pieces of topology data. The // compiler will optimize the loops where possible anyways. std::size_t num_of_sockets = hwloc_get_nbobjs_by_type(topo, HWLOC_OBJ_SOCKET); if (num_of_sockets == 0) num_of_sockets = 1; for (std::size_t i = 0; i < num_of_pus_; ++i) { std::size_t socket = init_socket_number(i); BOOST_ASSERT(socket < num_of_sockets); socket_numbers_.push_back(socket); } std::size_t num_of_nodes = hwloc_get_nbobjs_by_type(topo, HWLOC_OBJ_NODE); if (num_of_nodes == 0) num_of_nodes = 1; for (std::size_t i = 0; i < num_of_pus_; ++i) { std::size_t numa_node = init_numa_node_number(i); BOOST_ASSERT(numa_node < num_of_nodes); numa_node_numbers_.push_back(numa_node); } std::size_t num_of_cores = hwloc_get_nbobjs_by_type(topo, HWLOC_OBJ_CORE); if (num_of_cores == 0) num_of_cores = 1; for (std::size_t i = 0; i < num_of_pus_; ++i) { std::size_t core_number = init_core_number(i); BOOST_ASSERT(core_number < num_of_cores); core_numbers_.push_back(core_number); } machine_affinity_mask_ = init_machine_affinity_mask(); socket_affinity_masks_.reserve(num_of_pus_); numa_node_affinity_masks_.reserve(num_of_pus_); core_affinity_masks_.reserve(num_of_pus_); thread_affinity_masks_.reserve(num_of_pus_); for (std::size_t i = 0; i < num_of_pus_; ++i) { socket_affinity_masks_.push_back(init_socket_affinity_mask(i)); } for (std::size_t i = 0; i < num_of_pus_; ++i) { numa_node_affinity_masks_.push_back(init_numa_node_affinity_mask(i)); } for (std::size_t i = 0; i < num_of_pus_; ++i) { core_affinity_masks_.push_back(init_core_affinity_mask(i)); } for (std::size_t i = 0; i < num_of_pus_; ++i) { thread_affinity_masks_.push_back(init_thread_affinity_mask(i)); } } // }}}
// operations void* alloc(std::size_t count = 1) { unique_lock_type guard(mtx_); if (HPX_UNLIKELY(0 == count)) { HPX_THROW_EXCEPTION(bad_parameter, name() + "::alloc", "cannot allocate 0 objects"); } //std::size_t size = 0; value_type* p = NULL; { if (!heap_list_.empty()) { //size = heap_list_.size(); for (iterator it = heap_list_.begin(); it != heap_list_.end(); ++it) { typename list_type::value_type heap = *it; bool allocated = false; { util::scoped_unlock<unique_lock_type> ul(guard); allocated = heap->alloc(&p, count); } if (allocated) { #if defined(HPX_DEBUG) // Allocation succeeded, update statistics. alloc_count_ += count; if (alloc_count_ - free_count_ > max_alloc_count_) max_alloc_count_ = alloc_count_- free_count_; #endif return p; } #if defined(HPX_DEBUG) LOSH_(info) << (boost::format( "%1%::alloc: failed to allocate from heap[%2%] " "(heap[%2%] has allocated %3% objects and has " "space for %4% more objects)") % name() % (*it)->heap_count_ % (*it)->size() % (*it)->free_size()); #endif } } } // Create new heap. bool did_create = false; { #if defined(HPX_DEBUG) heap_list_.push_front(typename list_type::value_type( new heap_type(class_name_.c_str(), heap_count_ + 1, heap_step))); #else heap_list_.push_front(typename list_type::value_type( new heap_type(class_name_.c_str(), 0, heap_step))); #endif iterator itnew = heap_list_.begin(); typename list_type::value_type heap = *itnew; bool result = false; { util::scoped_unlock<unique_lock_type> ul(guard); result = heap->alloc(&p, count); } if (HPX_UNLIKELY(!result || NULL == p)) { // out of memory HPX_THROW_EXCEPTION(out_of_memory, name() + "::alloc", boost::str(boost::format( "new heap failed to allocate %1% objects") % count)); } #if defined(HPX_DEBUG) alloc_count_ += count; ++heap_count_; LOSH_(info) << (boost::format( "%1%::alloc: creating new heap[%2%], size is now %3%") % name() % heap_count_ % heap_list_.size()); #endif did_create = true; } if (did_create) return p; guard.unlock(); // Try again, we just got a new heap, so we should be good. return alloc(count); }
virtual void set_counter_value(counter_value const& /*value*/) { HPX_THROW_EXCEPTION(invalid_status, "set_counter_value", "set_counter_value is not implemented for this counter"); }
// operations value_type* alloc(std::size_t count = 1) { if (HPX_UNLIKELY(0 == count)) { HPX_THROW_EXCEPTION(bad_parameter, name() + "::alloc", "cannot allocate 0 objects"); } std::size_t size = 0; value_type* p = NULL; { shared_lock_type guard(mtx_); size = heap_list_.size(); if (size) { for (iterator it = heap_list_.begin(); it != heap_list_.end(); ++it) { if ((*it)->alloc(&p, count)) { // Allocation succeeded, update statistics. alloc_count_ += count; if (alloc_count_ - free_count_ > max_alloc_count_) max_alloc_count_ = alloc_count_- free_count_; return p; } LOSH_(info) << (boost::format( "%1%::alloc: failed to allocate from heap[%2%] " "(heap[%2%] has allocated %3% objects and has " "space for %4% more objects)") % name() % (*it)->heap_count_ % (*it)->size() % (*it)->free_size()); } } } // Create new heap. bool did_create = false; { // Acquire exclusive access. unique_lock_type ul(mtx_); iterator itnew = heap_list_.insert(heap_list_.begin(), typename list_type::value_type(new heap_type (class_name_.c_str(), heap_count_ + 1, heap_step))); if (HPX_UNLIKELY(itnew == heap_list_.end())) { HPX_THROW_EXCEPTION(out_of_memory, name() + "::alloc", "new heap could not be added"); } bool result = (*itnew)->alloc(&p, count); if (HPX_UNLIKELY(!result || NULL == p)) { // out of memory HPX_THROW_EXCEPTION(out_of_memory, name() + "::alloc", boost::str(boost::format( "new heap failed to allocate %1% objects") % count)); } alloc_count_ += count; ++heap_count_; LOSH_(info) << (boost::format( "%1%::alloc: creating new heap[%2%], size is now %3%") % name() % heap_count_ % heap_list_.size()); did_create = true; } if (did_create) return p; // Try again, we just got a new heap, so we should be good. return alloc(count); }
boost::shared_ptr<parcelport> parcelport::create(int type, util::runtime_configuration const& cfg, HPX_STD_FUNCTION<void(std::size_t, char const*)> const& on_start_thread, HPX_STD_FUNCTION<void()> const& on_stop_thread) { switch(type) { case connection_tcp: { #if defined(HPX_HAVE_PARCELPORT_TCP) std::string enable_tcp = cfg.get_entry("hpx.parcel.tcp.enable", "1"); if (boost::lexical_cast<int>(enable_tcp)) { return boost::make_shared<policies::tcp::connection_handler>( cfg, on_start_thread, on_stop_thread); } #endif HPX_THROW_EXCEPTION(bad_parameter, "parcelport::create", "unsupported connection type 'connection_tcp'"); } case connection_ipc: { #if defined(HPX_HAVE_PARCELPORT_IPC) // Create ipc based parcelport only if allowed by the // configuration info. std::string enable_ipc = cfg.get_entry("hpx.parcel.ipc.enable", "0"); if (boost::lexical_cast<int>(enable_ipc)) { return boost::make_shared<policies::ipc::connection_handler>( cfg, on_start_thread, on_stop_thread); } #endif HPX_THROW_EXCEPTION(bad_parameter, "parcelport::create", "unsupported connection type 'connection_ipc'"); } break; case connection_ibverbs: #if defined(HPX_HAVE_PARCELPORT_IBVERBS) { // Create ibverbs based parcelport only if allowed by the // configuration info. std::string enable_ibverbs = cfg.get_entry("hpx.parcel.ibverbs.enable", "0"); if (boost::lexical_cast<int>(enable_ibverbs)) { return boost::make_shared<policies::ibverbs::connection_handler>( cfg, on_start_thread, on_stop_thread); } } #endif HPX_THROW_EXCEPTION(bad_parameter, "parcelport::create", "unsupported connection type 'connection_ibverbs'"); break; case connection_portals4: HPX_THROW_EXCEPTION(bad_parameter, "parcelport::create", "unsupported connection type 'connection_portals4'"); break; case connection_mpi: #if defined(HPX_HAVE_PARCELPORT_MPI) { // Create MPI based parcelport only if allowed by the // configuration info. std::string enable_mpi = cfg.get_entry("hpx.parcel.mpi.enable", "0"); if (boost::lexical_cast<int>(enable_mpi)) { return boost::make_shared<policies::mpi::connection_handler>( cfg, on_start_thread, on_stop_thread); } } #endif HPX_THROW_EXCEPTION(bad_parameter, "parcelport::create", "unsupported connection type 'connection_mpi'"); break; default: HPX_THROW_EXCEPTION(bad_parameter, "parcelport::create", "unknown connection type"); break; } return boost::shared_ptr<parcelport>(); }
distributing_factory::remote_result_type distributing_factory::create_partitioned(components::component_type type, std::size_t count, std::size_t parts, partition_info const& info) const { // make sure we get prefixes for derived component type, if any components::component_type prefix_type = type; if (type != components::get_base_type(type)) prefix_type = components::get_derived_type(type); // get list of locality prefixes std::vector<naming::id_type> localities = hpx::find_all_localities(prefix_type); if (localities.empty()) { // no locality supports creating the requested component type HPX_THROW_EXCEPTION(bad_component_type, "distributing_factory::create_partitioned", "attempt to create component instance of unknown type: " + components::get_component_type_name(type)); } std::size_t part_size = info.size(); if (part_size < localities.size()) { // we have less localities than required by one partition HPX_THROW_EXCEPTION(bad_parameter, "distributing_factory::create_partitioned", "partition size is larger than number of localities"); } // a new partition starts every parts_delta localities std::size_t parts_delta = 0; if (localities.size() > part_size) parts_delta = localities.size() / part_size; // distribute the number of components to create evenly over all // available localities typedef std::vector<lazy_result> future_values_type; typedef server::runtime_support::bulk_create_components_action action_type; // start an asynchronous operation for each of the localities future_values_type v; for (std::size_t i = 0, j = 0; i < localities.size() && j < parts; i += parts_delta, ++j) { // create components for each locality in one go, overall, 'count' // components for each partition v.push_back(future_values_type::value_type(localities[i].get_gid())); lcos::packaged_action<action_type, std::vector<naming::gid_type> > p; p.apply(localities[i], type, count); v.back().gids_ = p.get_future(); } // now wait for the results remote_result_type results; BOOST_FOREACH(lazy_result& lr, v) { results.push_back(remote_result_type::value_type(lr.locality_, type)); results.back().gids_ = boost::move(lr.gids_.move()); }
/////////////////////////////////////////////////////////////////////// // Queries the current thread count of the queues. std::int64_t get_thread_count(thread_state_enum state = unknown, thread_priority priority = thread_priority_default, std::size_t num_thread = std::size_t(-1), bool reset = false) const { // Return thread count of one specific queue. std::int64_t count = 0; if (std::size_t(-1) != num_thread) { HPX_ASSERT(num_thread < queues_.size()); switch (priority) { case thread_priority_default: { if (num_thread < high_priority_queues_.size()) count = high_priority_queues_[num_thread]-> get_thread_count(state); if (queues_.size()-1 == num_thread) count += low_priority_queue_.get_thread_count(state); return count + queues_[num_thread]->get_thread_count(state); } case thread_priority_low: { if (queues_.size()-1 == num_thread) return low_priority_queue_.get_thread_count(state); break; } case thread_priority_normal: return queues_[num_thread]->get_thread_count(state); case thread_priority_boost: case thread_priority_critical: { if (num_thread < high_priority_queues_.size()) return high_priority_queues_[num_thread]-> get_thread_count(state); break; } default: case thread_priority_unknown: { HPX_THROW_EXCEPTION(bad_parameter, "local_priority_queue_scheduler::get_thread_count", "unknown thread priority value (thread_priority_unknown)"); return 0; } } return 0; } // Return the cumulative count for all queues. switch (priority) { case thread_priority_default: { for (std::size_t i = 0; i != high_priority_queues_.size(); ++i) count += high_priority_queues_[i]->get_thread_count(state); count += low_priority_queue_.get_thread_count(state); for (std::size_t i = 0; i != queues_.size(); ++i) count += queues_[i]->get_thread_count(state); break; } case thread_priority_low: return low_priority_queue_.get_thread_count(state); case thread_priority_normal: { for (std::size_t i = 0; i != queues_.size(); ++i) count += queues_[i]->get_thread_count(state); break; } case thread_priority_boost: case thread_priority_critical: { for (std::size_t i = 0; i != high_priority_queues_.size(); ++i) count += high_priority_queues_[i]->get_thread_count(state); break; } default: case thread_priority_unknown: { HPX_THROW_EXCEPTION(bad_parameter, "local_priority_queue_scheduler::get_thread_count", "unknown thread priority value (thread_priority_unknown)"); return 0; } } return count; }
/// \brief Create a new GID (if called for the first time), assign this /// GID to this instance of a component and register this gid /// with the AGAS service /// /// \returns The global id (GID) assigned to this instance of a /// component naming::gid_type get_base_gid( naming::gid_type const& assign_gid = naming::invalid_gid) const { if (!gid_) { applier::applier& appl = hpx::applier::get_applier(); naming::address addr(appl.here(), components::get_component_type<wrapped_type>(), boost::uint64_t(static_cast<this_component_type const*>(this))); if (!assign_gid) { gid_ = hpx::detail::get_next_id(); if (!applier::bind_gid_local(gid_, addr)) { hpx::util::osstream strm; strm << gid_; gid_ = naming::invalid_gid; // invalidate GID HPX_THROW_EXCEPTION(duplicate_component_address, "simple_component_base<Component>::get_base_gid", hpx::util::osstream_get_string(strm)); } } else { gid_ = assign_gid; naming::detail::strip_credits_from_gid(gid_); if (!agas::bind_sync(gid_, addr, appl.get_locality_id())) { hpx::util::osstream strm; strm << gid_; gid_ = naming::invalid_gid; // invalidate GID HPX_THROW_EXCEPTION(duplicate_component_address, "simple_component_base<Component>::get_base_gid", hpx::util::osstream_get_string(strm)); } } } naming::gid_type::mutex_type::scoped_lock l(gid_.get_mutex()); if (!naming::detail::has_credits(gid_)) { naming::gid_type gid = gid_; return gid; } // on first invocation take all credits to avoid a self reference naming::gid_type gid = gid_; naming::detail::strip_credits_from_gid( const_cast<naming::gid_type&>(gid_)); HPX_ASSERT(naming::detail::has_credits(gid)); // We have to assume this credit was split as otherwise the gid // returned at this point will control the lifetime of the // component. naming::detail::set_credit_split_mask_for_gid(gid); return gid; }
//[error_handling_raise_exception void raise_exception() { HPX_THROW_EXCEPTION(hpx::no_success, "raise_exception", "simulated error"); }
void decode_message_with_chunks( Parcelport & pp , Buffer buffer , std::size_t parcel_count , std::vector<serialization::serialization_chunk> &chunks , std::size_t num_thread = -1 ) { std::uint64_t inbound_data_size = buffer.data_size_; // protect from un-handled exceptions bubbling up try { try { // mark start of serialization util::high_resolution_timer timer; std::int64_t overall_add_parcel_time = 0; performance_counters::parcels::data_point& data = buffer.data_point_; { std::vector<parcel> deferred_parcels; // De-serialize the parcel data serialization::input_archive archive(buffer.data_, inbound_data_size, &chunks); if(parcel_count == 0) { archive >> parcel_count; //-V128 if (parcel_count > 1) deferred_parcels.reserve(parcel_count); } for(std::size_t i = 0; i != parcel_count; ++i) { bool deferred_schedule = true; if (i == parcel_count - 1) deferred_schedule = false; #if defined(HPX_HAVE_PARCELPORT_ACTION_COUNTERS) std::size_t archive_pos = archive.current_pos(); std::int64_t serialize_time = timer.elapsed_nanoseconds(); #endif // de-serialize parcel and add it to incoming parcel queue parcel p; // deferred_schedule will be set to false if it was previously // set to true and the action to be scheduled is direct. bool migrated = p.load_schedule(archive, num_thread, deferred_schedule); std::int64_t add_parcel_time = timer.elapsed_nanoseconds(); #if defined(HPX_HAVE_PARCELPORT_ACTION_COUNTERS) performance_counters::parcels::data_point action_data; action_data.bytes_ = archive.current_pos() - archive_pos; action_data.serialization_time_ = add_parcel_time - serialize_time; action_data.num_parcels_ = 1; pp.add_received_data(p.get_action()->get_action_name(), action_data); #endif // make sure this parcel ended up on the right locality naming::gid_type const& here = hpx::get_locality(); if (hpx::get_runtime_ptr() && here && (naming::get_locality_id_from_gid( p.destination_locality()) != naming::get_locality_id_from_gid(here))) { std::ostringstream os; os << "parcel destination does not match " "locality which received the parcel (" << here << "), " << p; HPX_THROW_EXCEPTION(invalid_status, "hpx::parcelset::decode_message", os.str()); return; } if (migrated) { naming::resolver_client& client = hpx::naming::get_agas_client(); client.route( std::move(p), &detail::parcel_route_handler, threads::thread_priority_normal); } else if (deferred_schedule) deferred_parcels.push_back(std::move(p)); // be sure not to measure add_parcel as serialization time overall_add_parcel_time += timer.elapsed_nanoseconds() - add_parcel_time; } // complete received data with parcel count data.num_parcels_ = parcel_count; data.raw_bytes_ = archive.bytes_read(); for (std::size_t i = 0; i != deferred_parcels.size(); ++i) { // If we are the last deferred parcel, we don't need to spin // a new thread... if (i == deferred_parcels.size() - 1) { deferred_parcels[i].schedule_action(num_thread); } // ... otherwise, schedule the parcel on a new thread. else { hpx::applier::register_thread_nullary( util::bind( util::one_shot( [num_thread](parcel&& p) { p.schedule_action(num_thread); } ), std::move(deferred_parcels[i])), "schedule_parcel", threads::pending, true, threads::thread_priority_critical, num_thread, threads::thread_stacksize_default); } } } // store the time required for serialization data.serialization_time_ = timer.elapsed_nanoseconds() - overall_add_parcel_time; pp.add_received_data(data); } catch (hpx::exception const& e) { LPT_(error) << "decode_message: caught hpx::exception: " << e.what(); hpx::report_error(boost::current_exception()); } catch (boost::system::system_error const& e) { LPT_(error) << "decode_message: caught boost::system::error: " << e.what(); hpx::report_error(boost::current_exception()); } catch (boost::exception const&) { LPT_(error) << "decode_message: caught boost::exception."; hpx::report_error(boost::current_exception()); } catch (std::exception const& e) { // We have to repackage all exceptions thrown by the // serialization library as otherwise we will loose the // e.what() description of the problem, due to slicing. boost::throw_exception(boost::enable_error_info( hpx::exception(serialization_error, e.what()))); } }
/////////////////////////////////////////////////////////////////////// // add new threads if there is some amount of work available std::size_t add_new(std::int64_t add_count, thread_queue* addfrom, std::unique_lock<mutex_type> &lk, bool steal = false) { HPX_ASSERT(lk.owns_lock()); if (HPX_UNLIKELY(0 == add_count)) return 0; std::size_t added = 0; task_description* task = nullptr; while (add_count-- && addfrom->new_tasks_.pop(task, steal)) { #ifdef HPX_HAVE_THREAD_QUEUE_WAITTIME if (maintain_queue_wait_times) { addfrom->new_tasks_wait_ += util::high_resolution_clock::now() - util::get<2>(*task); ++addfrom->new_tasks_wait_count_; } #endif --addfrom->new_tasks_count_; // measure thread creation time util::block_profiler_wrapper<add_new_tag> bp(add_new_logger_); // create the new thread threads::thread_init_data& data = util::get<0>(*task); thread_state_enum state = util::get<1>(*task); threads::thread_id_type thrd; create_thread_object(thrd, data, state, lk); delete task; // add the new entry to the map of all threads std::pair<thread_map_type::iterator, bool> p = thread_map_.insert(thrd); if (HPX_UNLIKELY(!p.second)) { lk.unlock(); HPX_THROW_EXCEPTION(hpx::out_of_memory, "threadmanager::add_new", "Couldn't add new thread to the thread map"); return 0; } ++thread_map_count_; // only insert the thread into the work-items queue if it is in // pending state if (state == pending) { // pushing the new thread into the pending queue of the // specified thread_queue ++added; schedule_thread(thrd.get()); } // this thread has to be in the map now HPX_ASSERT(thread_map_.find(thrd.get()) != thread_map_.end()); HPX_ASSERT(thrd->get_pool() == &memory_pool_); } if (added) { LTM_(debug) << "add_new: added " << added << " tasks to queues"; //-V128 } return added; }
// 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); } } }
/////////////////////////////////////////////////////////////////////////// // Call-back function for parcelHandler to call when new parcels are received void action_manager::fetch_parcel( parcelset::parcelhandler& parcel_handler, naming::gid_type const& parcel_id) { parcelset::parcel p; if (!parcel_handler.get_parcel(p, parcel_id)) return; while (threads::threadmanager_is(starting)) { boost::this_thread::sleep(boost::get_system_time() + boost::posix_time::milliseconds(HPX_NETWORK_RETRIES_SLEEP)); } // Give up if we're shutting down. if (threads::threadmanager_is(stopping)) { LPT_(debug) << "action_manager: fetch_parcel: dropping late " "parcel " << p; return; } // write this parcel to the log LPT_(debug) << "action_manager: fetch_parcel: " << p; // decode the action-type in the parcel continuation_type cont = p.get_continuation(); actions::action_type act = p.get_action(); actions::base_action::action_type acttype = act->get_action_type(); int comptype = act->get_component_type(); naming::locality dest = p.get_destination_locality(); // fetch the set of destinations std::vector<naming::address> const& addrs = p.get_destination_addrs(); // if the parcel carries a continuation it should be directed to a // single destination BOOST_ASSERT(!cont || addrs.size() == 1); // schedule a thread for each of the destinations threads::threadmanager_base& tm = appl_.get_thread_manager(); std::vector<naming::address>::const_iterator end = addrs.end(); for (std::vector<naming::address>::const_iterator it = addrs.begin(); it != end; ++it) { naming::address const& addr = *it; // make sure this parcel destination matches the proper locality BOOST_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 = appl_.get_runtime_support_raw_gid().get_lsb(); // 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)); } // either directly execute the action or create a new thread if (actions::base_action::direct_action == acttype) { // direct execution of the action if (!cont) { // No continuation is to be executed. act->get_thread_function(lva)(threads::wait_signaled); } else { // This parcel carries a continuation, we execute a wrapper // handling all related functionality. act->get_thread_function(cont, lva)(threads::wait_signaled); } } else { // 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 with the TM only. threads::thread_init_data data; tm.register_work( act->get_thread_init_data(lva, data), 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. threads::thread_init_data data; tm.register_work( act->get_thread_init_data(cont, lva, data), threads::pending); } } } }
/// the following functions are not implemented by default, they will /// just throw virtual void reset_counter_value() { HPX_THROW_EXCEPTION(invalid_status, "reset_counter_value", "reset_counter_value is not implemented for this counter"); }
void connection_handler::handle_messages() { detail::handling_messages hm(handling_messages_); // reset on exit bool bootstrapping = hpx::is_starting(); bool has_work = true; std::size_t k = 0; hpx::util::high_resolution_timer t; std::list<std::pair<int, MPI_Request> > close_requests; // We let the message handling loop spin for another 2 seconds to avoid the // costs involved with posting it to asio while(bootstrapping || has_work || (!has_work && t.elapsed() < 2.0)) { if(stopped_) break; // break the loop if someone requested to pause the parcelport if(!enable_parcel_handling_) break; // handle all send requests { hpx::lcos::local::spinlock::scoped_lock l(senders_mtx_); for( senders_type::iterator it = senders_.begin(); !stopped_ && enable_parcel_handling_ && it != senders_.end(); /**/) { if((*it)->done()) { it = senders_.erase(it); } else { ++it; } } has_work = !senders_.empty(); } // Send the pending close requests { hpx::lcos::local::spinlock::scoped_lock l(close_mtx_); typedef std::pair<int, int> pair_type; BOOST_FOREACH(pair_type p, pending_close_requests_) { header close_request = header::close(p.first, p.second); close_requests.push_back(std::make_pair(p.first, MPI_Request())); MPI_Isend( close_request.data(), // Data pointer close_request.data_size_, // Size close_request.type(), // MPI Datatype close_request.rank(), // Destination 0, // Tag communicator_, // Communicator &close_requests.back().second ); } pending_close_requests_.clear(); } // add new receive requests std::pair<bool, header> next(acceptor_.next_header()); if(next.first) { boost::shared_ptr<receiver> rcv; header h = next.second; receivers_tag_map_type & tag_map = receivers_map_[h.rank()]; receivers_tag_map_type::iterator jt = tag_map.find(h.tag()); if(jt != tag_map.end()) { rcv = jt->second; } else { rcv = boost::make_shared<receiver>( communicator_ , get_next_tag() , h.tag() , h.rank() , *this); tag_map.insert(std::make_pair(h.tag(), rcv)); } if(h.close_request()) { rcv->close(); } else { h.assert_valid(); if (static_cast<std::size_t>(h.size()) > this->get_max_message_size()) { // report this problem ... HPX_THROW_EXCEPTION(boost::asio::error::operation_not_supported, "mpi::connection_handler::handle_messages", "The size of this message exceeds the maximum inbound data size"); return; } if(rcv->async_read(h)) { #ifdef HPX_DEBUG receivers_type::iterator it = std::find(receivers_.begin(), receivers_.end(), rcv); HPX_ASSERT(it == receivers_.end()); #endif receivers_.push_back(rcv); } } } // handle all receive requests for(receivers_type::iterator it = receivers_.begin(); it != receivers_.end(); /**/) { boost::shared_ptr<receiver> rcv = *it; if(rcv->done()) { HPX_ASSERT(rcv->sender_tag() != -1); if(rcv->closing()) { receivers_tag_map_type & tag_map = receivers_map_[rcv->rank()]; receivers_tag_map_type::iterator jt = tag_map.find(rcv->sender_tag()); HPX_ASSERT(jt != tag_map.end()); tag_map.erase(jt); { hpx::lcos::local::spinlock::scoped_lock l(tag_mtx_); free_tags_.push_back(rcv->tag()); } } it = receivers_.erase(it); } else { ++it; } } if(!has_work) has_work = !receivers_.empty(); // handle completed close requests for( std::list<std::pair<int, MPI_Request> >::iterator it = close_requests.begin(); !stopped_ && enable_parcel_handling_ && it != close_requests.end(); ) { int completed = 0; MPI_Status status; int ret = 0; ret = MPI_Test(&it->second, &completed, &status); HPX_ASSERT(ret == MPI_SUCCESS); if(completed && status.MPI_ERROR != MPI_ERR_PENDING) { hpx::lcos::local::spinlock::scoped_lock l(tag_mtx_); free_tags_.push_back(it->first); it = close_requests.erase(it); } else { ++it; } } if(!has_work) has_work = !close_requests.empty(); if (bootstrapping) bootstrapping = hpx::is_starting(); if(has_work) { t.restart(); k = 0; } else { if(enable_parcel_handling_) { hpx::lcos::local::spinlock::yield(k); ++k; } } }
void hpx_thread_func() { HPX_THROW_EXCEPTION(hpx::invalid_status, "hpx_thread_func", "test"); }
// 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); } } }
void decode_message(Parcelport & pp, boost::shared_ptr<Buffer> buffer, std::vector<util::serialization_chunk> const *chunks, bool first_message = false) { unsigned archive_flags = boost::archive::no_header; if (!pp.allow_array_optimizations()) { archive_flags |= util::disable_array_optimization; archive_flags |= util::disable_data_chunking; } else if (!pp.allow_zero_copy_optimizations()) { archive_flags |= util::disable_data_chunking; } boost::uint64_t inbound_data_size = buffer->data_size_; // protect from un-handled exceptions bubbling up try { try { // mark start of serialization util::high_resolution_timer timer; boost::int64_t overall_add_parcel_time = 0; performance_counters::parcels::data_point& data = buffer->data_point_; { // De-serialize the parcel data util::portable_binary_iarchive archive(buffer->data_, chunks, inbound_data_size, archive_flags); std::size_t parcel_count = 0; archive >> parcel_count; //-V128 for(std::size_t i = 0; i != parcel_count; ++i) { #if defined(HPX_HAVE_SECURITY) naming::gid_type parcel_id; if (pp.enable_security()) { // handle certificate and verify parcel suffix once first_message = deserialize_certificate(archive, first_message); if (!first_message && i == 0) { verify_message_suffix(buffer->data_, buffer->data_point_, parcel_id); } } // de-serialize parcel and add it to incoming parcel queue parcel p; archive >> p; // verify parcel id, but only once while handling the // first parcel if (pp.enable_security() && !first_message && i == 0 && parcel_id != p.get_parcel_id()) { // again, all hell breaks loose HPX_THROW_EXCEPTION(security_error, "decode_message", "parcel id mismatch"); return; } #else // de-serialize parcel and add it to incoming parcel queue parcel p; archive >> p; #endif // make sure this parcel ended up on the right locality HPX_ASSERT(p.get_destination_locality() == pp.here()); // be sure not to measure add_parcel as serialization time boost::int64_t add_parcel_time = timer.elapsed_nanoseconds(); pp.add_received_parcel(p); overall_add_parcel_time += timer.elapsed_nanoseconds() - add_parcel_time; } // complete received data with parcel count data.num_parcels_ = parcel_count; data.raw_bytes_ = archive.bytes_read(); } // store the time required for serialization data.serialization_time_ = timer.elapsed_nanoseconds() - overall_add_parcel_time; pp.add_received_data(data); } catch (hpx::exception const& e) { LPT_(error) << "decode_message: caught hpx::exception: " << e.what(); hpx::report_error(boost::current_exception()); } catch (boost::system::system_error const& e) { LPT_(error) << "decode_message: caught boost::system::error: " << e.what(); hpx::report_error(boost::current_exception()); } catch (boost::exception const&) { LPT_(error) << "decode_message: caught boost::exception."; hpx::report_error(boost::current_exception()); } catch (std::exception const& e) { // We have to repackage all exceptions thrown by the // serialization library as otherwise we will loose the // e.what() description of the problem, due to slicing. boost::throw_exception(boost::enable_error_info( hpx::exception(serialization_error, e.what()))); } } catch (...) { LPT_(error) << "decode_message: caught unknown exception."; hpx::report_error(boost::current_exception()); } }
bool thread_pool<Scheduler>::run(boost::unique_lock<boost::mutex>& l, std::size_t num_threads) { HPX_ASSERT(l.owns_lock()); LTM_(info) //-V128 << "thread_pool::run: " << pool_name_ << " number of processing units available: " //-V128 << threads::hardware_concurrency(); LTM_(info) //-V128 << "thread_pool::run: " << pool_name_ << " creating " << num_threads << " OS thread(s)"; //-V128 if (0 == num_threads) { HPX_THROW_EXCEPTION(bad_parameter, "thread_pool::run", "number of threads is zero"); } #if defined(HPX_HAVE_THREAD_CUMULATIVE_COUNTS) && \ defined(HPX_HAVE_THREAD_IDLE_RATES) // scale timestamps to nanoseconds boost::uint64_t base_timestamp = util::hardware::timestamp(); boost::uint64_t base_time = util::high_resolution_clock::now(); boost::uint64_t curr_timestamp = util::hardware::timestamp(); boost::uint64_t curr_time = util::high_resolution_clock::now(); while ((curr_time - base_time) <= 100000) { curr_timestamp = util::hardware::timestamp(); curr_time = util::high_resolution_clock::now(); } if (curr_timestamp - base_timestamp != 0) { timestamp_scale_ = double(curr_time - base_time) / double(curr_timestamp - base_timestamp); } LTM_(info) << "thread_pool::run: " << pool_name_ << " timestamp_scale: " << timestamp_scale_; //-V128 #endif if (!threads_.empty() || sched_.has_reached_state(state_running)) return true; // do nothing if already running executed_threads_.resize(num_threads); executed_thread_phases_.resize(num_threads); tfunc_times_.resize(num_threads); exec_times_.resize(num_threads); try { HPX_ASSERT(startup_.get() == 0); startup_.reset( new boost::barrier(static_cast<unsigned>(num_threads+1)) ); // run threads and wait for initialization to complete sched_.set_all_states(state_running); topology const& topology_ = get_topology(); std::size_t thread_num = num_threads; while (thread_num-- != 0) { threads::mask_cref_type mask = sched_.Scheduler::get_pu_mask(topology_, thread_num); LTM_(info) //-V128 << "thread_pool::run: " << pool_name_ << " create OS thread " << thread_num //-V128 << ": will run on processing units within this mask: " #if !defined(HPX_WITH_MORE_THAN_64_THREADS) || \ (defined(HPX_HAVE_MAX_CPU_COUNT) && HPX_HAVE_MAX_CPU_COUNT <= 64) << std::hex << "0x" << mask; #else << "0b" << mask; #endif // create a new thread threads_.push_back(new boost::thread( util::bind(&thread_pool::thread_func, this, thread_num, boost::ref(topology_), boost::ref(*startup_)) )); // set the new threads affinity (on Windows systems) if (any(mask)) { error_code ec(lightweight); topology_.set_thread_affinity_mask(threads_.back(), mask, ec); if (ec) { LTM_(warning) //-V128 << "thread_pool::run: " << pool_name_ << " setting thread affinity on OS thread " //-V128 << thread_num << " failed with: " << ec.get_message(); } } else { LTM_(debug) //-V128 << "thread_pool::run: " << pool_name_ << " setting thread affinity on OS thread " //-V128 << thread_num << " was explicitly disabled."; } } // the main thread needs to have a unique thread_num init_tss(num_threads); startup_->wait(); }
void* one_size_heap_list::alloc(std::size_t count) { unique_lock_type guard(mtx_); if (HPX_UNLIKELY(0 == count)) { guard.unlock(); HPX_THROW_EXCEPTION(bad_parameter, name() + "::alloc", "cannot allocate 0 objects"); } //std::size_t size = 0; void* p = nullptr; { if (!heap_list_.empty()) { //size = heap_list_.size(); for (auto & heap : heap_list_) { bool allocated = false; { util::unlock_guard<unique_lock_type> ul(guard); allocated = heap->alloc(&p, count); } if (allocated) { #if defined(HPX_DEBUG) // Allocation succeeded, update statistics. alloc_count_ += count; if (alloc_count_ - free_count_ > max_alloc_count_) max_alloc_count_ = alloc_count_- free_count_; #endif return p; } #if defined(HPX_DEBUG) LOSH_(info) << hpx::util::format( "{1}::alloc: failed to allocate from heap[{2}] " "(heap[{2}] has allocated {3} objects and has " "space for {4} more objects)", name(), heap->heap_count(), heap->size(), heap->free_size()); #endif } } } // Create new heap. bool did_create = false; { #if defined(HPX_DEBUG) heap_list_.push_front(create_heap_( class_name_.c_str(), heap_count_ + 1, parameters_)); #else heap_list_.push_front(create_heap_( class_name_.c_str(), 0, parameters_)); #endif iterator itnew = heap_list_.begin(); typename list_type::value_type heap = *itnew; bool result = false; { util::unlock_guard<unique_lock_type> ul(guard); result = heap->alloc((void**)&p, count); } if (HPX_UNLIKELY(!result || nullptr == p)) { // out of memory guard.unlock(); HPX_THROW_EXCEPTION(out_of_memory, name() + "::alloc", hpx::util::format( "new heap failed to allocate {1} objects", count)); } #if defined(HPX_DEBUG) alloc_count_ += count; ++heap_count_; LOSH_(info) << hpx::util::format( "{1}::alloc: creating new heap[{2}], size is now {3}", name(), heap_count_, heap_list_.size()); #endif did_create = true; } if (did_create) return p; guard.unlock(); // Try again, we just got a new heap, so we should be good. return alloc(count); }
void parcelport::put_parcel(parcel const& p, write_handler_type f) { typedef pending_parcels_map::iterator iterator; naming::locality locality_id = p.get_destination_locality(); parcelport_connection_ptr client_connection; // enqueue the incoming parcel ... { util::spinlock::scoped_lock l(mtx_); pending_parcels_[locality_id].first.push_back(p); pending_parcels_[locality_id].second.push_back(f); } // Get a connection or reserve space for a new connection. if (!connection_cache_.get_or_reserve(locality_id, client_connection)) return; // Check if we need to create the new connection. if (!client_connection) { client_connection.reset(new parcelport_connection( io_service_pool_.get_io_service(), locality_id, connection_cache_, timer_, parcels_sent_)); // Connect to the target locality, retry if needed. boost::system::error_code error = boost::asio::error::try_again; for (int i = 0; i < HPX_MAX_NETWORK_RETRIES; ++i) { try { naming::locality::iterator_type end = locality_id.connect_end(); for (naming::locality::iterator_type it = locality_id.connect_begin(io_service_pool_.get_io_service()); it != end; ++it) { client_connection->socket().close(); client_connection->socket().connect(*it, error); if (!error) break; } if (!error) break; // we wait for a really short amount of time // TODO: Should this be an hpx::threads::suspend? boost::this_thread::sleep(boost::get_system_time() + boost::posix_time::milliseconds(HPX_NETWORK_RETRIES_SLEEP)); } catch (boost::system::error_code const& e) { HPX_THROW_EXCEPTION(network_error, "parcelport::send_parcel", e.message()); } } if (error) { client_connection->socket().close(); hpx::util::osstream strm; strm << error.message() << " (while trying to connect to: " << locality_id << ")"; HPX_THROW_EXCEPTION(network_error, "parcelport::send_parcel", hpx::util::osstream_get_string(strm)); } #if defined(HPX_DEBUG) else { std::string connection_addr = client_connection->socket().remote_endpoint().address().to_string(); boost::uint16_t connection_port = client_connection->socket().remote_endpoint().port(); BOOST_ASSERT(locality_id.get_address() == connection_addr); BOOST_ASSERT(locality_id.get_port() == connection_port); } #endif } #if defined(HPX_DEBUG) else { //LPT_(info) << "parcelport: reusing existing connection to: " // << addr.locality_; BOOST_ASSERT(locality_id == client_connection->destination()); std::string connection_addr = client_connection->socket().remote_endpoint().address().to_string(); boost::uint16_t connection_port = client_connection->socket().remote_endpoint().port(); BOOST_ASSERT(locality_id.get_address() == connection_addr); BOOST_ASSERT(locality_id.get_port() == connection_port); } #endif std::vector<parcel> parcels; std::vector<write_handler_type> handlers; util::spinlock::scoped_lock l(mtx_); iterator it = pending_parcels_.find(locality_id); if (it != pending_parcels_.end()) { BOOST_ASSERT(it->first == locality_id); std::swap(parcels, it->second.first); std::swap(handlers, it->second.second); } // If the parcels didn't get sent by another connection ... if (!parcels.empty() && !handlers.empty()) { send_pending_parcels(client_connection, parcels, handlers); } else { // ... or re-add the stuff to the cache BOOST_ASSERT(locality_id == client_connection->destination()); connection_cache_.reclaim(locality_id, client_connection); } }
naming::gid_type base_component::get_base_gid_dynamic( naming::gid_type const& assign_gid, naming::address const& addr, naming::gid_type (*f)(naming::gid_type)) const { if (!gid_) { if (!assign_gid) { if (f != nullptr) { gid_ = f(hpx::detail::get_next_id()); } else { gid_ = hpx::detail::get_next_id(); } if (!applier::bind_gid_local(gid_, addr)) { std::ostringstream strm; strm << "failed to bind id " << gid_ << "to locality: " << hpx::get_locality(); gid_ = naming::invalid_gid; // invalidate GID HPX_THROW_EXCEPTION(duplicate_component_address, "component_base<Component>::get_base_gid", strm.str()); } } else { applier::applier& appl = hpx::applier::get_applier(); gid_ = assign_gid; naming::detail::strip_credits_from_gid(gid_); if (!agas::bind( launch::sync, gid_, addr, appl.get_locality_id())) { std::ostringstream strm; strm << "failed to rebind id " << gid_ << "to locality: " << hpx::get_locality(); gid_ = naming::invalid_gid; // invalidate GID HPX_THROW_EXCEPTION(duplicate_component_address, "component_base<Component>::get_base_gid", strm.str()); } } } std::unique_lock<naming::gid_type::mutex_type> l(gid_.get_mutex()); if (!naming::detail::has_credits(gid_)) { naming::gid_type gid = gid_; return gid; } // on first invocation take all credits to avoid a self reference naming::gid_type gid = gid_; naming::detail::strip_credits_from_gid( const_cast<naming::gid_type&>(gid_)); HPX_ASSERT(naming::detail::has_credits(gid)); // We have to assume this credit was split as otherwise the gid // returned at this point will control the lifetime of the // component. naming::detail::set_credit_split_mask_for_gid(gid); return gid; }
// remote call to AGAS void register_worker(registration_header const& header) { // This lock acquires the bbb mutex on creation. When it goes out of scope, // it's dtor calls big_boot_barrier::notify(). big_boot_barrier::scoped_lock lock(get_big_boot_barrier()); naming::resolver_client& agas_client = get_runtime().get_agas_client(); if (HPX_UNLIKELY(agas_client.is_connecting())) { HPX_THROW_EXCEPTION(internal_server_error , "agas::register_worker" , "runtime_mode_connect can't find running application."); } if (HPX_UNLIKELY(!agas_client.is_bootstrap())) { HPX_THROW_EXCEPTION(internal_server_error , "agas::register_worker" , "registration parcel received by non-bootstrap locality."); } naming::gid_type prefix , parcel_lower, parcel_upper , heap_lower, heap_upper; agas_client.register_locality(header.locality, prefix); agas_client.get_id_range(header.locality, header.parcelport_allocation , parcel_lower, parcel_upper); agas_client.get_id_range(header.locality, header.response_allocation , heap_lower, heap_upper); naming::gid_type runtime_support_gid(prefix.get_msb() , header.component_runtime_support_ptr) , memory_gid(prefix.get_msb() , header.component_memory_ptr); naming::address runtime_support_address (header.locality, components::get_component_type<components::server::runtime_support>(), header.component_runtime_support_ptr); naming::address memory_address (header.locality, components::get_component_type<components::server::memory>(), header.component_memory_ptr); agas_client.bind(runtime_support_gid, runtime_support_address); agas_client.bind(memory_gid, memory_address); agas_client.bind_range(heap_lower, header.response_allocation , header.response_heap_address , header.response_heap_offset); naming::address primary_addr(get_runtime().here(), server::primary_namespace::get_component_type(), static_cast<void*>(&agas_client.bootstrap->primary_ns_server)); naming::address component_addr(get_runtime().here(), server::component_namespace::get_component_type(), static_cast<void*>(&agas_client.bootstrap->component_ns_server)); naming::address symbol_addr(get_runtime().here(), server::symbol_namespace::get_component_type(), static_cast<void*>(&agas_client.bootstrap->symbol_ns_server)); actions::base_action* p = new actions::transfer_action<notify_console_action>( notification_header( prefix, header.response_heap_address, header.response_heap_ptr, heap_lower, heap_upper, parcel_lower, parcel_upper, primary_addr, component_addr, symbol_addr)); // FIXME: This could screw with startup. // TODO: Handle cases where localities try to connect to AGAS while it's // shutting down. if (agas_client.status() != starting) { // We can just send the parcel now, the connecting locality isn't a part // of startup synchronization. get_big_boot_barrier().apply(naming::get_locality_id_from_gid(prefix) , naming::address(header.locality), p); } else // AGAS is starting up; this locality is participating in startup { // synchronization. HPX_STD_FUNCTION<void()>* thunk = new HPX_STD_FUNCTION<void()> (boost::bind(&big_boot_barrier::apply , boost::ref(get_big_boot_barrier()) , naming::get_locality_id_from_gid(prefix) , naming::address(header.locality) , p)); get_big_boot_barrier().add_thunk(thunk); } }