MADNESS  version 0.9
worldref.h
Go to the documentation of this file.
1 /*
2  This file is part of MADNESS.
3 
4  Copyright (C) 2007,2010 Oak Ridge National Laboratory
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 
20  For more information please contact:
21 
22  Robert J. Harrison
23  Oak Ridge National Laboratory
24  One Bethel Valley Road
25  P.O. Box 2008, MS-6367
26 
27  email: harrisonrj@ornl.gov
28  tel: 865-241-3937
29  fax: 865-572-0680
30 
31 
32  $Id$
33 */
34 
35 
36 #ifndef MADNESS_WORLD_WORLDREF_H__INCLUDED
37 #define MADNESS_WORLD_WORLDREF_H__INCLUDED
38 
41 
42 #include <madness/world/atomicint.h> // for AtomicInt
43 #include <madness/world/shared_ptr.h> // for shared_ptr
44 #include <madness/world/worldtypes.h> // for ProcessID
45 #include <madness/world/archive.h> // for wrap_opaque
46 #include <madness/world/worldam.h> // for new_am_arg
47 #include <madness/world/worldptr.h> // for WorldPtr
48 #include <madness/world/worldhashmap.h> // for ConcurrentHashMap
49 #include <iosfwd> // for std::ostream
50 
51 //#define MADNESS_REMOTE_REFERENCE_DEBUG
52 #ifdef MADNESS_REMOTE_REFERENCE_DEBUG
53 #include <madness/world/print.h> // for print
54 #endif
55 
56 namespace madness {
57 
58  class World;
59  template <typename T> class RemoteReference;
60 //
61 // template <typename T>
62 // std::ostream& operator<<(std::ostream& s, const RemoteReference<T>& ref);
63 
64  namespace archive {
65  template <typename, typename>
66  struct ArchiveLoadImpl;
67 
68  template <typename, typename>
69  struct ArchiveStoreImpl;
70  }
71 
72  namespace detail {
73 
74 
75  template <typename T> class RemoteCounterImpl;
76 
78 
88  private:
89  madness::AtomicInt count_;
90 
91  // Copy not allowed
93  RemoteCounterBase& operator=(const RemoteCounterBase&);
94 
95  public:
96 
97  RemoteCounterBase() { count_ = 1; }
98  virtual ~RemoteCounterBase() { }
99 
101 
105  virtual void* key() const = 0;
106 
108 
111  long use_count() const { return count_; }
112 
114 
117  template <typename T>
119  return static_cast<const RemoteCounterImpl<T>*>(this)->get_shared();
120  }
121 
123 
128  void add_ref() {
129 #ifdef MADNESS_REMOTE_REFERENCE_DEBUG
130  long c = count_++;
131  print(">>> RemoteCounterBase(", this->key(), ") +ref count=", c + 1);
132 #else
133  count_++;
134 #endif
135  }
136 
138 
141  bool release() {
142 #ifdef MADNESS_REMOTE_REFERENCE_DEBUG
143  long c = count_;
144  print(">>> RemoteCounterBase(", this->key(), ") -ref count=", c - 1);
145 #endif
146  return count_.dec_and_test();
147  }
148  }; // class RemoteCounterBase
149 
151 
158  template <typename T>
159  class RemoteCounterImpl : public RemoteCounterBase {
160  private:
161  // At some point this should probably be changed to a quick allocator
162  // When that happens, also uncomment the new and delete operators
163 // typedef std::allocator<RemoteCounterImpl<T> > A;
164 
165  // Keep a copy of the shared pointer to make sure it stays in memory
166  // while we have outstanding remote references to it.
167  std::shared_ptr<T> pointer_;
168 
169  public:
171  RemoteCounterBase(), pointer_(p)
172  { }
173 
174  virtual ~RemoteCounterImpl() { }
175 
177 
179  const std::shared_ptr<T>& get_shared() const { return pointer_; }
180 
182 
186  virtual void* key() const { return static_cast<void*>(pointer_.get()); }
187 
188 // void* operator new(std::size_t) {
189 // return A().allocate(1);
190 // }
191 //
192 // void operator delete(void * p) {
193 // A().deallocate(static_cast<RemoteCounterImpl<T> *>(p), 1);
194 // }
195  }; // class RemoteCounterImpl
196 
198 
203  private:
204  typedef RemoteCounterBase implT;
206 
207  static pimpl_mapT pimpl_map_;
208 
212  mutable WorldPtr<implT> pimpl_;
213 
215 
219  void destroy() {
220  if(pimpl_.is_local()) {
221  if(pimpl_->release()) {
222  // No one else is referencing this pointer.
223  // We can safely dispose of it.
224 
225 #ifdef MADNESS_REMOTE_REFERENCE_DEBUG
226  print(">>> RemoteCounter::unregister_ptr_: key=", pimpl_->key(), ", value=", pimpl_);
227 #endif
228  unregister_ptr_(pimpl_->key());
229  delete pimpl_.get();
230  }
231  }
232 
233  pimpl_ = WorldPtr<implT>();
234  }
235 
237 
249  template <typename T>
250  static WorldPtr<implT> register_ptr_(World& w, const std::shared_ptr<T>& p) {
251  // Check for a null pointer
252  if(p.get() == NULL)
253  return WorldPtr<implT>(w, NULL);
254 
256  // Pointer is local and non-null
257  if(pimpl_map_.insert(acc,static_cast<void*>(p.get()))) {
258  // The pointer is not registered so we need to make a
259  // new pimpl.
260  implT* pimpl = new RemoteCounterImpl<T>(p);
261 
262  try{
263  acc->second = WorldPtr<implT>(w, pimpl);
264  } catch(...) {
265  delete pimpl;
266  throw;
267  }
268 
269 #ifdef MADNESS_REMOTE_REFERENCE_DEBUG
270  print(">>> RemoteCounter::register_ptr_(new): key=", p.get(), ", pimpl=", acc->second);
271 #endif
272  } else {
273  // The pointer is already registered, so we just need
274  // increment the counter.
275 #ifdef MADNESS_REMOTE_REFERENCE_DEBUG
276  print(">>> RemoteCounter::register_ptr_(existing): key=", acc->second->key(), ", pimpl=", acc->second);
277 #endif
278  acc->second->add_ref();
279  }
280 
281  return acc->second;
282  }
283 
285 
288  static void unregister_ptr_(void* key) {
289  std::size_t ereased = pimpl_map_.erase(key);
290  MADNESS_ASSERT(ereased > 0);
291  }
292 
293  RemoteCounter(const WorldPtr<implT>& p) :
294  pimpl_(p)
295  { }
296 
297  public:
298 
299  RemoteCounter() : pimpl_() { }
300 
301  RemoteCounter(const RemoteCounter& other) :
302  pimpl_(other.pimpl_)
303  {
304  if(pimpl_ && pimpl_.is_local())
305  pimpl_->add_ref();
306  }
307 
308  template <typename T>
309  explicit RemoteCounter(World& w, const std::shared_ptr<T>& p) :
310  pimpl_(register_ptr_(w, p))
311  { }
312 
313  ~RemoteCounter() { destroy(); }
314 
316  WorldPtr<implT> temp = other.pimpl_;
317 
318  if(pimpl_ != temp) {
319  if(temp)
320  temp->add_ref();
321  destroy();
322  pimpl_ = temp;
323  }
324 
325  return *this;
326  }
327 
329 
332  long use_count() const { return (pimpl_.is_local() ? pimpl_->use_count() : 0); }
333  bool unique() const { return use_count() == 1; }
334  bool empty() const { return ! pimpl_; }
335 
336  bool is_local() const { return pimpl_.is_local(); }
337  bool has_owner() const { return pimpl_.has_owner(); }
338  ProcessID owner() const { return pimpl_.owner(); }
339 
340  template <typename T>
341  const std::shared_ptr<T>& get_shared() const { return pimpl_->get_shared<T>(); }
342 
344  get_worldid() const { return pimpl_.get_worldid(); }
345  World& get_world() const { return pimpl_.get_world(); }
346  void swap(RemoteCounter& other) {
347  madness::detail::swap(pimpl_, other.pimpl_);
348  }
349 
350  private:
351 
352  template <typename, typename>
354 
355  template <typename, typename>
357 
358  template <typename Archive>
359  void load_(const Archive& ar) {
360  WorldPtr<implT> p;
361  ar & p;
362  RemoteCounter(p).swap(*this);
363 
364 #ifdef MADNESS_REMOTE_REFERENCE_DEBUG
365  print(">>> RemoteCounter::load: pimpl=", pimpl_);
366 #endif
367  }
368 
369  template <typename Archive>
370  void store_(const Archive& ar) const {
371  ar & pimpl_;
372 
373  if(! ar.count_only()) {
374 #ifdef MADNESS_REMOTE_REFERENCE_DEBUG
375  print(">>> RemoteCounter::store: pimpl=", pimpl_);
376 #endif
377  if(pimpl_.is_local())
378  pimpl_->add_ref();
379  else
380  pimpl_ = WorldPtr<implT>();
381  }
382  }
383 
384 
385  }; // class RemoteCounter
386 
387  inline void swap(RemoteCounter& l, RemoteCounter& r) { l.swap(r); }
388 
389  std::ostream& operator<<(std::ostream& out, const RemoteCounter& counter);
390 
391  } // namespace detail
392 
393 
395 
406  template <typename T>
407  class RemoteReference {
408  public:
410  typedef T* pointerT;
411 
412  private:
413  mutable pointerT pointer_;
414  detail::RemoteCounter counter_;
415 
416  // This is for RemoteReferences of other types, so they can still access
417  // private members.
418  template <typename>
419  friend class RemoteReference;
420 
421  // Handles reset of a remote reference from another node.
422  static void reset_handler(const AmArg& arg) {
424  arg & r;
425  // r resets on scope exit.
426  }
427 
428  public:
429 
432  pointer_(), counter_() {};
433 
435 
440  pointer_(p.get()), counter_(w, p)
441  { }
442 
444 
447  pointer_(other.pointer_), counter_(other.counter_)
448  { }
449 
451 
455  template <typename U>
457  pointer_(other.pointer_), counter_(other.counter_)
458  { }
459 
461 
463 
466  RemoteReference<T>(other).swap(*this);
467  return *this;
468  }
469 
471 
475  template <typename U>
477  RemoteReference<T>(other).swap(*this);
478  return *this;
479  }
480 
481 
483 
490  void reset() {
491  if((! (counter_.is_local())) && counter_.has_owner())
493  else
494  RemoteReference<T>().swap(*this);
495  }
496 
498 
501  operator bool() const {
502  return ! counter_.empty();
503  }
504 
506 
509  pointerT get() const {
510  MADNESS_ASSERT(counter_.is_local());
511  return pointer_;
512  }
513 
515 
519  MADNESS_ASSERT(counter_.is_local());
520  return counter_.get_shared<T>();
521  }
522 
524 
528  referenceT operator*() const {
529  MADNESS_ASSERT(pointer_ != NULL);
530  MADNESS_ASSERT(counter_.is_local());
531  return *pointer_;
532  }
533 
535 
539  pointerT operator->() const {
540  MADNESS_ASSERT(pointer_ != NULL);
541  MADNESS_ASSERT(counter_.is_local());
542  return pointer_;
543  }
544 
546 
549  long use_count() const { return counter_.use_count(); }
550 
552 
555  bool unique() const { return counter_.unique(); }
556 
558 
563  template <typename U>
564  void swap(RemoteReference<U>& other) {
565  std::swap(pointer_, other.pointer_);
566  madness::detail::swap(counter_, other.counter_);
567  }
568 
570 
574  inline bool is_local() const { return counter_.is_local(); }
575 
577 
580  inline ProcessID owner() const { return counter_.owner(); }
581 
583 
586  World& get_world() const { return counter_.get_world(); }
587 
589 
592  template <typename Archive>
593  void serialize(const Archive& ar) const {
594  // All of the interesting stuff happens in the counter serialization.
595  ar & archive::wrap_opaque(pointer_) & counter_;
596  }
597 
598  public:
599 
601 
604  friend std::ostream& operator<<(std::ostream& out, const RemoteReference<T>& ref) {
605  out << "RemoteReference( pointer=" << ref.pointer_ << " counter=" << ref.counter_ << ")";
606  return out;
607  }
608  }; // class RemoteReference
609 
610 
612 
616  template <typename T, typename U>
618  l.swap(r);
619  }
620 
621  namespace archive {
622 
623  // This function is not allowed. Therefore it is not implemented so that
624  // a compiler error is generated it it is called. This still does not
625  // prevent remote references from being wrapped as part of another object.
626  template <typename T>
627  archive_array<unsigned char> wrap_opaque(const RemoteReference<T>& t);
628 
629  // Remote counter serialization
630 
631  template <typename Archive>
632  struct ArchiveLoadImpl<Archive, detail::RemoteCounter > {
633  static inline void load(const Archive& ar, detail::RemoteCounter& c) {
634  c.load_(ar);
635  }
636  };
637 
638  template <typename Archive>
639  struct ArchiveStoreImpl<Archive, detail::RemoteCounter > {
640  static inline void store(const Archive& ar, const detail::RemoteCounter& c) {
641  c.store_(ar);
642  }
643  };
644 
645  } // namespace archive
646 } // namespace madness
647 
648 #endif // MADNESS_WORLD_WORLDREF_H__INCLUDED
Remote reference counter.
Definition: worldref.h:202
long use_count() const
Counter accessor.
Definition: worldref.h:332
World & get_world() const
Owning world accessor.
Definition: worldref.h:586
Definition: shared_ptr_bits.h:38
World active message that extends an RMI message.
Definition: worldam.h:81
Remote counter implementation object.
Definition: worldref.h:75
pointerT get() const
Reference pointer accessor.
Definition: worldref.h:509
Definition: worldhashmap.h:332
bool empty() const
Definition: worldref.h:334
ProcessID owner() const
Definition: worldref.h:338
std::ostream & operator<<(std::ostream &out, const RemoteCounter &counter)
Definition: worldref.cc:42
AmArg * new_am_arg(const A &a, const B &b, const C &c, const D &d, const E &e, const F &f, const G &g, const H &h, const I &i, const J &j)
Convenience template for serializing arguments into a new AmArg.
Definition: worldam.h:185
detail::ReferenceWrapper< T > const ref(T &t)
Reference wrapper factory function.
Definition: ref.h:132
long use_count() const
Remote and local counter accessor.
Definition: worldref.h:111
~RemoteReference()
Definition: worldref.h:460
Base class for remote counter implementation objects.
Definition: worldref.h:87
T * pointerT
Definition: worldref.h:410
const std::shared_ptr< T > & get_shared() const
Shared pointer accessor.
Definition: worldref.h:179
Interface templates for the archives (serialization)
void swap(WorldPtr< T > &l, WorldPtr< T > &r)
Swap the content of l with r.
Definition: worldptr.h:356
void reset()
Release this reference.
Definition: worldref.h:490
virtual void * key() const =0
Counter key accessor.
WorldPtr< implT >::worldidT get_worldid() const
Definition: worldref.h:344
bool dec_and_test()
Decrements the counter and returns true if the new value is zero.
Definition: atomicint.h:178
RemoteReference(const RemoteReference< U > &other)
Copy conversion constructor.
Definition: worldref.h:456
RemoteReference(World &w, const std::shared_ptr< T > &p)
Construct a remote reference to p.
Definition: worldref.h:439
Default store of a thingy via serialize(ar,t)
Definition: archive.h:708
World & get_world() const
Definition: worldref.h:345
Definition: worldhashmap.h:57
Tensor< typename Tensor< T >::scalar_type > arg(const Tensor< T > &t)
Return a new tensor holding the argument of each element of t (complex types only) ...
Definition: tensor.h:2429
U & reference
Definition: worldptr.h:51
WorldAmInterface & am
AM interface.
Definition: worldfwd.h:460
referenceT operator*() const
Reference object accessor.
Definition: worldref.h:528
RemoteCounter(World &w, const std::shared_ptr< T > &p)
Definition: worldref.h:309
unsigned long worldidT
World ID type.
Definition: worldptr.h:67
pointerT operator->() const
Reference object pointer accessor.
Definition: worldref.h:539
bool has_owner() const
Definition: worldref.h:337
virtual void * key() const
Counter key accessor.
Definition: worldref.h:186
const std::shared_ptr< T > & get_shared() const
Shared pointer accessor.
Definition: worldref.h:118
Simple structure used to manage references/pointers to remote instances.
Definition: worldref.h:59
ProcessID owner() const
Rank accessor.
Definition: worldptr.h:301
T * get() const
Definition: shared_ptr_bits.h:485
void swap(RemoteReference< U > &other)
Swap references.
Definition: worldref.h:564
worldidT get_worldid() const
World ID accessor.
Definition: worldptr.h:294
std::size_t erase(const keyT &key)
Definition: worldhashmap.h:503
const T1 &f1 return GTEST_2_TUPLE_() T(f0, f1)
void add_ref()
Increment the reference count.
Definition: worldref.h:128
World & get_world() const
World accessor.
Definition: worldptr.h:285
RemoteReference()
Makes a non-shared (no reference count) null pointer.
Definition: worldref.h:431
void swap(RemoteCounter &other)
Definition: worldref.h:346
Implements active message layer for World on top of RMI layer.
std::pair< iterator, bool > insert(const datumT &datum)
Definition: worldhashmap.h:469
Default load of a thingy via serialize(ar,t)
Definition: archive.h:718
bool is_local() const
Locally owned reference.
Definition: worldref.h:574
ProcessID owner() const
Reference owner accessor.
Definition: worldref.h:580
bool is_local() const
Definition: worldref.h:336
An integer with atomic set, get, read+inc, read+dec, dec+test operations.
Definition: atomicint.h:73
RMI::Request send(const ProcessID dest, am_handlerT op, const AmArg *arg, const int attr=RMI::ATTR_ORDERED, const bool managed=true)
Sends an unmanaged non-blocking active message.
Definition: worldam.h:386
A parallel world with full functionality wrapping an MPI communicator.
Definition: worldfwd.h:416
static void store(const Archive &ar, const detail::RemoteCounter &c)
Definition: worldref.h:640
bool unique() const
Definition: worldref.h:333
pointer get() const
Pointer accessor.
Definition: worldptr.h:195
bool unique() const
Get uniqueness.
Definition: worldref.h:555
int ProcessID
Used to clearly identify process number/rank.
Definition: worldtypes.h:37
RemoteCounter & operator=(const RemoteCounter &other)
Definition: worldref.h:315
RemoteCounterImpl(const std::shared_ptr< T > &p)
Definition: worldref.h:170
archive_array< unsigned char > wrap_opaque(const T *, unsigned int)
Factory function to wrap pointer to contiguous data as opaque (uchar) archive_array.
Definition: archive.h:827
bool has_owner() const
Check that the world pointer has an owner.
Definition: worldptr.h:185
void serialize(const Archive &ar) const
Serialize the remote reference.
Definition: worldref.h:593
RemoteCounter(const RemoteCounter &other)
Definition: worldref.h:301
RemoteCounterBase()
Definition: worldref.h:97
void swap(Vector< T, N > &l, Vector< T, N > &r)
Definition: array.h:308
const std::shared_ptr< T > & get_shared() const
Definition: worldref.h:341
A global pointer address, valid anywhere in the world.
Definition: worldptr.h:65
void print(const A &a)
Print a single item to std::cout terminating with new line.
Definition: print.h:122
virtual ~RemoteCounterBase()
Definition: worldref.h:98
RemoteReference(const RemoteReference< T > &other)
Copy constructor.
Definition: worldref.h:446
static void load(const Archive &ar, detail::RemoteCounter &c)
Definition: worldref.h:633
bool release()
Decrement the reference count.
Definition: worldref.h:141
RemoteReference< T > & operator=(const RemoteReference< T > &other)
Copy conversion assignment operator.
Definition: worldref.h:465
Holds machinery to set up Functions/FuncImpls using various Factories and Interfaces.
Definition: chem/atomutil.cc:45
detail::ptr_traits< T >::reference referenceT
Definition: worldref.h:409
const double c
Definition: gfit.cc:200
RemoteReference< T > & operator=(const RemoteReference< U > &other)
Copy conversion assignment operator.
Definition: worldref.h:476
long use_count() const
Reference count accessor.
Definition: worldref.h:549
void swap(mpfr::mpreal &x, mpfr::mpreal &y)
Definition: mpreal.h:3069
RemoteCounter()
Definition: worldref.h:299
virtual ~RemoteCounterImpl()
Definition: worldref.h:174
~RemoteCounter()
Definition: worldref.h:313
bool is_local() const
Check that the world pointer references a local pointer.
Definition: worldptr.h:179
const std::shared_ptr< T > & get_shared() const
Reference shared_ptr accssor.
Definition: worldref.h:518
Defines and implements a concurrent hashmap.