1 //  Copyright (c) 2007-2018 Hartmut Kaiser
2 //  Copyright (c) 2011 Bryce Lelbach
3 //  Copyright (c) 2007 Richard D. Guidry Jr.
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 #ifndef HPX_RUNTIME_NAMING_NAME_HPP
9 #define HPX_RUNTIME_NAMING_NAME_HPP
10 
11 #include <hpx/config.hpp>
12 #include <hpx/lcos/local/spinlock.hpp>
13 #include <hpx/lcos/local/spinlock_pool.hpp>
14 #include <hpx/runtime/naming/id_type.hpp>
15 #include <hpx/runtime/naming_fwd.hpp>
16 #include <hpx/runtime/serialization/serialization_fwd.hpp>
17 #include <hpx/traits/get_remote_result.hpp>
18 #include <hpx/traits/is_bitwise_serializable.hpp>
19 #include <hpx/traits/promise_local_result.hpp>
20 #include <hpx/util/assert.hpp>
21 #include <hpx/util/atomic_count.hpp>
22 #include <hpx/util/detail/yield_k.hpp>
23 #include <hpx/util/itt_notify.hpp>
24 #include <hpx/util/register_locks.hpp>
25 
26 #include <cstddef>
27 #include <cstdint>
28 #include <functional>
29 #include <iosfwd>
30 #include <mutex>
31 #include <string>
32 #include <vector>
33 
34 #include <hpx/config/warnings_prefix.hpp>
35 
36 ///////////////////////////////////////////////////////////////////////////////
37 // Version of id_type
38 #define HPX_IDTYPE_VERSION  0x20
39 #define HPX_GIDTYPE_VERSION 0x10
40 
41 ///////////////////////////////////////////////////////////////////////////////
42 namespace hpx { namespace naming
43 {
44     namespace detail
45     {
46         ///////////////////////////////////////////////////////////////////////
47         // forward declaration
48         inline std::uint64_t strip_internal_bits_from_gid(std::uint64_t msb)
49             HPX_SUPER_PURE;
50 
51         inline std::uint64_t strip_internal_bits_and_component_type_from_gid(
52             std::uint64_t msb) HPX_SUPER_PURE;
53 
54         inline std::uint64_t strip_lock_from_gid(std::uint64_t msb)
55             HPX_SUPER_PURE;
56 
57         inline std::uint64_t get_internal_bits(std::uint64_t msb)
58             HPX_SUPER_PURE;
59 
60         inline std::uint64_t strip_internal_bits_and_locality_from_gid(
61                 std::uint64_t msb) HPX_SUPER_PURE;
62 
63         inline bool is_locked(gid_type const& gid);
64     }
65 
66     ///////////////////////////////////////////////////////////////////////////
67     /// Global identifier for components across the HPX system.
68     struct HPX_EXPORT gid_type
69     {
70         struct tag {};
71 
72         // These typedefs are for Boost.ICL.
73         typedef gid_type size_type;
74         typedef gid_type difference_type;
75 
76         static std::uint64_t const credit_base_mask = 0x1full;
77         static std::uint16_t const credit_shift = 24;
78 
79         static std::uint64_t const credit_mask = credit_base_mask << credit_shift;
80         static std::uint64_t const was_split_mask = 0x80000000ull; //-V112
81         static std::uint64_t const has_credits_mask = 0x40000000ull; //-V112
82         static std::uint64_t const is_locked_mask = 0x20000000ull; //-V112
83 
84         static std::uint64_t const locality_id_mask = 0xffffffff00000000ull;
85         static std::uint16_t const locality_id_shift = 32; //-V112
86 
87         static std::uint64_t const virtual_memory_mask = 0x3fffffull;
88 
89         // don't cache this id in the AGAS caches
90         static std::uint64_t const dont_cache_mask = 0x800000ull; //-V112
91 
92         // the object is migratable
93         static std::uint64_t const is_migratable = 0x400000ull; //-V112
94 
95         // Bit 64 is set for all dynamically assigned ids (if this is not set
96         // then the lsb corresponds to the lva of the referenced object).
97         static std::uint64_t const dynamically_assigned = 0x1ull;
98 
99         // Bits 65-84 are used to store the component type (20 bits) if bit
100         // 64 is not set.
101         static std::uint64_t const component_type_base_mask = 0xfffffull;
102         static std::uint64_t const component_type_shift = 1ull;
103         static std::uint64_t const component_type_mask =
104             component_type_base_mask << component_type_shift;
105 
106         static std::uint64_t const credit_bits_mask =
107             credit_mask | was_split_mask | has_credits_mask;
108         static std::uint64_t const internal_bits_mask = credit_bits_mask |
109             is_locked_mask | dont_cache_mask | is_migratable;
110         static std::uint64_t const special_bits_mask =
111             locality_id_mask | internal_bits_mask | component_type_mask;
112 
gid_typehpx::naming::gid_type113         explicit gid_type (std::uint64_t lsb_id = 0)
114           : id_msb_(0), id_lsb_(lsb_id)
115         {}
116 
gid_typehpx::naming::gid_type117         explicit gid_type (std::uint64_t msb_id, std::uint64_t lsb_id)
118           : id_msb_(naming::detail::strip_lock_from_gid(msb_id)),
119             id_lsb_(lsb_id)
120         {
121         }
122 
gid_typehpx::naming::gid_type123         gid_type (gid_type const& rhs)
124           : id_msb_(naming::detail::strip_lock_from_gid(rhs.get_msb())),
125             id_lsb_(rhs.get_lsb())
126         {
127         }
gid_typehpx::naming::gid_type128         gid_type (gid_type && rhs)
129           : id_msb_(naming::detail::strip_lock_from_gid(rhs.get_msb())),
130             id_lsb_(rhs.get_lsb())
131         {
132             rhs.id_lsb_ = rhs.id_msb_ = 0;
133         }
134 
~gid_typehpx::naming::gid_type135         ~gid_type()
136         {
137             HPX_ASSERT(!is_locked());
138         }
139 
operator =hpx::naming::gid_type140         gid_type& operator=(std::uint64_t lsb_id)
141         {
142             HPX_ASSERT(!is_locked());
143             id_msb_ = 0;
144             id_lsb_ = lsb_id;
145             return *this;
146         }
147 
operator =hpx::naming::gid_type148         gid_type& operator=(gid_type const& rhs)
149         {
150             if (this != &rhs)
151             {
152                 HPX_ASSERT(!is_locked());
153                 id_msb_ = naming::detail::strip_lock_from_gid(rhs.get_msb());
154                 id_lsb_ = rhs.get_lsb();
155             }
156             return *this;
157         }
operator =hpx::naming::gid_type158         gid_type& operator=(gid_type && rhs)
159         {
160             if (this != &rhs)
161             {
162                 HPX_ASSERT(!is_locked());
163                 id_msb_ = naming::detail::strip_lock_from_gid(rhs.get_msb());
164                 id_lsb_ = rhs.get_lsb();
165 
166                 rhs.id_lsb_ = rhs.id_msb_ = 0;
167             }
168             return *this;
169         }
170 
operator boolhpx::naming::gid_type171         explicit operator bool() const noexcept
172         {
173             return 0 != id_lsb_ || 0 != id_msb_;
174         }
175 
176         // We support increment, decrement, addition and subtraction
operator ++hpx::naming::gid_type177         gid_type& operator++()       // pre-increment
178         {
179             *this += 1;
180             return *this;
181         }
operator ++hpx::naming::gid_type182         gid_type operator++(int)     // post-increment
183         {
184             gid_type t(*this);
185             ++(*this);
186             return t;
187         }
188 
operator --hpx::naming::gid_type189         gid_type& operator--()       // pre-decrement
190         {
191             *this -= 1;
192             return *this;
193         }
operator --hpx::naming::gid_type194         gid_type operator--(int)     // post-decrement
195         {
196             gid_type t(*this);
197             --(*this);
198             return t;
199         }
200 
201         // GID + GID
202         friend HPX_EXPORT gid_type operator+ (
203             gid_type const& lhs, gid_type const& rhs);
operator +=hpx::naming::gid_type204         gid_type operator+= (gid_type const& rhs)
205         { return (*this = *this + rhs); }
206 
207         // GID + std::uint64_t
operator +(gid_type const & lhs,std::uint64_t rhs)208         friend gid_type operator+ (gid_type const& lhs, std::uint64_t rhs)
209         { return lhs + gid_type(0, rhs); }
operator +=hpx::naming::gid_type210         gid_type operator+= (std::uint64_t rhs)
211         { return (*this = *this + rhs); }
212 
213         // GID - GID
214         friend HPX_EXPORT gid_type operator- (gid_type const& lhs,
215             gid_type const& rhs);
operator -=hpx::naming::gid_type216         gid_type operator-= (gid_type const& rhs)
217         { return (*this = *this - rhs); }
218 
219         // GID - std::uint64_t
operator -(gid_type const & lhs,std::uint64_t rhs)220         friend gid_type operator- (gid_type const& lhs, std::uint64_t rhs)
221         { return lhs - gid_type(0, rhs); }
operator -=hpx::naming::gid_type222         gid_type operator-= (std::uint64_t rhs)
223         { return (*this = *this - rhs); }
224 
operator &(gid_type const & lhs,std::uint64_t rhs)225         friend gid_type operator& (gid_type const& lhs, std::uint64_t rhs)
226         {
227             return gid_type(lhs.id_msb_, lhs.id_lsb_ & rhs);
228         }
229 
230         // comparison is required as well
operator ==(gid_type const & lhs,gid_type const & rhs)231         friend bool operator== (gid_type const& lhs, gid_type const& rhs)
232         {
233             std::int64_t lhs_msb =
234                 detail::strip_internal_bits_from_gid(lhs.id_msb_);
235             std::int64_t rhs_msb =
236                 detail::strip_internal_bits_from_gid(rhs.id_msb_);
237 
238             return (lhs_msb == rhs_msb) && (lhs.id_lsb_ == rhs.id_lsb_);
239         }
operator !=(gid_type const & lhs,gid_type const & rhs)240         friend bool operator!= (gid_type const& lhs, gid_type const& rhs)
241         {
242             return !(lhs == rhs);
243         }
244 
operator <(gid_type const & lhs,gid_type const & rhs)245         friend bool operator< (gid_type const& lhs, gid_type const& rhs)
246         {
247             std::int64_t lhs_msb =
248                 detail::strip_internal_bits_from_gid(lhs.id_msb_);
249             std::int64_t rhs_msb =
250                 detail::strip_internal_bits_from_gid(rhs.id_msb_);
251 
252             if (lhs_msb < rhs_msb)
253             {
254                 return true;
255             }
256             if (lhs_msb > rhs_msb)
257             {
258                 return false;
259             }
260             return lhs.id_lsb_ < rhs.id_lsb_;
261         }
262 
operator <=(gid_type const & lhs,gid_type const & rhs)263         friend bool operator<= (gid_type const& lhs, gid_type const& rhs)
264         {
265             std::int64_t lhs_msb =
266                 detail::strip_internal_bits_from_gid(lhs.id_msb_);
267             std::int64_t rhs_msb =
268                 detail::strip_internal_bits_from_gid(rhs.id_msb_);
269 
270             if (lhs_msb < rhs_msb)
271             {
272                 return true;
273             }
274             if (lhs_msb > rhs_msb)
275             {
276                 return false;
277             }
278             return lhs.id_lsb_ <= rhs.id_lsb_;
279         }
280 
operator >(gid_type const & lhs,gid_type const & rhs)281         friend bool operator> (gid_type const& lhs, gid_type const& rhs)
282         {
283             return !(lhs <= rhs);
284         }
285 
operator >=(gid_type const & lhs,gid_type const & rhs)286         friend bool operator>= (gid_type const& lhs, gid_type const& rhs)
287         {
288             return !(lhs < rhs);
289         }
290 
get_msbhpx::naming::gid_type291         std::uint64_t get_msb() const
292         {
293             return id_msb_;
294         }
set_msbhpx::naming::gid_type295         void set_msb(std::uint64_t msb)
296         {
297             id_msb_ = msb;
298         }
get_lsbhpx::naming::gid_type299         std::uint64_t get_lsb() const
300         {
301             return id_lsb_;
302         }
set_lsbhpx::naming::gid_type303         void set_lsb(std::uint64_t lsb)
304         {
305             id_lsb_ = lsb;
306         }
set_lsbhpx::naming::gid_type307         void set_lsb(void* lsb)
308         {
309             id_lsb_ = reinterpret_cast<std::uint64_t>(lsb);
310         }
311 
312         std::string to_string() const;
313 
314         // this type is at the same time its own mutex type
315         typedef gid_type mutex_type;
316 
317         // Note: we deliberately don't register this lock with the lock
318         //       tracking to avoid false positives. We know that gid_types need
319         //       to be locked while suspension.
lockhpx::naming::gid_type320         void lock()
321         {
322             HPX_ITT_SYNC_PREPARE(this);
323 
324             for (std::size_t k = 0; !acquire_lock(); ++k)
325             {
326                 util::detail::yield_k(k, "hpx::naming::gid_type::lock");
327             }
328 
329             util::register_lock(this);
330 
331             HPX_ITT_SYNC_ACQUIRED(this);
332         }
333 
try_lockhpx::naming::gid_type334         bool try_lock()
335         {
336             HPX_ITT_SYNC_PREPARE(this);
337 
338             if (acquire_lock())
339             {
340                 HPX_ITT_SYNC_ACQUIRED(this);
341                 util::register_lock(this);
342                 return true;
343             }
344 
345             HPX_ITT_SYNC_CANCEL(this);
346             return false;
347         }
348 
unlockhpx::naming::gid_type349         void unlock()
350         {
351             HPX_ITT_SYNC_RELEASING(this);
352 
353             relinquish_lock();
354             util::unregister_lock(this);
355 
356             HPX_ITT_SYNC_RELEASED(this);
357         }
358 
get_mutexhpx::naming::gid_type359         mutex_type& get_mutex() const { return const_cast<mutex_type&>(*this); }
360 
361     private:
362         friend HPX_EXPORT std::ostream& operator<<(std::ostream& os,
363             gid_type const& id);
364 
365         friend class hpx::serialization::access;
366 
367         void save(serialization::output_archive& ar, unsigned int version) const;
368 
369         void load(serialization::input_archive& ar, unsigned int version);
370 
371         HPX_SERIALIZATION_SPLIT_MEMBER()
372 
373         // lock implementation
374         typedef lcos::local::spinlock_pool<tag> internal_mutex_type;
375 
376         // returns whether lock has been acquired
acquire_lockhpx::naming::gid_type377         bool acquire_lock()
378         {
379             internal_mutex_type::scoped_lock l(this);
380             bool was_locked = (id_msb_ & is_locked_mask) ? true : false;
381             if (!was_locked)
382             {
383                 id_msb_ |= is_locked_mask;
384                 return true;
385             }
386             return false;
387         }
388 
relinquish_lockhpx::naming::gid_type389         void relinquish_lock()
390         {
391             util::ignore_lock(this);
392             internal_mutex_type::scoped_lock l(this);
393             util::reset_ignored(this);
394 
395             id_msb_ &= ~is_locked_mask;
396         }
397 
398         // this is used for assertions only, no need to acquire the lock
is_lockedhpx::naming::gid_type399         bool is_locked() const
400         {
401             return (id_msb_ & is_locked_mask) ? true : false;
402         }
403 
404         friend bool detail::is_locked(gid_type const& gid);
405 
406         // actual gid
407         std::uint64_t id_msb_;
408         std::uint64_t id_lsb_;
409     };
410 }}
411 
412 ///////////////////////////////////////////////////////////////////////////////
413 // we know that we can serialize a gid as a byte sequence
414 HPX_IS_BITWISE_SERIALIZABLE(hpx::naming::gid_type)
415 
416 namespace hpx { namespace naming
417 {
418     ///////////////////////////////////////////////////////////////////////////
419     //  Handle conversion to/from locality_id
420     inline gid_type get_gid_from_locality_id(std::uint32_t locality_id)
421         HPX_SUPER_PURE;
422 
get_gid_from_locality_id(std::uint32_t locality_id)423     inline gid_type get_gid_from_locality_id(std::uint32_t locality_id)
424     {
425         return gid_type(
426             std::uint64_t(locality_id+1) << gid_type::locality_id_shift,
427             0);
428     }
429 
430     inline std::uint32_t get_locality_id_from_gid(std::uint64_t msb) HPX_PURE;
431 
get_locality_id_from_gid(std::uint64_t msb)432     inline std::uint32_t get_locality_id_from_gid(std::uint64_t msb)
433     {
434         return std::uint32_t(msb >> gid_type::locality_id_shift) - 1;
435     }
436 
437     inline std::uint32_t get_locality_id_from_gid(gid_type const& id) HPX_PURE;
438 
get_locality_id_from_gid(gid_type const & id)439     inline std::uint32_t get_locality_id_from_gid(gid_type const& id)
440     {
441         return get_locality_id_from_gid(id.get_msb());
442     }
443 
get_locality_from_gid(gid_type const & id)444     inline gid_type get_locality_from_gid(gid_type const& id)
445     {
446         return get_gid_from_locality_id(get_locality_id_from_gid(id));
447     }
448 
is_locality(gid_type const & gid)449     inline bool is_locality(gid_type const& gid)
450     {
451         return get_locality_from_gid(gid) == gid;
452     }
453 
454     inline std::uint64_t replace_locality_id(std::uint64_t msb,
455         std::uint32_t locality_id) HPX_PURE;
456 
replace_locality_id(std::uint64_t msb,std::uint32_t locality_id)457     inline std::uint64_t replace_locality_id(std::uint64_t msb,
458         std::uint32_t locality_id)
459     {
460         msb &= ~gid_type::locality_id_mask;
461         return msb | get_gid_from_locality_id(locality_id).get_msb();
462     }
463 
464     inline gid_type replace_locality_id(gid_type const& gid,
465         std::uint32_t locality_id) HPX_PURE;
466 
replace_locality_id(gid_type const & gid,std::uint32_t locality_id)467     inline gid_type replace_locality_id(gid_type const& gid,
468         std::uint32_t locality_id)
469     {
470         std::uint64_t msb = gid.get_msb() & ~gid_type::locality_id_mask;
471         msb |= get_gid_from_locality_id(locality_id).get_msb();
472         return gid_type(msb, gid.get_lsb());
473     }
474 
475     ///////////////////////////////////////////////////////////////////////////
refers_to_virtual_memory(std::uint64_t msb)476     inline bool refers_to_virtual_memory(std::uint64_t msb)
477     {
478         return !(msb & gid_type::virtual_memory_mask);
479     }
480 
refers_to_virtual_memory(gid_type const & gid)481     inline bool refers_to_virtual_memory(gid_type const& gid)
482     {
483         return refers_to_virtual_memory(gid.get_msb());
484     }
485 
486     ///////////////////////////////////////////////////////////////////////////
refers_to_local_lva(gid_type const & gid)487     inline bool refers_to_local_lva(gid_type const& gid)
488     {
489         return !(gid.get_msb() & gid_type::dynamically_assigned);
490     }
491 
replace_component_type(gid_type const & gid,std::uint32_t type)492     inline gid_type replace_component_type(gid_type const& gid,
493         std::uint32_t type)
494     {
495         std::uint64_t msb = gid.get_msb() & ~gid_type::component_type_mask;
496 
497         HPX_ASSERT(!(msb & gid_type::dynamically_assigned));
498         msb |= ((type << gid_type::component_type_shift) &
499                     gid_type::component_type_mask);
500         return gid_type(msb, gid.get_lsb());
501     }
502 
503     ///////////////////////////////////////////////////////////////////////////
504     namespace detail
505     {
506         // We store the log2(credit) in the gid_type
log2(std::int64_t val)507         inline std::int16_t log2(std::int64_t val)
508         {
509             std::int16_t ret = -1;
510             while (val != 0)
511             {
512                 val >>= 1;
513                 ++ret;
514             }
515             return ret;
516         }
517 
power2(std::int16_t log2credits)518         inline std::int64_t power2(std::int16_t log2credits)
519         {
520             HPX_ASSERT(log2credits >= 0);
521             return static_cast<std::int64_t>(1) << log2credits;
522         }
523 
524         ///////////////////////////////////////////////////////////////////////
has_credits(gid_type const & id)525         inline bool has_credits(gid_type const& id)
526         {
527             return (id.get_msb() & gid_type::has_credits_mask) ? true : false;
528         }
529 
gid_was_split(gid_type const & id)530         inline bool gid_was_split(gid_type const& id)
531         {
532             return (id.get_msb() & gid_type::was_split_mask) ? true : false;
533         }
534 
set_credit_split_mask_for_gid(gid_type & id)535         inline void set_credit_split_mask_for_gid(gid_type& id)
536         {
537             id.set_msb(id.get_msb() | gid_type::was_split_mask);
538         }
539 
540         ///////////////////////////////////////////////////////////////////////
store_in_cache(gid_type const & id)541         inline bool store_in_cache(gid_type const& id)
542         {
543             return (id.get_msb() & gid_type::dont_cache_mask) ? false : true;
544         }
545 
set_dont_store_in_cache(gid_type & gid)546         inline void set_dont_store_in_cache(gid_type& gid)
547         {
548             gid.set_msb(gid.get_msb() | gid_type::dont_cache_mask);
549         }
550 
set_dont_store_in_cache(id_type & id)551         inline void set_dont_store_in_cache(id_type& id)
552         {
553             id.set_msb(id.get_msb() | gid_type::dont_cache_mask);
554         }
555 
556         ///////////////////////////////////////////////////////////////////////
is_migratable(gid_type const & id)557         inline bool is_migratable(gid_type const& id)
558         {
559             return (id.get_msb() & gid_type::is_migratable) ? true : false;
560         }
561 
set_is_migratable(gid_type & gid)562         inline void set_is_migratable(gid_type& gid)
563         {
564             gid.set_msb(gid.get_msb() | gid_type::is_migratable);
565         }
566 
567         ///////////////////////////////////////////////////////////////////////
568         inline std::int64_t get_credit_from_gid(gid_type const& id) HPX_PURE;
569 
get_log2credit_from_gid(gid_type const & id)570         inline std::int16_t get_log2credit_from_gid(gid_type const& id)
571         {
572             HPX_ASSERT(has_credits(id));
573             return std::int16_t((id.get_msb() >> gid_type::credit_shift) &
574                     gid_type::credit_base_mask);
575         }
576 
get_credit_from_gid(gid_type const & id)577         inline std::int64_t get_credit_from_gid(gid_type const& id)
578         {
579             return has_credits(id) ? detail::power2(get_log2credit_from_gid(id)) : 0;
580         }
581 
582         ///////////////////////////////////////////////////////////////////////
strip_internal_bits_from_gid(std::uint64_t msb)583         inline std::uint64_t strip_internal_bits_from_gid(std::uint64_t msb)
584         {
585             return msb & ~gid_type::internal_bits_mask;
586         }
587 
strip_internal_bits_from_gid(gid_type & id)588         inline gid_type& strip_internal_bits_from_gid(gid_type& id)
589         {
590             id.set_msb(strip_internal_bits_from_gid(id.get_msb()));
591             return id;
592         }
593 
strip_internal_bits_except_dont_cache_from_gid(std::uint64_t msb)594         inline std::uint64_t strip_internal_bits_except_dont_cache_from_gid(
595             std::uint64_t msb)
596         {
597             return msb & ~(gid_type::credit_bits_mask | gid_type::is_locked_mask);
598         }
599 
strip_internal_bits_except_dont_cache_from_gid(gid_type & id)600         inline gid_type& strip_internal_bits_except_dont_cache_from_gid(
601             gid_type& id)
602         {
603             id.set_msb(
604                 strip_internal_bits_except_dont_cache_from_gid(id.get_msb()));
605             return id;
606         }
607 
strip_internal_bits_and_component_type_from_gid(std::uint64_t msb)608         inline std::uint64_t strip_internal_bits_and_component_type_from_gid(
609             std::uint64_t msb)
610         {
611             return msb &
612                 ~(gid_type::internal_bits_mask | gid_type::component_type_mask);
613         }
614 
strip_internal_bits_and_component_type_from_gid(gid_type & id)615         inline gid_type& strip_internal_bits_and_component_type_from_gid(
616             gid_type& id)
617         {
618             id.set_msb(
619                 strip_internal_bits_and_component_type_from_gid(id.get_msb()));
620             return id;
621         }
622 
get_internal_bits(std::uint64_t msb)623         inline std::uint64_t get_internal_bits(std::uint64_t msb)
624         {
625             return msb &
626                 (gid_type::internal_bits_mask | gid_type::component_type_mask);
627         }
628 
strip_internal_bits_and_locality_from_gid(std::uint64_t msb)629         inline std::uint64_t strip_internal_bits_and_locality_from_gid(
630                 std::uint64_t msb)
631         {
632             return msb &
633                 (~gid_type::special_bits_mask | gid_type::component_type_mask);
634         }
635 
636         ///////////////////////////////////////////////////////////////////////
get_component_type_from_gid(std::uint64_t msb)637         inline std::uint32_t get_component_type_from_gid(std::uint64_t msb)
638         {
639             HPX_ASSERT(!(msb & gid_type::dynamically_assigned));
640             return (msb >> gid_type::component_type_shift) &
641                 gid_type::component_type_base_mask;
642         }
643 
add_component_type_to_gid(std::uint64_t msb,std::uint32_t type)644         inline std::uint64_t add_component_type_to_gid(std::uint64_t msb,
645             std::uint32_t type)
646         {
647             HPX_ASSERT(!(msb & gid_type::dynamically_assigned));
648             return (msb & ~gid_type::component_type_mask) |
649                 ((type << gid_type::component_type_shift) &
650                     gid_type::component_type_mask);
651         }
652 
653         ///////////////////////////////////////////////////////////////////////
strip_lock_from_gid(std::uint64_t msb)654         inline std::uint64_t strip_lock_from_gid(std::uint64_t msb)
655         {
656             return msb & ~gid_type::is_locked_mask;
657         }
658 
strip_lock_from_gid(gid_type & gid)659         inline gid_type& strip_lock_from_gid(gid_type& gid)
660         {
661             gid.set_msb(strip_lock_from_gid(gid.get_msb()));
662             return gid;
663         }
664 
is_locked(gid_type const & gid)665         inline bool is_locked(gid_type const& gid)
666         {
667             return gid.is_locked();
668         }
669 
670         ///////////////////////////////////////////////////////////////////////
671         inline gid_type get_stripped_gid(gid_type const& id) HPX_PURE;
672 
get_stripped_gid(gid_type const & id)673         inline gid_type get_stripped_gid(gid_type const& id)
674         {
675             std::uint64_t const msb = strip_internal_bits_from_gid(id.get_msb());
676             std::uint64_t const lsb = id.get_lsb();
677             return gid_type(msb, lsb);
678         }
679 
680         inline gid_type get_stripped_gid_except_dont_cache(gid_type const& id)
681             HPX_PURE;
682 
get_stripped_gid_except_dont_cache(gid_type const & id)683         inline gid_type get_stripped_gid_except_dont_cache(gid_type const& id)
684         {
685             std::uint64_t const msb =
686                 strip_internal_bits_except_dont_cache_from_gid(id.get_msb());
687             std::uint64_t const lsb = id.get_lsb();
688             return gid_type(msb, lsb);
689         }
690 
strip_credits_from_gid(std::uint64_t msb)691         inline std::uint64_t strip_credits_from_gid(std::uint64_t msb)
692         {
693             return msb & ~gid_type::credit_bits_mask;
694         }
695 
strip_credits_from_gid(gid_type & id)696         inline gid_type& strip_credits_from_gid(gid_type& id)
697         {
698             id.set_msb(strip_credits_from_gid(id.get_msb()));
699             return id;
700         }
701 
702         ///////////////////////////////////////////////////////////////////////
set_log2credit_for_gid(gid_type & id,std::int16_t log2credits)703         inline void set_log2credit_for_gid(gid_type& id, std::int16_t log2credits)
704         {
705             // credit should be a clean log2
706             HPX_ASSERT(log2credits >= 0);
707             HPX_ASSERT(0 == (log2credits & ~gid_type::credit_base_mask));
708 
709             id.set_msb((id.get_msb() & ~gid_type::credit_mask) |
710                 ((std::int32_t(log2credits) << gid_type::credit_shift)
711                     & gid_type::credit_mask) |
712                 gid_type::has_credits_mask);
713         }
714 
set_credit_for_gid(gid_type & id,std::int64_t credits)715         inline void set_credit_for_gid(gid_type& id, std::int64_t credits)
716         {
717             if (credits != 0)
718             {
719                 std::int16_t log2credits = detail::log2(credits);
720                 HPX_ASSERT(detail::power2(log2credits) == credits);
721 
722                 set_log2credit_for_gid(id, log2credits);
723             }
724             else
725             {
726                 strip_credits_from_gid(id);
727             }
728         }
729 
730         ///////////////////////////////////////////////////////////////////////
731         // has side effects, can't be pure
732         HPX_EXPORT std::int64_t add_credit_to_gid(gid_type& id,
733             std::int64_t credits);
734 
735         HPX_EXPORT std::int64_t remove_credit_from_gid(gid_type& id,
736             std::int64_t debit);
737 
738         HPX_EXPORT std::int64_t fill_credit_for_gid(gid_type& id,
739             std::int64_t credits = std::int64_t(HPX_GLOBALCREDIT_INITIAL));
740 
741         ///////////////////////////////////////////////////////////////////////
742         HPX_EXPORT gid_type move_gid(gid_type& id);
743         HPX_EXPORT gid_type move_gid_locked(std::unique_lock<gid_type::mutex_type> l,
744             gid_type& gid);
745 
746         HPX_EXPORT std::int64_t replenish_credits(gid_type& id);
747         HPX_EXPORT std::int64_t replenish_credits_locked(
748             std::unique_lock<gid_type::mutex_type>& l, gid_type& id);
749 
750         ///////////////////////////////////////////////////////////////////////
751         // splits the current credit of the given id and assigns half of it to
752         // the returned copy
753         HPX_EXPORT gid_type split_credits_for_gid(gid_type& id);
754         HPX_EXPORT gid_type split_credits_for_gid_locked(
755             std::unique_lock<gid_type::mutex_type>& l, gid_type& id);
756     }
757 
758     HPX_EXPORT gid_type operator+ (gid_type const& lhs, gid_type const& rhs);
759     HPX_EXPORT gid_type operator- (gid_type const& lhs, gid_type const& rhs);
760 
761     ///////////////////////////////////////////////////////////////////////////
762     gid_type const invalid_gid = gid_type();
763 
764     ///////////////////////////////////////////////////////////////////////////
765     HPX_EXPORT std::ostream& operator<<(std::ostream& os, gid_type const& id);
766 
767     namespace detail
768     {
769         ///////////////////////////////////////////////////////////////////////
770         enum id_type_management
771         {
772             unknown_deleter = -1,
773             unmanaged = 0,          // unmanaged GID
774             managed = 1,            // managed GID
775             managed_move_credit = 2 // managed GID which will give up all
776                                     // credits when sent
777         };
778 
779         // forward declaration
780         struct HPX_EXPORT id_type_impl;
781 
782         // custom deleter for id_type_impl above
783         HPX_EXPORT void gid_managed_deleter (id_type_impl* p);
784         HPX_EXPORT void gid_unmanaged_deleter (id_type_impl* p);
785 
786         HPX_EXPORT void intrusive_ptr_add_ref(id_type_impl* p);
787         HPX_EXPORT void intrusive_ptr_release(id_type_impl* p);
788 
789         ///////////////////////////////////////////////////////////////////////
790         struct HPX_EXPORT id_type_impl : gid_type
791         {
792         public:
793             HPX_NON_COPYABLE(id_type_impl);
794 
795         private:
796             typedef void (*deleter_type)(detail::id_type_impl*);
797             static deleter_type get_deleter(id_type_management t);
798 
799         public:
id_type_implhpx::naming::detail::id_type_impl800             id_type_impl()
801               : count_(0), type_(unknown_deleter)
802             {}
803 
id_type_implhpx::naming::detail::id_type_impl804             explicit id_type_impl (std::uint64_t lsb_id, id_type_management t)
805               : gid_type(0, lsb_id), count_(0), type_(t)
806             {}
807 
id_type_implhpx::naming::detail::id_type_impl808             explicit id_type_impl (std::uint64_t msb_id, std::uint64_t lsb_id,
809                     id_type_management t)
810               : gid_type(msb_id, lsb_id), count_(0), type_(t)
811             {}
812 
id_type_implhpx::naming::detail::id_type_impl813             explicit id_type_impl (gid_type const& gid, id_type_management t)
814               : gid_type(gid), count_(0), type_(t)
815             {}
816 
get_management_typehpx::naming::detail::id_type_impl817             id_type_management get_management_type() const
818             {
819                 return type_;
820             }
set_management_typehpx::naming::detail::id_type_impl821             void set_management_type(id_type_management type)
822             {
823                 type_ = type;
824             }
825 
826             // serialization
827             void save(serialization::output_archive& ar, unsigned) const;
828 
829             void load(serialization::input_archive& ar, unsigned);
830 
831             HPX_SERIALIZATION_SPLIT_MEMBER()
832 
833         private:
834             // credit management (called during serialization), this function
835             // has to be 'const' as save() above has to be 'const'.
836             void preprocess_gid(serialization::output_archive& ar) const;
837 
838             // reference counting
839             friend HPX_EXPORT void intrusive_ptr_add_ref(id_type_impl* p);
840             friend HPX_EXPORT void intrusive_ptr_release(id_type_impl* p);
841 
842             util::atomic_count count_;
843             id_type_management type_;
844         };
845     }
846 
847     ///////////////////////////////////////////////////////////////////////////
848     HPX_API_EXPORT gid_type get_parcel_dest_gid(id_type const& id);
849 }}
850 
851 #include <hpx/runtime/naming/id_type.hpp>
852 #include <hpx/runtime/naming/id_type_impl.hpp>
853 
854 namespace hpx { namespace naming
855 {
856     ///////////////////////////////////////////////////////////////////////////
857     HPX_EXPORT std::ostream& operator<<(std::ostream& os, id_type const& id);
858 
859     ///////////////////////////////////////////////////////////////////////
860     // Handle conversion to/from locality_id
861     // FIXME: these names are confusing, 'id' appears in identifiers far too
862     // frequently.
863     inline id_type get_id_from_locality_id(std::uint32_t locality_id) HPX_SUPER_PURE;
864 
get_id_from_locality_id(std::uint32_t locality_id)865     inline id_type get_id_from_locality_id(std::uint32_t locality_id)
866     {
867         return id_type(
868             std::uint64_t(locality_id+1) << gid_type::locality_id_shift,
869             0, id_type::unmanaged);
870     }
871 
872     inline std::uint32_t get_locality_id_from_id(id_type const& id) HPX_PURE;
873 
get_locality_id_from_id(id_type const & id)874     inline std::uint32_t get_locality_id_from_id(id_type const& id)
875     {
876         return std::uint32_t(id.get_msb() >> gid_type::locality_id_shift) - 1;
877     }
878 
get_locality_from_id(id_type const & id)879     inline id_type get_locality_from_id(id_type const& id)
880     {
881         return get_id_from_locality_id(get_locality_id_from_id(id));
882     }
883 
is_locality(id_type const & id)884     inline bool is_locality(id_type const& id)
885     {
886         return is_locality(id.get_gid());
887     }
888 
889     ///////////////////////////////////////////////////////////////////////////
890     HPX_EXPORT char const* get_management_type_name(id_type::management_type m);
891 }}
892 
893 ///////////////////////////////////////////////////////////////////////////////
894 namespace hpx { namespace traits
895 {
896     template <>
897     struct get_remote_result<naming::id_type, naming::gid_type>
898     {
callhpx::traits::get_remote_result899         static naming::id_type call(naming::gid_type const& rhs)
900         {
901             bool has_credits = naming::detail::has_credits(rhs);
902             return naming::id_type(rhs,
903                 has_credits ?
904                     naming::id_type::managed :
905                     naming::id_type::unmanaged);
906         }
907     };
908 
909     template <>
910     struct promise_local_result<naming::gid_type>
911     {
912         typedef naming::id_type type;
913     };
914 
915     // we need to specialize this template to allow for automatic conversion of
916     // the vector<naming::gid_type> to a vector<naming::id_type>
917     template <>
918     struct get_remote_result<
919         std::vector<naming::id_type>, std::vector<naming::gid_type> >
920     {
921         static std::vector<naming::id_type>
callhpx::traits::get_remote_result922         call(std::vector<naming::gid_type> const& rhs)
923         {
924             std::vector<naming::id_type> result;
925             result.reserve(rhs.size());
926             for (naming::gid_type const& r : rhs)
927             {
928                 bool has_credits = naming::detail::has_credits(r);
929                 result.push_back(naming::id_type(r,
930                     has_credits ?
931                         naming::id_type::managed :
932                         naming::id_type::unmanaged));
933             }
934             return result;
935         }
936     };
937 
938     template <>
939     struct promise_local_result<std::vector<naming::gid_type> >
940     {
941         typedef std::vector<naming::id_type> type;
942     };
943 }}
944 
945 ///////////////////////////////////////////////////////////////////////////////
946 namespace hpx
947 {
948     // pull invalid id into the main namespace
949     using naming::invalid_id;
950 }
951 
952 ///////////////////////////////////////////////////////////////////////////////
953 namespace std
954 {
955     // specialize std::hash for hpx::naming::gid_type
956     template <>
957     struct hash<hpx::naming::gid_type>
958     {
operator ()std::hash959         std::size_t operator()(::hpx::naming::gid_type const& gid) const
960         {
961             std::size_t const h1 (std::hash<std::uint64_t>()(gid.get_lsb()));
962             std::size_t const h2 (std::hash<std::uint64_t>()(
963                 hpx::naming::detail::strip_internal_bits_from_gid(gid.get_msb())));
964             return h1 ^ (h2 << 1);
965         }
966     };
967 }
968 
969 #include <hpx/config/warnings_suffix.hpp>
970 
971 #endif /*HPX_RUNTIME_NAMING_NAME_HPP*/
972