/home/users/khuck/src/hpx-lsu/hpx/runtime/components/server/managed_component_base.hpp

Line% of fetchesSource
1  
//  Copyright (c) 2007-2016 Hartmut Kaiser
2  
//  Copyright (c)      2011 Thomas Heller
3  
//
4  
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
5  
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
7  
#if !defined(HPX_COMPONENTS_MANAGED_COMPONENT_BASE_JUN_04_2008_0902PM)
8  
#define HPX_COMPONENTS_MANAGED_COMPONENT_BASE_JUN_04_2008_0902PM
9  
10  
#include <hpx/config.hpp>
11  
12  
#include <hpx/runtime/components/component_type.hpp>
13  
#include <hpx/runtime/components/server/create_component_fwd.hpp>
14  
#include <hpx/runtime/components/server/wrapper_heap.hpp>
15  
#include <hpx/runtime/components/server/wrapper_heap_list.hpp>
16  
#include <hpx/runtime/components_fwd.hpp>
17  
#include <hpx/throw_exception.hpp>
18  
#include <hpx/traits/is_component.hpp>
19  
#include <hpx/traits/managed_component_policies.hpp>
20  
#include <hpx/util/reinitializable_static.hpp>
21  
#include <hpx/util/unique_function.hpp>
22  
23  
#include <cstddef>
24  
#include <cstdint>
25  
#include <sstream>
26  
#include <stdexcept>
27  
#include <type_traits>
28  
#include <utility>
29  
30  
///////////////////////////////////////////////////////////////////////////////
31  
namespace hpx { namespace components
32  
{
33  
    template <typename Component, typename Derived>
34  
    class managed_component;
35  
36  
    ///////////////////////////////////////////////////////////////////////////
37  
    namespace detail_adl_barrier
38  
    {
39  
        template <typename BackPtrTag>
40  
        struct init;
41  
42  
        template <>
43  
        struct init<traits::construct_with_back_ptr>
44  
        {
45  
            template <typename Component, typename Managed>
46  
            static void call(Component* component, Managed* this_)
47  
            {
48  
            }
49  
50  
            template <typename Component, typename Managed, typename ...Ts>
51  
            static void call_new(Component*& component, Managed* this_, Ts&&... vs)
52  
            {
53  
                typedef typename Managed::wrapped_type wrapped_type;
54  
                component = new wrapped_type(this_, std::forward<Ts>(vs)...);
55  
            }
56  
        };
57  
58  
        template <>
59  
        struct init<traits::construct_without_back_ptr>
60  
        {
61  
            template <typename Component, typename Managed>
62  
            static void call(Component* component, Managed* this_)
63  
            {
64  
                component->set_back_ptr(this_);
65  
            }
66  
67  
            template <typename Component, typename Managed, typename ...Ts>
68  
            static void call_new(Component*& component, Managed* this_, Ts&&... vs)
69  
            {
70  
                typedef typename Managed::wrapped_type wrapped_type;
71  
                component = new wrapped_type(std::forward<Ts>(vs)...);
72  
                component->set_back_ptr(this_);
73  
            }
74  
        };
75  
76  
        ///////////////////////////////////////////////////////////////////////
77  
        // This is used by the component implementation to decide whether to
78  
        // delete the managed_component instance it depends on.
79  
        template <typename DtorTag>
80  
        struct destroy_backptr;
81  
82  
        template <>
83  
        struct destroy_backptr<traits::managed_object_is_lifetime_controlled>
84  
        {
85  
            template <typename BackPtr>
86  
            static void call(BackPtr* back_ptr)
87  
            {
88  
                // The managed_component's controls the lifetime of the
89  
                // component implementation.
90  
                delete back_ptr;
91  
            }
92  
        };
93  
94  
        template <>
95  
        struct destroy_backptr<traits::managed_object_controls_lifetime>
96  
        {
97  
            template <typename BackPtr>
98  
            static void call(BackPtr*)
99  
            {
100  
                // The managed_component's lifetime is controlled by the
101  
                // component implementation. Do nothing.
102  
            }
103  
        };
104  
105  
        ///////////////////////////////////////////////////////////////////////
106  
        // This is used by the managed_component to decide whether to
107  
        // delete the component implementation depending on it.
108  
        template <typename DtorTag>
109  
        struct manage_lifetime;
110  
111  
        template <>
112  
        struct manage_lifetime<traits::managed_object_is_lifetime_controlled>
113  
        {
114  
            template <typename Component>
115  
            static void call(Component*)
116  
            {
117  
                // The managed_component's lifetime is controlled by the
118  
                // component implementation. Do nothing.
119  
            }
120  
121  
            template <typename Component>
122  
            static void addref(Component* component)
123  
            {
124  
                intrusive_ptr_add_ref(component);
125  
            }
126  
127  
            template <typename Component>
128  
            static void release(Component* component)
129  
            {
130  
                intrusive_ptr_release(component);
131  
            }
132  
        };
133  
134  
        template <>
135  
        struct manage_lifetime<traits::managed_object_controls_lifetime>
136  
        {
137  
            template <typename Component>
138  
            static void call(Component* component)
139  
            {
140  
                // The managed_component controls the lifetime of the
141  
                // component implementation.
142  
                component->finalize();
143  
                delete component;
144  
            }
145  
146  
            template <typename Component>
147  
            static void addref(Component*)
148  
            {
149  
            }
150  
151  
            template <typename Component>
152  
            static void release(Component*)
153  
            {
154  
            }
155  
        };
156  
    }
157  
158  
    ///////////////////////////////////////////////////////////////////////////
159  
    template <typename Component, typename Wrapper,
160  
        typename CtorPolicy, typename DtorPolicy>
161  
    class managed_component_base
162  
      : public traits::detail::managed_component_tag
163  
    {
164  
        HPX_NON_COPYABLE(managed_component_base);
165  
166  
    private:
167  
        Component& derived()
168  
        {
169  
            return static_cast<Component&>(*this);
170  
        }
171  
        Component const& derived() const
172  
        {
173  
            return static_cast<Component const&>(*this);
174  
        }
175  
176  
    public:
177  
        typedef typename std::conditional<
178  
            std::is_same<Component, detail::this_type>::value,
179  
            managed_component_base, Component
180  
        >::type this_component_type;
181  
182  
        typedef this_component_type wrapped_type;
183  
184  
        typedef void has_managed_component_base;
185  
        typedef CtorPolicy ctor_policy;
186  
        typedef DtorPolicy dtor_policy;
187  
188  
        // make sure that we have a back_ptr whenever we need to control the
189  
        // lifetime of the managed_component
190  
        static_assert((
191  
            std::is_same<ctor_policy, traits::construct_without_back_ptr>::value ||
192  
            std::is_same<dtor_policy,
193  
            traits::managed_object_controls_lifetime>::value),
194  
            "std::is_same<ctor_policy, traits::construct_without_back_ptr>::value || "
195  
            "std::is_same<dtor_policy, "
196  
            "traits::managed_object_controls_lifetime>::value");
197  
198  
        managed_component_base()
199  
          : back_ptr_(nullptr)
200  
        {}
201  
202  
        managed_component_base(managed_component<Component, Wrapper>* back_ptr)
203  
          : back_ptr_(back_ptr)
204  
        {
205  
            HPX_ASSERT(back_ptr);
206  
        }
207  
208  
        // The implementation of the component is responsible for deleting the
209  
        // actual managed component object
210  
        ~managed_component_base()
211  
        {
212  
            detail_adl_barrier::destroy_backptr<dtor_policy>::call(back_ptr_);
213  
        }
214  
215  
        // components must contain a typedef for wrapping_type defining the
216  
        // managed_component type used to encapsulate instances of this
217  
        // component
218  
        typedef managed_component<Component, Wrapper> wrapping_type;
219  
        typedef Component base_type_holder;
220  
221  
        /// \brief finalize() will be called just before the instance gets
222  
        ///        destructed
223  
        void finalize() {}
224  
225  
        // This exposes the component type
226  
        static component_type get_component_type()
227  
        {
228  
            return components::get_component_type<Component>();
229  
        }
230  
        static void set_component_type(component_type type)
231  
        {
232  
            components::set_component_type<Component>(type);
233  
        }
234  
235  
        naming::id_type get_unmanaged_id() const;
236  
        naming::id_type get_id() const;
237  
238  
#if defined(HPX_HAVE_COMPONENT_GET_GID_COMPATIBILITY)
239  
        naming::id_type get_gid() const
240  
        {
241  
            return get_unmanaged_id();
242  
        }
243  
#endif
244  
245  
    protected:
246  
        naming::gid_type get_base_gid() const;
247  
248  
    public:
249  
        // Pinning functionality
250  
        void pin() {}
251  
        void unpin() {}
252  
        std::uint32_t pin_count() const { return 0; }
253  
254  
        void mark_as_migrated()
255  
        {
256  
            // If this assertion is triggered then this component instance is
257  
            // being migrated even if the component type has not been enabled
258  
            // to support migration.
259  
            HPX_ASSERT(false);
260  
        }
261  
262  
    protected:
263  
        template <typename>
264  
        friend struct detail_adl_barrier::init;
265  
266  
        void set_back_ptr(components::managed_component<Component, Wrapper>* bp)
267  
        {
268  
            HPX_ASSERT(nullptr == back_ptr_);
269  
            HPX_ASSERT(bp);
270  
            back_ptr_ = bp;
271  
        }
272  
273  
    private:
274  
        managed_component<Component, Wrapper>* back_ptr_;
275  
    };
276  
277  
    ///////////////////////////////////////////////////////////////////////////
278  
    namespace detail
279  
    {
280  
        ///////////////////////////////////////////////////////////////////////
281  
        template <typename Component, typename Derived>
282  
        struct heap_factory
283  
        {
284  
            // the memory for the wrappers is managed by a one_size_heap_list
285  
            typedef detail::wrapper_heap_list<
286  
                detail::fixed_wrapper_heap<Derived> > heap_type;
287  
288  
            typedef detail::fixed_wrapper_heap<Derived> block_type;
289  
            typedef Derived value_type;
290  
291  
        private:
292  
            struct wrapper_heap_tag {};
293  
294  
            static heap_type& get_heap()
295  
            {
296  
                // ensure thread-safe initialization
297  
                util::reinitializable_static<
298  
                    heap_type, wrapper_heap_tag
299  
                > heap(components::get_component_type<Component>());
300  
                return heap.get();
301  
            }
302  
303  
        public:
304  
            static void* alloc(std::size_t count = 1)
305  
            {
306  
                return get_heap().alloc(count);
307  
            }
308  
            static void free(void* p, std::size_t count = 1)
309  
            {
310  
                get_heap().free(p, count);
311  
            }
312  
            static naming::gid_type get_gid(void* p)
313  
            {
314  
                return get_heap().get_gid(p);
315  
            }
316  
        };
317  
    }
318  
    // reference counting
319  
    template <typename Component, typename Derived>
320  
    void intrusive_ptr_add_ref(managed_component<Component, Derived>* p)
321  
    {
322  
        detail_adl_barrier::manage_lifetime<
323  
            typename traits::managed_component_dtor_policy<Component>::type
324  
        >::addref(p->component_);
325  
    }
326  
    template <typename Component, typename Derived>
327  
    void intrusive_ptr_release(managed_component<Component, Derived>* p)
328  
    {
329  
        detail_adl_barrier::manage_lifetime<
330  
            typename traits::managed_component_dtor_policy<Component>::type
331  
        >::release(p->component_);
332  
    }
333  
334  
    ///////////////////////////////////////////////////////////////////////////
335  
    /// The managed_component template is used as a indirection layer
336  
    /// for components allowing to gracefully handle the access to non-existing
337  
    /// components.
338  
    ///
339  
    /// Additionally it provides memory management capabilities for the
340  
    /// wrapping instances, and it integrates the memory management with the
341  
    /// AGAS service. Every instance of a managed_component gets assigned
342  
    /// a global id.
343  
    /// The provided memory management allocates the managed_component
344  
    /// instances from a special heap, ensuring fast allocation and avoids a
345  
    /// full network round trip to the AGAS service for each of the allocated
346  
    /// instances.
347  
    ///
348  
    /// \tparam Component
349  
    /// \tparam Derived
350  
    ///
351  
    template <typename Component, typename Derived>
352  
    class managed_component
353  
    {
354  
        HPX_NON_COPYABLE(managed_component);
355  
356  
    public:
357  
        typedef typename std::conditional<
358  
                std::is_same<Derived, detail::this_type>::value,
359  
                managed_component, Derived
360  
            >::type derived_type;
361  
362  
        typedef Component wrapped_type;
363  
        typedef Component type_holder;
364  
        typedef typename Component::base_type_holder base_type_holder;
365  
366  
        typedef detail::heap_factory<Component, derived_type> heap_type;
367  
        typedef typename heap_type::value_type value_type;
368  
369  
        /// \brief Construct a managed_component instance holding a
370  
        ///        wrapped instance. This constructor takes ownership of the
371  
        ///        passed pointer.
372  
        ///
373  
        /// \param c    [in] The pointer to the wrapped instance. The
374  
        ///             managed_component takes ownership of this pointer.
375  
        explicit managed_component(Component* comp)
376  
          : component_(comp)
377  
        {
378  
            detail_adl_barrier::init<
379  
                typename traits::managed_component_ctor_policy<Component>::type
380  
            >::call(component_, this);
381  
            intrusive_ptr_add_ref(this);
382  
        }
383  
384  
    public:
385  
        /// \brief Construct a managed_component instance holding a new wrapped
386  
        ///        instance
387  
        template <typename ...Ts>
388  
        managed_component(Ts&&... vs)
389  
          : component_(nullptr)
390  
        {
391  
            detail_adl_barrier::init<
392  
                typename traits::managed_component_ctor_policy<Component>::type
393  
            >::call_new(component_, this, std::forward<Ts>(vs)...);
394  
            intrusive_ptr_add_ref(this);
395  
        }
396  
397  
    public:
398  
        /// \brief The destructor releases any wrapped instances
399  
        ~managed_component()
400  
        {
401  
            intrusive_ptr_release(this);
402  
            detail_adl_barrier::manage_lifetime<
403  
                typename traits::managed_component_dtor_policy<Component>::type
404  
            >::call(component_);
405  
        }
406  
407  
        /// \brief finalize() will be called just before the instance gets
408  
        ///        destructed
409  
        void finalize() {}  // finalize the wrapped component in our destructor
410  
411  
        static component_type get_component_type()
412  
        {
413  
            return components::get_component_type<wrapped_type>();
414  
        }
415  
        static void set_component_type(component_type t)
416  
        {
417  
            components::set_component_type<wrapped_type>(t);
418  
        }
419  
420  
        /// \brief Return a pointer to the wrapped instance
421  
        /// \note  Caller must check validity of returned pointer
422  
        Component* get()
423  
        {
424  
            return component_;
425  
        }
426  
        Component const* get() const
427  
        {
428  
            return component_;
429  
        }
430  
431  
        Component* get_checked()
432  
        {
433  
            if (!component_) {
434  
                std::ostringstream strm;
435  
                strm << "component is nullptr ("
436  
                     << components::get_component_type_name(
437  
                        components::get_component_type<wrapped_type>())
438  
                     << ") gid(" << get_base_gid() << ")";
439  
                HPX_THROW_EXCEPTION(invalid_status,
440  
                    "managed_component<Component, Derived>::get_checked",
441  
                    strm.str());
442  
            }
443  
            return get();
444  
        }
445  
446  
        Component const* get_checked() const
447  
        {
448  
            if (!component_) {
449  
                std::ostringstream strm;
450  
                strm << "component is nullptr ("
451  
                     << components::get_component_type_name(
452  
                        components::get_component_type<wrapped_type>())
453  
                     << ") gid(" << get_base_gid() << ")";
454  
                HPX_THROW_EXCEPTION(invalid_status,
455  
                    "managed_component<Component, Derived>::get_checked",
456  
                    strm.str());
457  
            }
458  
            return get();
459  
        }
460  
461  
    public:
462  
        /// \brief  The memory for managed_component objects is managed by
463  
        ///         a class specific allocator. This allocator uses a one size
464  
        ///         heap implementation, ensuring fast memory allocation.
465  
        ///         Additionally the heap registers the allocated
466  
        ///         managed_component instance with the AGAS service.
467  
        ///
468  
        /// \param size   [in] The parameter \a size is supplied by the
469  
        ///               compiler and contains the number of bytes to allocate.
470  
        static void* operator new(std::size_t size)
471  
        {
472  
            if (size > sizeof(managed_component))
473  
                return ::operator new(size);
474  
            void* p = heap_type::alloc();
475  
            if (nullptr == p) {
476  
                HPX_THROW_STD_EXCEPTION(std::bad_alloc(),
477  
                    "managed_component::operator new(std::size_t size)");
478  
            }
479  
            return p;
480  
        }
481  
        static void operator delete(void* p, std::size_t size)
482  
        {
483  
            if (nullptr == p)
484  
                return;     // do nothing if given a nullptr pointer
485  
486  
            if (size != sizeof(managed_component)) {
487  
                ::operator delete(p);
488  
                return;
489  
            }
490  
            heap_type::free(p);
491  
        }
492  
493  
        /// \brief  The placement operator new has to be overloaded as well
494  
        ///         (the global placement operators are hidden because of the
495  
        ///         new/delete overloads above).
496  
        static void* operator new(std::size_t, void *p)
497  
        {
498  
            return p;
499  
        }
500  
        /// \brief  This operator delete is called only if the placement new
501  
        ///         fails.
502  
        static void operator delete(void*, void*)
503  
        {}
504  
505  
        /// \brief  The function \a create is used for allocation and
506  
        //          initialization of arrays of wrappers.
507  
        static value_type* create(std::size_t count = 1)
508  
        {
509  
            // allocate the memory
510  
            void* p = heap_type::alloc(count);
511  
            if (nullptr == p) {
512  
                HPX_THROW_STD_EXCEPTION(std::bad_alloc(),
513  
                    "managed_component::create");
514  
            }
515  
516  
            if (1 == count)
517  
                return new (p) value_type();
518  
519  
            // call constructors
520  
            std::size_t succeeded = 0;
521  
            try {
522  
                value_type* curr = reinterpret_cast<value_type*>(p);
523  
                for (std::size_t i = 0; i != count; ++i, ++curr) {
524  
                    // call placement new, might throw
525  
                    new (curr) value_type();
526  
                    ++succeeded;
527  
                }
528  
            }
529  
            catch (...) {
530  
                // call destructors for successfully constructed objects
531  
                value_type* curr = reinterpret_cast<value_type*>(p);
532  
                for (std::size_t i = 0; i != succeeded; ++i)
533  
                {
534  
                    curr->finalize();
535  
                    curr->~derived_type();
536  
                    ++curr;
537  
                }
538  
                heap_type::free(p, count);     // free memory
539  
                throw;      // rethrow
540  
            }
541  
            return reinterpret_cast<value_type*>(p);
542  
        }
543  
544  
        /// \brief  The function \a destroy is used for deletion and
545  
        //          de-allocation of arrays of wrappers
546  
        static void destroy(value_type* p, std::size_t count = 1)
547  
        {
548  
            if (nullptr == p || 0 == count)
549  
                return;     // do nothing if given a nullptr pointer
550  
551  
            // call destructors for all managed_component instances
552  
            value_type* curr = p;
553  
            for (std::size_t i = 0; i != count; ++i)
554  
            {
555  
                curr->finalize();
556  
                curr->~derived_type();
557  
                ++curr;
558  
            }
559  
560  
            // free memory itself
561  
            heap_type::free(p, count);
562  
        }
563  
564  
#if defined(HPX_HAVE_SECURITY)
565  
        static components::security::capability get_required_capabilities(
566  
            components::security::traits::capability<>::capabilities caps)
567  
        {
568  
            return components::default_component_creation_capabilities(caps);
569  
        }
570  
#endif
571  
572  
    public:
573  
        ///////////////////////////////////////////////////////////////////////
574  
        // The managed_component behaves just like the wrapped object
575  
        Component* operator-> ()
576  
        {
577  
            return get_checked();
578  
        }
579  
580  
        Component const* operator-> () const
581  
        {
582  
            return get_checked();
583  
        }
584  
585  
        ///////////////////////////////////////////////////////////////////////
586  
        Component& operator* ()
587  
        {
588  
            return *get_checked();
589  
        }
590  
591  
        Component const& operator* () const
592  
        {
593  
            return *get_checked();
594  
        }
595  
596  
        ///////////////////////////////////////////////////////////////////////
597  
        /// \brief Return the global id of this \a future instance
598  
        naming::id_type get_unmanaged_id() const
599  
        {
600  
            return naming::id_type(get_base_gid(), naming::id_type::unmanaged);
601  
        }
602  
603  
#if defined(HPX_HAVE_COMPONENT_GET_GID_COMPATIBILITY)
604  
        naming::id_type get_gid() const
605  
        {
606  
            return get_unmanaged_id();
607  
        }
608  
#endif
609  
610  
#if defined(HPX_HAVE_CXX11_EXTENDED_FRIEND_DECLARATIONS) && !defined(__CUDACC__)
611  
    private:
612  
        // declare friends which are allowed to access get_base_gid()
613  
        friend Component;
614  
615  
        template <typename Component_, typename Wrapper_,
616  
            typename CtorPolicy, typename DtorPolicy>
617  
        friend class managed_component_base;
618  
619  
        template <typename Component_>
620  
        friend naming::gid_type server::create(std::size_t count);
621  
622  
        template <typename Component_>
623  
        friend naming::gid_type server::create(
624  
            util::unique_function_nonser<void(void*)> const& ctor);
625  
626  
        template <typename Component_>
627  
        friend naming::gid_type server::create(naming::gid_type const& gid,
628  
            util::unique_function_nonser<void(void*)> const& ctor);
629  
#endif
630  
631  
        naming::gid_type get_base_gid(
632  
            naming::gid_type const& assign_gid = naming::invalid_gid) const
633  
        {
634  
            if (assign_gid)
635  
            {
636  
                HPX_THROW_EXCEPTION(bad_parameter,
637  
                    "managed_component::get_base_gid",
638  
                    "managed_components must be assigned new gids on creation");
639  
                return naming::invalid_gid;
640  
            }
641  
            return heap_type::get_gid(const_cast<managed_component*>(this));
642  
        }
643  
644  
    public:
645  
        // reference counting
646  
        template<typename C, typename D>
647  
        friend void intrusive_ptr_add_ref(managed_component<C, D>* p);
648  
649  
        template<typename C, typename D>
650  
        friend void intrusive_ptr_release(managed_component<C, D>* p);
651  
652  
    protected:
653  
        Component* component_;
654  
    };
655  
656  
    ///////////////////////////////////////////////////////////////////////////
657  
    template <typename Component, typename Wrapper,
658  
        typename CtorPolicy, typename DtorPolicy>
659  
    inline naming::id_type
660  
    managed_component_base<Component, Wrapper, CtorPolicy, DtorPolicy>::
661  
        get_unmanaged_id() const
662  
    {
663  
        HPX_ASSERT(back_ptr_);
664  
        return back_ptr_->get_unmanaged_id();
665  
    }
666  
667  
    template <typename Component, typename Wrapper,
668  
        typename CtorPolicy, typename DtorPolicy>
669  
    inline naming::id_type
670  
    managed_component_base<Component, Wrapper, CtorPolicy, DtorPolicy>::
671  
        get_id() const
672  
    {
673  
        // all credits should have been taken already
674  
        naming::gid_type gid = derived().get_base_gid();
675  
676  
        // The underlying heap will always give us a full set of credits, but
677  
        // those are valid for the first invocation of get_base_gid() only.
678  
        // We have to get rid of those credits and properly replenish those.
679  
        naming::detail::strip_credits_from_gid(gid);
680  
681  
        // any invocation causes the credits to be replenished
682  
        naming::detail::replenish_credits(gid);
683  
        return naming::id_type(gid, naming::id_type::managed);
684  
    }
685  
686  
    template <typename Component, typename Wrapper,
687  
        typename CtorPolicy, typename DtorPolicy>
688  
    inline naming::gid_type
689  
    managed_component_base<Component, Wrapper, CtorPolicy, DtorPolicy>::
690  
        get_base_gid() const
691  
    {
692  
        HPX_ASSERT(back_ptr_);
693  
        return back_ptr_->get_base_gid();
694  
    }
695  
}}
696  
697  
#endif
698  
699  
700  

Copyright (c) 2006-2012 Rogue Wave Software, Inc. All Rights Reserved.
Patents pending.