1 //  Copyright (c) 2007-2017 Hartmut Kaiser
2 //  Copyright (c)      2011 Bryce Lelbach
3 //  Copyright (c) 2011-2016 Thomas Heller
4 //
5 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
6 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 
8 /// \file transfer_action.hpp
9 
10 #ifndef HPX_RUNTIME_ACTIONS_TRANSFER_BASE_ACTION_HPP
11 #define HPX_RUNTIME_ACTIONS_TRANSFER_BASE_ACTION_HPP
12 
13 #include <hpx/runtime/actions_fwd.hpp>
14 
15 #include <hpx/runtime/actions/action_support.hpp>
16 #include <hpx/runtime/actions/base_action.hpp>
17 #include <hpx/runtime/actions/detail/invocation_count_registry.hpp>
18 #include <hpx/runtime/components/pinned_ptr.hpp>
19 #include <hpx/runtime/serialization/input_archive.hpp>
20 #include <hpx/runtime/serialization/output_archive.hpp>
21 #include <hpx/runtime/serialization/unique_ptr.hpp>
22 #include <hpx/traits/action_does_termination_detection.hpp>
23 #include <hpx/traits/action_message_handler.hpp>
24 #include <hpx/traits/action_priority.hpp>
25 #include <hpx/traits/action_schedule_thread.hpp>
26 #include <hpx/traits/action_serialization_filter.hpp>
27 #include <hpx/traits/action_stacksize.hpp>
28 #include <hpx/traits/action_was_object_migrated.hpp>
29 #include <hpx/util/assert.hpp>
30 #include <hpx/util/get_and_reset_value.hpp>
31 #include <hpx/util/serialize_exception.hpp>
32 #include <hpx/util/tuple.hpp>
33 #if HPX_HAVE_ITTNOTIFY != 0 && !defined(HPX_HAVE_APEX)
34 #include <hpx/util/itt_notify.hpp>
35 #endif
36 
37 #include <atomic>
38 #include <cstddef>
39 #include <cstdint>
40 #include <memory>
41 #include <type_traits>
42 #include <utility>
43 
44 namespace hpx { namespace actions
45 {
46     ///////////////////////////////////////////////////////////////////////////
47     // If one or more arguments of the action are non-default-constructible,
48     // the transfer_action does not store the argument tuple directly but a
49     // unique_ptr to the tuple instead.
50     namespace detail
51     {
52         template <typename Args>
53         struct argument_holder
54         {
55             argument_holder() = default;
56 
argument_holderhpx::actions::detail::argument_holder57             explicit argument_holder(Args && args)
58               : data_(new Args(std::move(args)))
59             {}
60 
61             template <typename ... Ts>
argument_holderhpx::actions::detail::argument_holder62             argument_holder(Ts && ... ts)
63               : data_(new Args(std::forward<Ts>(ts)...))
64             {}
65 
66             template <typename Archive>
serializehpx::actions::detail::argument_holder67             void serialize(Archive& ar, unsigned int const)
68             {
69                 ar & data_;
70             }
71 
72             HPX_HOST_DEVICE HPX_FORCEINLINE
datahpx::actions::detail::argument_holder73             Args& data()
74             {
75                 HPX_ASSERT(!!data_);
76                 return *data_;
77             }
78 
79 #if defined(HPX_DISABLE_ASSERTS) || defined(BOOST_DISABLE_ASSERTS) || defined(NDEBUG)
80             HPX_CONSTEXPR HPX_HOST_DEVICE HPX_FORCEINLINE
datahpx::actions::detail::argument_holder81             Args const& data() const
82             {
83                 return *data_;
84             }
85 #else
86             HPX_HOST_DEVICE HPX_FORCEINLINE
datahpx::actions::detail::argument_holder87             Args const& data() const
88             {
89                 HPX_ASSERT(!!data_);
90                 return *data_;
91             }
92 #endif
93 
94         private:
95             std::unique_ptr<Args> data_;
96         };
97     }
98 }}
99 
100 namespace hpx { namespace util
101 {
102     template <std::size_t I, typename Args>
103     HPX_CONSTEXPR HPX_HOST_DEVICE HPX_FORCEINLINE
104     typename util::tuple_element<I, Args>::type&
get(hpx::actions::detail::argument_holder<Args> & t)105     get(hpx::actions::detail::argument_holder<Args>& t)
106     {
107         return util::tuple_element<I, Args>::get(t.data());
108     }
109 
110     template <std::size_t I, typename Args>
111     HPX_CONSTEXPR HPX_HOST_DEVICE HPX_FORCEINLINE
112     typename util::tuple_element<I, Args>::type const&
get(hpx::actions::detail::argument_holder<Args> const & t)113     get(hpx::actions::detail::argument_holder<Args> const& t)
114     {
115         return util::tuple_element<I, Args>::get(t.data());
116     }
117 
118     template <std::size_t I, typename Args>
119     HPX_CONSTEXPR HPX_HOST_DEVICE HPX_FORCEINLINE
120     typename util::tuple_element<I, Args>::type&&
get(hpx::actions::detail::argument_holder<Args> && t)121     get(hpx::actions::detail::argument_holder<Args>&& t)
122     {
123         return std::forward<typename util::tuple_element<I, Args>::type>(
124             util::get<I>(t.data()));
125     }
126 
127     template <std::size_t I, typename Args>
128     HPX_CONSTEXPR HPX_HOST_DEVICE HPX_FORCEINLINE
129     typename util::tuple_element<I, Args>::type const&&
get(hpx::actions::detail::argument_holder<Args> const && t)130     get(hpx::actions::detail::argument_holder<Args> const&& t)
131     {
132         return std::forward<
133                 typename util::tuple_element<I, Args>::type const
134             >(util::get<I>(t.data()));
135     }
136 }}
137 
138 namespace hpx { namespace actions
139 {
140     ///////////////////////////////////////////////////////////////////////////
141     template <typename Action>
142     struct transfer_base_action : base_action_data
143     {
144     public:
145         HPX_NON_COPYABLE(transfer_base_action);
146 
147     public:
148         typedef typename Action::component_type component_type;
149         typedef typename Action::derived_type derived_type;
150         typedef typename Action::result_type result_type;
151         typedef typename Action::arguments_type arguments_base_type;
152         typedef typename std::conditional<
153                 std::is_constructible<arguments_base_type>::value,
154                     arguments_base_type,
155                     detail::argument_holder<arguments_base_type>
156             >::type arguments_type;
157         typedef typename Action::continuation_type continuation_type;
158 
159         // This is the priority value this action has been instantiated with
160         // (statically). This value might be different from the priority member
161         // holding the runtime value an action has been created with
162         HPX_STATIC_CONSTEXPR std::uint32_t priority_value =
163             traits::action_priority<Action>::value;
164 
165         // This is the stacksize value this action has been instantiated with
166         // (statically). This value might be different from the stacksize member
167         // holding the runtime value an action has been created with
168         HPX_STATIC_CONSTEXPR std::uint32_t stacksize_value =
169             traits::action_stacksize<Action>::value;
170 
171         typedef typename Action::direct_execution direct_execution;
172 
173         // construct an empty transfer_action to avoid serialization overhead
174         transfer_base_action() = default;
175 
176         // construct an action from its arguments
177         template <typename... Ts>
transfer_base_actionhpx::actions::transfer_base_action178         explicit transfer_base_action(Ts&&... vs)
179           : base_action_data(
180                 detail::thread_priority<static_cast<threads::thread_priority>(
181                     priority_value)>::call(threads::thread_priority_default),
182                 detail::thread_stacksize<static_cast<threads::thread_stacksize>(
183                     stacksize_value)>::call(threads::thread_stacksize_default))
184           , arguments_(std::forward<Ts>(vs)...)
185         {}
186 
187         template <typename ...Ts>
transfer_base_actionhpx::actions::transfer_base_action188         transfer_base_action(threads::thread_priority priority, Ts&&... vs)
189           : base_action_data(
190                 detail::thread_priority<static_cast<threads::thread_priority>(
191                     priority_value)>::call(priority),
192                 detail::thread_stacksize<static_cast<threads::thread_stacksize>(
193                     stacksize_value)>::call(threads::thread_stacksize_default))
194           , arguments_(std::forward<Ts>(vs)...)
195         {}
196 
197         //
~transfer_base_actionhpx::actions::transfer_base_action198         ~transfer_base_action() noexcept override
199         {
200             detail::register_action<derived_type>::instance.instantiate();
201         }
202 
203     public:
204         /// retrieve component type
get_static_component_typehpx::actions::transfer_base_action205         static int get_static_component_type()
206         {
207             return derived_type::get_component_type();
208         }
209 
210     private:
211         /// The function \a get_component_type returns the \a component_type
212         /// of the component this action belongs to.
get_component_typehpx::actions::transfer_base_action213         int get_component_type() const override
214         {
215             return derived_type::get_component_type();
216         }
217 
218         /// The function \a get_action_name returns the name of this action
219         /// (mainly used for debugging and logging purposes).
get_action_namehpx::actions::transfer_base_action220         char const* get_action_name() const override
221         {
222             return detail::get_action_name<derived_type>();
223         }
224 
225         /// The function \a get_serialization_id returns the id which has been
226         /// associated with this action (mainly used for serialization purposes).
get_action_idhpx::actions::transfer_base_action227         std::uint32_t get_action_id() const override
228         {
229             return detail::get_action_id<derived_type>();
230         }
231 
232 #if HPX_HAVE_ITTNOTIFY != 0 && !defined(HPX_HAVE_APEX)
233         /// The function \a get_action_name_itt returns the name of this action
234         /// as a ITT string_handle
get_action_name_itthpx::actions::transfer_base_action235         util::itt::string_handle const& get_action_name_itt() const override
236         {
237             return detail::get_action_name_itt<derived_type>();
238         }
239 #endif
240 
241         /// The function \a get_action_type returns whether this action needs
242         /// to be executed in a new thread or directly.
get_action_typehpx::actions::transfer_base_action243         action_type get_action_type() const override
244         {
245             return derived_type::get_action_type();
246         }
247 
248         /// Return whether the embedded action is part of termination detection
does_termination_detectionhpx::actions::transfer_base_action249         bool does_termination_detection() const override
250         {
251             return traits::action_does_termination_detection<derived_type>::call();
252         }
253 
254         /// Return whether the given object was migrated
255         std::pair<bool, components::pinned_ptr>
was_object_migratedhpx::actions::transfer_base_action256             was_object_migrated(hpx::naming::gid_type const& id,
257                 naming::address::address_type lva) override
258         {
259             return traits::action_was_object_migrated<derived_type>::call(id, lva);
260         }
261 
262         /// Return a pointer to the filter to be used while serializing an
263         /// instance of this action type.
get_serialization_filterhpx::actions::transfer_base_action264         serialization::binary_filter* get_serialization_filter(
265             parcelset::parcel const& p) const override
266         {
267             return traits::action_serialization_filter<derived_type>::call(p);
268         }
269 
270         /// Return a pointer to the message handler to be used for this action.
get_message_handlerhpx::actions::transfer_base_action271         parcelset::policies::message_handler* get_message_handler(
272             parcelset::parcelhandler* ph, parcelset::locality const& loc,
273             parcelset::parcel const& p) const override
274         {
275             return traits::action_message_handler<derived_type>::
276                 call(ph, loc, p);
277         }
278 
279     public:
280         /// retrieve the N's argument
281         template <std::size_t N>
282         HPX_CONSTEXPR inline
283         typename util::tuple_element<N, arguments_type>::type const&
gethpx::actions::transfer_base_action284         get() const
285         {
286             return util::get<N>(arguments_);
287         }
288 
289         /// Extract the current invocation count for this action
get_invocation_counthpx::actions::transfer_base_action290         static std::int64_t get_invocation_count(bool reset)
291         {
292             return util::get_and_reset_value(invocation_count_, reset);
293         }
294 
295         // serialization support
296         // loading ...
load_basehpx::actions::transfer_base_action297         void load_base(hpx::serialization::input_archive & ar)
298         {
299             ar >> arguments_;
300             this->base_action_data::load_base(ar);
301         }
302 
303         // saving ...
save_basehpx::actions::transfer_base_action304         void save_base(hpx::serialization::output_archive & ar)
305         {
306             ar << arguments_;
307             this->base_action_data::save_base(ar);
308         }
309 
310     protected:
311         arguments_type arguments_;
312 
313     private:
314         static std::atomic<std::int64_t> invocation_count_;
315 
316     protected:
increment_invocation_counthpx::actions::transfer_base_action317         static void increment_invocation_count()
318         {
319             ++invocation_count_;
320         }
321     };
322 
323     template <typename Action>
324     std::atomic<std::int64_t>
325         transfer_base_action<Action>::invocation_count_(0);
326 
327     namespace detail
328     {
329         template <typename Action>
register_remote_action_invocation_count(invocation_count_registry & registry)330         void register_remote_action_invocation_count(
331             invocation_count_registry& registry)
332         {
333             registry.register_class(
334                 hpx::actions::detail::get_action_name<Action>(),
335                 &transfer_base_action<Action>::get_invocation_count
336             );
337         }
338     }
339 
340     ///////////////////////////////////////////////////////////////////////////
341     template <std::size_t N, typename Action>
342     HPX_CONSTEXPR inline typename util::tuple_element<
343         N, typename transfer_action<Action>::arguments_type
get(transfer_base_action<Action> const & args)344     >::type const& get(transfer_base_action<Action> const& args)
345     {
346         return args.template get<N>();
347     }
348 }}
349 
350 #if defined(HPX_HAVE_PARCELPORT_ACTION_COUNTERS)
351 #include <hpx/runtime/parcelset/detail/per_action_data_counter_registry.hpp>
352 
353 namespace hpx { namespace parcelset { namespace detail
354 {
355     /// \cond NOINTERNAL
356     template <typename Action>
register_per_action_data_counter_types(per_action_data_counter_registry & registry)357     void register_per_action_data_counter_types(
358         per_action_data_counter_registry& registry)
359     {
360         registry.register_class(
361             hpx::actions::detail::get_action_name<Action>()
362         );
363     }
364     /// \endcond
365 }}}
366 #endif
367 
368 #endif
369