Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding hpx::local_new #2617

Merged
merged 1 commit into from May 12, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/hpx.idx
Expand Up @@ -345,6 +345,7 @@ binpacked '' "hpx\.components\.binpacked.*"

# hpx/runtime/components/new.hpp
new_ "" "hpx\.new_id.*"
local_new "" "hpx\.local_new.*"

# hpx/runtime/components/copy_component.hpp
copy "" "hpx\.components\.copy.*"
Expand Down
110 changes: 110 additions & 0 deletions hpx/runtime/components/new.hpp
Expand Up @@ -12,6 +12,7 @@
#include <hpx/lcos/future.hpp>
#include <hpx/runtime/components/client_base.hpp>
#include <hpx/runtime/components/default_distribution_policy.hpp>
#include <hpx/runtime/components/server/create_component.hpp>
#include <hpx/runtime/components/stubs/stub_base.hpp>
#include <hpx/runtime/naming/name.hpp>
#include <hpx/traits/is_client.hpp>
Expand Down Expand Up @@ -68,6 +69,49 @@ namespace hpx
<unspecified>
new_(id_type const& locality, Ts&&... vs);

/// \brief Create one new instance of the given Component type on the
/// current locality.
///
/// This function creates one new instance of the given Component
/// type on the current locality and returns a future object for the
/// global address which can be used to reference the new component
/// instance.
///
/// \param vs [in] Any number of arbitrary arguments (passed by
/// value, by const reference or by rvalue reference)
/// which will be forwarded to the constructor of
/// the created component instance.
///
/// \note This function requires to specify an explicit template
/// argument which will define what type of component(s) to
/// create, for instance:
/// \code
/// hpx::future<hpx::id_type> f =
/// hpx::local_new<some_component>(...);
/// hpx::id_type id = f.get();
/// \endcode
///
/// \returns The function returns different types depending on its use:\n
/// * If the explicit template argument \a Component represents a
/// component type (<code>traits::is_component<Component>::value</code>
/// evaluates to true), the function will return an \a hpx::future
/// object instance which can be used to retrieve the global
/// address of the newly created component.
/// * If the explicit template argument \a Component represents a
/// client side object (<code>traits::is_client<Component>::value</code>
/// evaluates to true), the function will return a new instance
/// of that type which can be used to refer to the newly created
/// component instance.
///
/// \note The difference of this funtion to \a hpx::new_ is that it can
/// be used in cases where the supplied arguments are non-copyable
/// and non-movable. All operations are guaranteed to be local
/// only.
///
template <typename Component, typename ...Ts>
<unspecified>
local_new(Ts&&... vs);

/// \brief Create multiple new instances of the given Component type on the
/// specified locality.
///
Expand Down Expand Up @@ -372,11 +416,77 @@ namespace hpx { namespace components
return detail::new_client<Client>::call(
policy, std::forward<Ts>(vs)...);
}

///////////////////////////////////////////////////////////////////////////
// Same as above, but just on this locality. This does not go through an
// action, that means that the constructor arguments can be non-copyable
// and non-movable.
namespace detail
{
template <typename Component>
struct local_new_component
{
typedef typename hpx::future<hpx::id_type> type;

template <typename ...Ts>
static type call(Ts &&... ts)
{
typedef typename Component::wrapping_type component_type;

hpx::id_type id(
components::server::construct<component_type>(
std::forward<Ts>(ts)...
),
hpx::id_type::managed);
return hpx::make_ready_future(std::move(id));
}
};

template <typename Client>
struct local_new_client
{
typedef Client type;
typedef typename Client::server_component_type::wrapping_type
component_type;

template <typename ...Ts>
static type call(Ts &&... ts)
{
hpx::id_type id(
components::server::construct<component_type>(
std::forward<Ts>(ts)...
),
hpx::id_type::managed);
return make_client<Client>(std::move(id));
}
};
}

template <typename Component, typename ...Ts>
inline typename util::lazy_enable_if<
traits::is_component<Component>::value,
detail::local_new_component<Component>
>::type
local_new(Ts &&... ts)
{
return detail::local_new_component<Component>::call(std::forward<Ts>(ts)...);
}

