rambrain
managedPtr.h
Go to the documentation of this file.
1 /* rambrain - a dynamical physical memory extender
2  * Copyright (C) 2015 M. Imgrund, A. Arth
3  * mimgrund (at) mpifr-bonn.mpg.de
4  * arth (at) usm.uni-muenchen.de
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 3 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, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef MANAGEDPTR_H
21 #define MANAGEDPTR_H
22 
23 #include "managedMemory.h"
24 #include "rambrain_atomics.h"
25 #include "common.h"
26 #include "exceptions.h"
27 #include <type_traits>
28 #include <pthread.h>
29 
30 //Test classes
31 #ifdef BUILD_TESTS
32 class managedPtr_Unit_ChunkInUse_Test;
33 class managedPtr_Unit_GetLocPointer_Test;
34 class managedPtr_Unit_SmartPointery_Test;
35 class managedFileSwap_Unit_SwapSingleIsland_Test;
36 class managedFileSwap_Unit_SwapNextAndSingleIsland_Test;
37 
38 class adhereTo_Unit_LoadUnload_Test;
39 class adhereTo_Unit_LoadUnloadConst_Test;
40 class adhereTo_Unit_TwiceAdhered_Test;
41 class adhereTo_Unit_TwiceAdheredOnceUsed_Test;
42 #endif
43 
44 namespace rambrain
45 {
46 
47 template <class T>
48 class adhereTo;
49 
50 
51 //Convenience macros
53 #define ADHERETO(class,instance) adhereTo<class> instance##_glue(instance);\
54  class* instance = instance##_glue;
55 #define ADHERETOCONST(class,instance) const adhereTo<class> instance##_glue(instance);\
57  const class* instance = instance##_glue;
58 #define ADHERETOLOC(class,instance,locinstance) adhereTo<class> instance##_glue(instance);\
60  class* locinstance = instance##_glue;
61 #define ADHERETOLOCCONST(class,instance,locinstance) const adhereTo<class> instance##_glue(instance);\
63  const class* locinstance = instance##_glue;
64 
65 
66 
67 
68 
79 template <class T, int dim = 1>
80 class managedPtr
81 {
82 
83 public:
85  managedPtr ( const managedPtr<T, dim> &ref ) : n_elem ( ref.n_elem ), subPtrs ( new managedPtr < T, dim - 1 > [n_elem] ) {
86  for ( unsigned int i = 0; i < n_elem; ++i ) {
87  subPtrs[i] = ref.subPtrs[i];
88  }
89  }
90 
92  template <typename... ctor_args>
93  managedPtr ( unsigned int n_elem , ctor_args... Args ) : n_elem ( n_elem ), subPtrs ( new managedPtr < T, dim - 1 > [n_elem] ) {
94  for ( unsigned int i = 0; i < n_elem; ++i ) {
95  subPtrs[i] = managedPtr < T, dim - 1 > ( Args... );
96  }
97  }
98 
100  managedPtr() : managedPtr ( 1 ) {}
101 
104  delete[] subPtrs;
105  }
106 
109  n_elem = ref.n_elem;
110  delete [] subPtrs;
111  subPtrs = new managedPtr < T, dim - 1 > [n_elem];
112  for ( int i = 0; i < n_elem; ++i ) {
113  subPtrs[i] = ref.subPtrs[i];
114  }
115  return *this;
116  }
117 
119  managedPtr < T, dim - 1 > &operator[] ( int i ) {
120  return subPtrs[i];
121  }
122 
124  const managedPtr < T, dim - 1 > &operator[] ( int i ) const {
125  return subPtrs[i];
126  }
127 
128 private:
129  unsigned int n_elem;
130  managedPtr < T, dim - 1 > * subPtrs;
131 };
132 
133 
144 template <class T>
145 class managedPtr<T, 1>
146 {
147 public:
149  managedPtr ( const managedPtr<T, 1> &ref ) : chunk ( ref.chunk ), tracker ( ref.tracker ), n_elem ( ref.n_elem ) {
150  rambrain_atomic_add_fetch ( tracker, 1 );
151  }
152 
154  managedPtr() : managedPtr ( 1 ) {}
155 
157  template <typename... ctor_args>
158  managedPtr ( unsigned int n_elem , ctor_args... Args ) {
159  this->n_elem = n_elem;
160  tracker = new unsigned int;
161  ( *tracker ) = 1;
162  if ( n_elem == 0 ) {
163  chunk = NULL;
164  return;
165  }
166 
167 
168 #ifdef PARENTAL_CONTROL
169 
179  bool iamSyncer;
180  if ( pthread_mutex_trylock ( &managedMemory::parentalMutex ) == 0 ) {
181  //Could lock
182  iamSyncer = true;
183  } else {
184  //Could not lock. Perhaps, I already have a lock:
185  if ( pthread_equal ( pthread_self(), managedMemory::creatingThread ) ) {
186  iamSyncer = false;//I was called by my parents!
187  } else {
188  //I need to gain the lock:
189  rambrain_pthread_mutex_lock ( &managedMemory::parentalMutex );
190  iamSyncer = true;
191  }
192  }
193  //iamSyncer tells me whether I am the parent thread (not object!)
194 
195  //Set our thread id as the one without locking:
196  if ( iamSyncer ) {
197  managedMemory::creatingThread = pthread_self();
198 
199  }
200 #endif
201 
202  chunk = managedMemory::defaultManager->mmalloc ( sizeof ( T ) * n_elem );
203 
204 #ifdef PARENTAL_CONTROL
205  //Now call constructor and save possible children's sake:
206  memoryID savedParent = managedMemory::parent;
207  managedMemory::parent = chunk->id;
208 #endif
209 
210  setUse();
211  for ( unsigned int n = 0; n < n_elem; n++ ) {
212  new ( ( ( T * ) chunk->locPtr ) + n ) T ( Args... );
213  }
214  unsetUse();
215 #ifdef PARENTAL_CONTROL
216  managedMemory::parent = savedParent;
217  if ( iamSyncer ) {
219  //Let others do the job:
220  rambrain_pthread_mutex_unlock ( &managedMemory::parentalMutex );
221  }
222 #endif
223  }
224 
227  int trackerold = rambrain_atomic_sub_fetch ( tracker, 1 );
228  if ( trackerold == 0 ) {//Ensure destructor to be called only once.
229  mDelete<T>();
230  }
231  }
232 
234  inline unsigned int size() const {
235  return n_elem;
236  }
237 
239  bool prepareUse() const {
240  managedMemory::defaultManager->prepareUse ( *chunk, true );
241  return true;
242  }
243 
245  bool setUse ( bool writable = true, bool *tracker = NULL ) const {
246  if ( tracker )
247  if ( !rambrain_atomic_bool_compare_and_swap ( tracker, false, true ) ) {
248  waitForSwapin();
249  return false;
250  }
251  bool result = managedMemory::defaultManager->setUse ( *chunk , writable );
252 
253  return result;
254  }
255 
257  bool unsetUse ( unsigned int loaded = 1 ) const {
258  return managedMemory::defaultManager->unsetUse ( *chunk , loaded );
259  }
260 
263  if ( chunk ) {
264  if ( ref.chunk == chunk ) {
265  return *this;
266  }
267  if ( rambrain_atomic_sub_fetch ( tracker, 1 ) == 0 ) {
268  mDelete<T>();
269  }
270  }
271  n_elem = ref.n_elem;
272  chunk = ref.chunk;
273  tracker = ref.tracker;
274  rambrain_atomic_add_fetch ( tracker, 1 );
275  return *this;
276  }
277 
279  DEPRECATED T &operator[] ( int i ) {
280  managedPtr<T> &self = *this;
281  ADHERETOLOC ( T, self, loc );
282  return loc[i];
283  }
285  DEPRECATED const T &operator[] ( int i ) const {
286  const managedPtr<T> &self = *this;
287  ADHERETOLOCCONST ( T, self, loc );
288  return loc[i];
289  }
290 
294  T *getLocPtr() const {
295  if ( chunk->status != MEM_ALLOCATED_INUSE_WRITE ) {
296  waitForSwapin();
297  }
298  return ( T * ) chunk->locPtr;
299  }
300 
304  const T *getConstLocPtr() const {
305  if ( ! ( chunk->status & MEM_ALLOCATED_INUSE_READ ) ) {
306  waitForSwapin();
307  }
308  return ( T * ) chunk->locPtr;
309  }
310 
311 private:
313  unsigned int *tracker;
314  unsigned int n_elem;
315 
317  template <class G>
318  typename std::enable_if<std::is_class<G>::value>::type
319  mDelete ( ) const {
320  if ( n_elem > 0 ) {
321 
322  setUse();
323  for ( unsigned int n = 0; n < n_elem; n++ ) {
324  ( ( ( G * ) chunk->locPtr ) + n )->~G();
325  }
326  unsetUse();
328  }
329  delete tracker;
330  }
332  template <class G>
333  typename std::enable_if < !std::is_class<G>::value >::type
334  mDelete ( ) {
335  if ( n_elem > 0 ) {
337  }
338  delete tracker;
339  }
340 
346  void waitForSwapin() const {
347  //While in this case, we are not the guy who actually enforce the swapin, we never the less have to wait
348  //for the chunk to become ready. This is done in the following way:
349  if ( ! ( chunk->status & MEM_ALLOCATED ) ) { // We may savely check against this as use will be set by other adhereTo thread and cannot be undone as long as calling adhereTo exists
350  rambrain_pthread_mutex_lock ( &managedMemory::defaultManager->stateChangeMutex );
351  //We will burn a little bit of power here, eventually, but this is a very rare case.
352  while ( ! managedMemory::defaultManager->waitForSwapin ( *chunk, true ) ) {};
353  rambrain_pthread_mutex_unlock ( &managedMemory::defaultManager->stateChangeMutex );
354  }
355  }
356 
357 
358 
359 
360  template<class G>
361  friend class adhereTo;
362  template<class G>
363  friend class adhereToConst;
364 
365  //Test classes
366 #ifdef BUILD_TESTS
367  friend class ::managedPtr_Unit_ChunkInUse_Test;
368  friend class ::managedPtr_Unit_GetLocPointer_Test;
369  friend class ::managedPtr_Unit_SmartPointery_Test;
370  friend class ::managedFileSwap_Unit_SwapSingleIsland_Test;
371  friend class ::managedFileSwap_Unit_SwapNextAndSingleIsland_Test;
372  friend class ::adhereTo_Unit_TwiceAdheredOnceUsed_Test;
373 #endif
374 };
375 
376 
387 template <class T>
388 class adhereTo
389 {
390 public:
392  adhereTo ( const adhereTo<T> &ref ) : data ( ref.data ) {
395  if ( loadedWritable ) {
396  data->setUse ( loadedWritable );
397  }
398  if ( loadedReadable ) {
399  data->setUse ( loadedReadable );
400  }
401  };
402 
407  adhereTo ( const managedPtr<T> &data, bool loadImmediately = true ) : data ( &data ) {
408  if ( loadImmediately && data.size() != 0 ) {
409  data.prepareUse();
410  }
411 
412  }
413 
415  adhereTo ( const managedPtr<T> *data, bool loadImmediately = true ) : adhereTo ( *data, loadImmediately ) {};
416 
419  if ( loadedReadable ) {
420  data->unsetUse();
421  }
422  if ( loadedWritable ) {
423  data->unsetUse();
424  }
425  this->data = ref.data;
428 
429  if ( loadedWritable ) {
430  data->setUse ( loadedWritable );
431  }
432  if ( loadedReadable ) {
433  data->setUse ( loadedReadable );
434  }
435  return *this;
436  }
437 
439  operator const T *() { //This one is needed as c++ refuses to pick operator const T *() const as a default in this case
440  return * ( ( const adhereTo * ) this );
441  }
443  operator const T *() const {
444  if ( data->size() == 0 ) {
445  return NULL;
446  }
447  if ( !loadedReadable ) {
448  data->setUse ( false, &loadedReadable );
449  }
450  return data->getConstLocPtr();
451  }
453  operator T *() {
454  if ( data->size() == 0 ) {
455  return NULL;
456  }
457  if ( !loadedWritable ) {
458  data->setUse ( true, &loadedWritable );
459  }
460  return data->getLocPtr();
461  }
464  unsigned char loaded = 0;
465  loaded = ( loadedReadable ? 1 : 0 ) + ( loadedWritable ? 1 : 0 );
466  if ( loaded > 0 && data->size() != 0 ) {
467  data->unsetUse ( loaded );
468  }
469  }
470 private:
472 
473  mutable bool loadedWritable = false;
474  mutable bool loadedReadable = false;
475 
476  //Test classes
477 #ifdef BUILD_TESTS
478  friend class ::adhereTo_Unit_LoadUnload_Test;
479  friend class ::adhereTo_Unit_LoadUnloadConst_Test;
480  friend class ::adhereTo_Unit_TwiceAdhered_Test;
481  friend class ::adhereTo_Unit_TwiceAdheredOnceUsed_Test;
482 #endif
483 };
484 
491 {
492 public:
494  if ( !locksByUser ) {
495  start();
496  }
497  };
499  if ( !locksByUser ) {
500  stop();
501  }
502  }
504  void stop() {
505  rambrain_pthread_mutex_unlock ( &mutex );
506  }
508  void start() {
509  rambrain_pthread_mutex_lock ( &mutex );
510  }
511 private:
512  static pthread_mutex_t mutex; // is defined in managedMemory.cpp
514 
515 };
516 
518 #define LISTOFINGREDIENTS rambrainGlobalCriticalSectionControl rambrain_section_control;
519 
520 
521 }
522 
523 #endif
524 
managedPtr< T, dim-1 > * subPtrs
Definition: managedPtr.h:130
adhereTo(const managedPtr< T > *data, bool loadImmediately=true)
Provides the same functionality as the other constructor but accepts a managedPtr pointer as argument...
Definition: managedPtr.h:415
Main class to allocate memory that is managed by the rambrain memory defaultManager in a multidimensi...
Definition: managedPtr.h:145
adhereTo< T > & operator=(const adhereTo< T > &ref)
Simple assignment operator.
Definition: managedPtr.h:418
memoryID id
an ID to identify the object in scheduler or elsewhere
unsigned int n_elem
Definition: managedPtr.h:129
const T * getConstLocPtr() const
returns const local pointer to object
Definition: managedPtr.h:304
void * locPtr
pointer to the actual data in RAM
bool setUse(memoryID id)
Convenience interface for setUse( managedMemoryChunk &chunk, bool writeAccess )
Main class to fetch memory that is managed by rambrain for actual usage.
Definition: managedPtr.h:48
uint64_t memoryID
adhereTo(const adhereTo< T > &ref)
copy constructor
Definition: managedPtr.h:392
bool prepareUse(rambrain::managedMemoryChunk &chunk, bool acquireLock=true)
Triggers swapin of chunk.
adhereTo(const managedPtr< T > &data, bool loadImmediately=true)
constructor fetching data
Definition: managedPtr.h:407
Main class to allocate memory that is managed by the rambrain memory defaultManager.
Definition: managedMemory.h:54
rambrainGlobalCriticalSectionControl(bool locksByUser=false)
Definition: managedPtr.h:493
static managedMemory * defaultManager
static memoryID parent
const managedPtr< T > * data
Definition: managedPtr.h:471
managedPtr< T, dim > & operator=(const managedPtr< T, dim > &ref)
assignment operator
Definition: managedPtr.h:108
std::enable_if< std::is_class< G >::value >::type mDelete() const
This function manages correct deallocation for array elements having a destructor.
Definition: managedPtr.h:319
managedPtr(unsigned int n_elem, ctor_args...Args)
instantiates managedPtr containing n_elem elements in the current dimension and passes Args as argume...
Definition: managedPtr.h:93
managedPtr(const managedPtr< T, dim > &ref)
copy ctor
Definition: managedPtr.h:85
unsigned int size() const
Simple getter.
Definition: managedPtr.h:234
bool prepareUse() const
tells the memory manager to possibly swap in chunk for near future use
Definition: managedPtr.h:239
void mfree(rambrain::memoryID id, bool inCleanup=false)
this function unregisters and deallocates a chunk
~managedPtr()
destructor
Definition: managedPtr.h:103
managedPtr(const managedPtr< T, 1 > &ref)
copy ctor
Definition: managedPtr.h:149
void stop()
stop pulling critical ingredients in a multithreaded situation
Definition: managedPtr.h:504
std::enable_if< !std::is_class< G >::value >::type mDelete()
This function manages correct deallocation for array elements lacking a destructor.
Definition: managedPtr.h:334
manages all managed Chunks of raw memory
managedMemoryChunk * mmalloc(global_bytesize sizereq)
allocates and registers a new raw memory chunk of size sizereq to be filled in by managedPtr ...
managedMemoryChunk * chunk
Definition: managedPtr.h:312
void start()
start pulling of critical ingredients in a multithreaded situation
Definition: managedPtr.h:508
managedPtr()
with no arguments given, instantiates an array with one element
Definition: managedPtr.h:154
T * getLocPtr() const
returns local pointer to object
Definition: managedPtr.h:294
bool setUse(bool writable=true, bool *tracker=NULL) const
Atomically sets use to a chunk if tracker is not already set to true. returns whether we set use or n...
Definition: managedPtr.h:245
bool unsetUse(unsigned int loaded=1) const
unsets use count on memory chunk
Definition: managedPtr.h:257
this class marks a section as globally critical. Only one thread can process any section where such a...
Definition: managedPtr.h:490
managedPtr< T, dim-1 > & operator[](int i)
simple getter for this dimension
Definition: managedPtr.h:119
static pthread_t creatingThread
void waitForSwapin() const
: indefinitely waits for swapin of the chunk While it would have been desirable to throw exceptions w...
Definition: managedPtr.h:346
static pthread_mutex_t parentalMutex
managedPtr(unsigned int n_elem, ctor_args...Args)
instantiates managedPtr containing n_elem elements and passes Args as arguments to the constructor of...
Definition: managedPtr.h:158
~adhereTo()
destructor
Definition: managedPtr.h:463
bool unsetUse(memoryID id)
Convenience interface for unsetUse ( managedMemoryChunk &chunk, bool writeAccess ) ...
managedPtr()
with no arguments given, instantiates an array with one element
Definition: managedPtr.h:100