template <typename Client, typename ...Ts>
inline typename util::lazy_enable_if<
traits::is_client<Client>::value,
detail::local_new_client<Client>
>::type
local_new(Ts &&... ts)
{
return detail::local_new_client<Client>::call(std::forward<Ts>(ts)...);
}
}}

namespace hpx
{
using hpx::components::new_;
using hpx::components::local_new;
}

#endif
Expand Down
53 changes: 38 additions & 15 deletions hpx/runtime/components/server/create_component.hpp
Expand Up @@ -41,12 +41,9 @@ namespace hpx { namespace components { namespace server

Component::destroy(c, count);

std::ostringstream strm;
strm << "global id " << gid << " is already bound to a different "
"component instance";
HPX_THROW_EXCEPTION(hpx::duplicate_component_address,
HPX_THROW_EXCEPTION(hpx::unknown_component_address,
"create<Component>",
strm.str());
"can't assign global id");

return naming::invalid_gid;
}
Expand All @@ -73,14 +70,11 @@ namespace hpx { namespace components { namespace server
return gid;
}

Component::heap_type::free(c, 1); //-V107
Component::destroy(c, 1);

std::ostringstream strm;
strm << "global id " << gid << " is already bound to a different "
"component instance";
HPX_THROW_EXCEPTION(hpx::duplicate_component_address,
HPX_THROW_EXCEPTION(hpx::unknown_component_address,
"create<Component>(ctor)",
strm.str());
"can't assign global id");

return naming::invalid_gid;
}
Expand All @@ -107,10 +101,10 @@ namespace hpx { namespace components { namespace server
return gid;
}

Component::heap_type::free(c, 1); //-V107
Component::destroy(c, 1);

std::ostringstream strm;
strm << "global id " << assigned_gid <<
strm << "global id " << gid <<
" is already bound to a different component instance";
HPX_THROW_EXCEPTION(hpx::duplicate_component_address,
"create<Component>(naming::gid_type, ctor)",
Expand All @@ -119,6 +113,36 @@ namespace hpx { namespace components { namespace server
return naming::invalid_gid;
}

template <typename Component, typename ...Ts>
naming::gid_type create_with_args(Ts&&... ts)
{
void * cv = Component::heap_type::alloc(1);
try {
new (cv) Component(std::forward<Ts>(ts)...);
}
catch(...)
{
Component::heap_type::free(cv, 1); //-V107
throw;
}
Component *c = static_cast<Component *>(cv);

naming::gid_type gid = c->get_base_gid();
if (gid)
{
// everything is ok, return the new id
return gid;
}

Component::destroy(c, 1);

HPX_THROW_EXCEPTION(hpx::unknown_component_address,
"create_with_args<Component>(Ts&&...)",
"can't assign global id");

return naming::invalid_gid;
}

///////////////////////////////////////////////////////////////////////////
/// Create component with arguments
namespace detail
Expand All @@ -141,8 +165,7 @@ namespace hpx { namespace components { namespace server
template <typename Component, typename ...Ts>
naming::gid_type construct(Ts&&... vs)
{
return server::create<Component>(
detail::construct_function<Component>(std::forward<Ts>(vs)...));
return server::create_with_args<Component>(std::forward<Ts>(vs)...);
}
}}}

Expand Down
3 changes: 3 additions & 0 deletions hpx/runtime/components/server/create_component_fwd.hpp
Expand Up @@ -30,6 +30,9 @@ namespace hpx { namespace components { namespace server
template <typename Component>
naming::gid_type create(naming::gid_type const& gid,
util::unique_function_nonser<void(void*)> const& ctor);

template <typename Component, typename ...Ts>
naming::gid_type create_with_args(Ts&&... ts);
}}}

#endif
Expand Down
3 changes: 3 additions & 0 deletions hpx/runtime/components/server/managed_component_base.hpp
Expand Up @@ -619,6 +619,9 @@ namespace hpx { namespace components
template <typename Component_>
friend naming::gid_type server::create(naming::gid_type const& gid,
util::unique_function_nonser<void(void*)> const& ctor);

template <typename Component_, typename ...Ts>
friend naming::gid_type server::create_with_args(Ts&&... ts);
#endif

naming::gid_type get_base_gid(
Expand Down
2 changes: 1 addition & 1 deletion hpx/runtime/components/server/runtime_support.hpp
Expand Up @@ -446,7 +446,7 @@ namespace hpx { namespace components { namespace server
};

///////////////////////////////////////////////////////////////////////////
// Functions wrapped by creat_component actions below
// Functions wrapped by create_component actions below
#if defined(__NVCC__)
template <typename Component>
naming::gid_type runtime_support::create_component()
Expand Down
6 changes: 6 additions & 0 deletions hpx/runtime/components/server/simple_component_base.hpp
Expand Up @@ -117,6 +117,8 @@ namespace hpx { namespace components
std::uint64_t(static_cast<this_component_type const*>(this)));
}

#if defined(HPX_HAVE_CXX11_EXTENDED_FRIEND_DECLARATIONS) && !defined(__NVCC__) && \
!defined(__CUDACC__)
protected:
// declare friends which are allowed to access get_base_gid()
template <typename Component_>
Expand All @@ -130,6 +132,10 @@ namespace hpx { namespace components
friend naming::gid_type server::create(naming::gid_type const& gid,
util::unique_function_nonser<void(void*)> const& ctor);

template <typename Component_, typename ...Ts>
friend naming::gid_type server::create_with_args(Ts&&... ts);
#endif

// 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
Expand Down
1 change: 1 addition & 0 deletions tests/unit/component/CMakeLists.txt
Expand Up @@ -18,6 +18,7 @@ set(tests
inheritance_3_classes_2_abstract
inheritance_3_classes_concrete
launch_process
local_new
migrate_component
migrate_component_to_storage
new_
Expand Down
86 changes: 86 additions & 0 deletions tests/unit/component/local_new.cpp
@@ -0,0 +1,86 @@
// Copyright (c) 2015-2017 Hartmut Kaiser
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <hpx/hpx_main.hpp>
#include <hpx/include/components.hpp>
#include <hpx/include/actions.hpp>
#include <hpx/util/lightweight_test.hpp>

#include <cstddef>
#include <utility>
#include <vector>

///////////////////////////////////////////////////////////////////////////////
struct A
{
A() = default;

HPX_NON_COPYABLE(A);
};

///////////////////////////////////////////////////////////////////////////////
struct test_server : hpx::components::simple_component_base<test_server>
{
test_server() = default;
test_server(A const&) {}

hpx::id_type call() const { return hpx::find_here(); }

HPX_DEFINE_COMPONENT_ACTION(test_server, call);
};

typedef hpx::components::simple_component<test_server> server_type;
HPX_REGISTER_COMPONENT(server_type, test_server);

typedef test_server::call_action call_action;
HPX_REGISTER_ACTION(call_action);

struct test_client : hpx::components::client_base<test_client, test_server>
{
typedef hpx::components::client_base<test_client, test_server> base_type;

test_client(hpx::id_type const& id)
: base_type(id)
{}
test_client(hpx::future<hpx::id_type> && id)
: base_type(std::move(id))
{}

hpx::id_type call() const
{
return hpx::async<call_action>(this->get_id()).get();
}
};

///////////////////////////////////////////////////////////////////////////////
void test_create_single_instance()
{
hpx::id_type id = hpx::local_new<test_server>().get();
HPX_TEST(hpx::async<call_action>(id).get() == hpx::find_here());

test_client t1 = hpx::local_new<test_client>();
HPX_TEST(t1.call() == hpx::find_here());
}

void test_create_single_instance_non_copyable_arg()
{
A a;

hpx::id_type id = hpx::local_new<test_server>(a).get();
HPX_TEST(hpx::async<call_action>(id).get() == hpx::find_here());

test_client t1 = hpx::local_new<test_client>(a);
HPX_TEST(t1.call() == hpx::find_here());
}

///////////////////////////////////////////////////////////////////////////////
int main()
{
test_create_single_instance();
test_create_single_instance_non_copyable_arg();

return 0;
}