Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

SharedObject.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_SharedObject_h
00003 #define INCLUDED_SharedObject_h
00004 
00005 #include "RCRegion.h"
00006 #include <stdexcept>
00007 #include <typeinfo>
00008 
00009 //! It's nice to have a parent class of SharedObject (which is what you probably want to be reading) so that you can pass around the data structure without worrying about what type is inside the shared memory region.
00010 /*! See MotionManager for an example on how to use this. */
00011 class SharedObjectBase {
00012 public:
00013   //! when passed to the SharedObject constructor, indicates that no RCRegion should be created
00014   struct NoInit {};
00015   
00016   void* data() const { return rcr->Base(); } //!< returns a pointer to the data region
00017   RCRegion * getRegion() const { return rcr; } //!< returns the OPEN-R memory region, should you need it
00018   
00019   virtual ~SharedObjectBase() {} //!< destructor
00020   
00021 #ifndef PLATFORM_APERIOS
00022   //! return the next region serial number -- doesn't actually increment it though, repeated calls will return the same value until the value is actually used
00023   static unsigned int getNextKey() { return serialNumber+1; }
00024 #endif
00025 
00026   //! assignment, adds a reference to the existing region (shallow copy)
00027   SharedObjectBase& operator=(const SharedObjectBase& sob) {
00028     if(rcr==sob.rcr)
00029       return *this;
00030     removeRef();
00031     rcr=sob.rcr;
00032     if(rcr!=NULL)
00033       rcr->AddReference();
00034     return *this;
00035   }
00036   
00037 protected:
00038   //! constructor, protected because you shouldn't need to create this directly, just a common interface to all templates of SharedObject
00039   SharedObjectBase() : rcr(NULL) {}
00040   //! copy constructor, adds a reference to the existing region (shallow copy)
00041   SharedObjectBase(const SharedObjectBase& sob) : rcr(sob.rcr) {
00042     if(rcr!=NULL)
00043       rcr->AddReference();
00044   }
00045 
00046   //!removes a reference from #rcr, and if necessary, destructs its data
00047   virtual void removeRef()=0;
00048   
00049   RCRegion * rcr; //!< the pointer to the shared memory region this is in charge of
00050   
00051 #ifndef PLATFORM_APERIOS
00052   static unsigned int serialNumber; //!< incremented for each region created so they will all have unique IDs
00053 #endif
00054 };  
00055 
00056 
00057 //! This templated class allows convenient creation of any type of class wrapped in a shared memory region
00058 /*! @see MotionManager for an example on how to use this.*/
00059 template<class MC>
00060 class SharedObject : public SharedObjectBase {
00061 public:
00062   
00063   //!if you really need more than 5 arguments for your class, well, you're one crazy puppy but if you really want to, just make more like shown... (yay templates!)
00064   //!@name templated contructors - allows you to pass constructor arguments on to the object being created
00065 
00066   //! Creates the class with the default constructor
00067   SharedObject() : SharedObjectBase() {
00068     rcr=createRCRegion();
00069     new (rcr->Base()) MC;
00070   }
00071   //! Creates the class, passing its constructor t1
00072   template<class T1> explicit SharedObject(const T1& t1) : SharedObjectBase() {
00073     rcr=createRCRegion();
00074     new (rcr->Base()) MC(t1);
00075   }
00076   //! Creates the class, passing its constructor t1 and t2
00077   template<class T1, class T2> SharedObject(const T1& t1, const T2& t2) : SharedObjectBase(){
00078     rcr=createRCRegion();
00079     new (rcr->Base()) MC(t1,t2);
00080   }
00081   //! Creates the class, passing its constructor t1, t2, and t3
00082   template<class T1, class T2, class T3> SharedObject(const T1& t1, const T2& t2, const T3& t3) : SharedObjectBase(){
00083     rcr=createRCRegion();
00084     new (rcr->Base()) MC(t1,t2,t3);
00085   }
00086   //! Creates the class, passing its constructor t1, t2, t3 and t4
00087   template<class T1, class T2, class T3, class T4> SharedObject(const T1& t1, const T2& t2, const T3& t3, const T4& t4) : SharedObjectBase(){
00088     rcr=createRCRegion();
00089     new (rcr->Base()) MC(t1,t2,t3,t4);
00090   }
00091   //! Creates the class, passing its constructor t1, t2, t3, t4 and t5 - if you need more arguments, just add them
00092   template<class T1, class T2, class T3, class T4, class T5> SharedObject(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5) : SharedObjectBase(){
00093     rcr=createRCRegion();
00094     new (rcr->Base()) MC(t1,t2,t3,t4,t5);
00095   }
00096   //@}
00097 
00098   //! a no-op constructor, so you can transfer a SharedObject created elsewhere with operator=() later
00099   SharedObject(const SharedObjectBase::NoInit&) : SharedObjectBase() {}
00100   
00101   //! copy constructor adds a reference to the underlying RCRegion, allowing the SharedObject instances to "share" the region
00102   SharedObject(const SharedObject& sh) : SharedObjectBase(sh) {}
00103   
00104   //! Constructs from a pre-existing region, laying claim to the caller's reference to the region - region's creator is responsible for initialization
00105   /*! In other words, this SharedObject doesn't addReference, but will
00106    *  removeReference when the time is right (upon destruction).  If
00107    *  you want to maintain an reference of your own to the region, you
00108    *  will need to call addReference yourself.
00109    *
00110    *  In comparison, the copy constructor will add a reference to the
00111    *  underlying RCRegion and "share" the RCRegion with the original
00112    *  SharedObject */
00113   explicit SharedObject(RCRegion * r) : SharedObjectBase() {
00114     rcr=r;
00115     if(rcr->Size()!=sizeof(MC)) {
00116 #ifdef PLATFORM_APERIOS
00117       std::cerr << "ERROR: SharedObject(RCRegion* r) region size ("<<rcr->Size()<<") does not match size of SharedObject type ("<<sizeof(MC)<<")" << std::endl;
00118 #else
00119       std::cerr << "ERROR: SharedObject(RCRegion* r) region "<<rcr->ID().key<<" size ("<<rcr->Size()<<") does not match size of SharedObject type ("<<sizeof(MC)<<")" << std::endl;
00120 #endif
00121       throw std::invalid_argument("SharedObject(RCRegion* r): region size does not match sizeof(type)");
00122     }
00123   }
00124   
00125   //! destructor, removes reference to shared region
00126   virtual ~SharedObject() { removeRef(); }
00127   
00128   MC* operator->() const { return dataCasted(); } //!< smart pointer to the underlying class
00129   MC& operator*() const { return *dataCasted(); } //!< smart pointer to the underlying class
00130   MC& operator[](int i) const { return dataCasted()[i]; } //!< smart pointer to the underlying class
00131   
00132 protected:
00133   MC* dataCasted() const { return static_cast<MC*>(data()); } //!< returns a correctly typed pointer to the object's memory
00134   
00135   //!removes a reference from #rcr, and if necessary, destructs its data
00136   virtual void removeRef() {
00137     if(rcr!=NULL) {
00138       //std::cout << "~SharedObjectBase(): rcr->NumberOfReference()==" << rcr->NumberOfReference() << std::endl;
00139       if(rcr->NumberOfReference()>0) {
00140         if(rcr->NumberOfReference()==1)
00141           dataCasted()->~MC(); //call destructor
00142         rcr->RemoveReference();
00143       } else
00144         std::cerr << "WARNING: SharedObjectBase destructed without reference" << std::endl;
00145       rcr=NULL;
00146     }
00147   }
00148   
00149   //! creates and returns RCRegion of correct size for current class.  Adds a reference (which is removed in the destructor)
00150   static RCRegion * createRCRegion() {
00151 #ifdef PLATFORM_APERIOS
00152     RCRegion * r = new RCRegion(calcsize());
00153 #else
00154     char name[RCRegion::MAX_NAME_LEN];
00155     unsigned int suffixlen=snprintf(name,RCRegion::MAX_NAME_LEN,".%d.%d",ProcessID::getID(),++serialNumber);
00156     if(suffixlen>RCRegion::MAX_NAME_LEN)
00157       suffixlen=RCRegion::MAX_NAME_LEN;
00158     snprintf(name,RCRegion::MAX_NAME_LEN,"Sh.%.*s.%d.%d",RCRegion::MAX_NAME_LEN-suffixlen-3,typeid(MC).name(),ProcessID::getID(),++serialNumber);
00159     name[RCRegion::MAX_NAME_LEN-1]='\0';
00160     RCRegion * r = new RCRegion(name,calcsize());
00161 #endif
00162     //cout << "SIZE is " << r->Size() << endl;
00163     //cout << "BASE is " << (void*)r->Base() << endl;
00164     //std::cout << "createRCRegion(): rcr->NumberOfReference()==" << r->NumberOfReference() << std::endl;
00165     //r->addReference();
00166     //std::cout << "createRCRegion()NOW: rcr->NumberOfReference()==" << r->NumberOfReference() << std::endl;
00167     return r;
00168   }
00169 
00170   //!Calculates the size of the memory region to be used, (on Aperios, rounding up to the nearest page size)
00171   /*! Not sure this is completely necessary, but may be nice.  Of course, this also means even
00172    *  small regions are going to be at least 4K (current page size)  If memory gets tight or we
00173    *  get a lot of little regions floating around, this might be worth checking into */
00174   static unsigned int calcsize() {
00175 #ifndef PLATFORM_APERIOS
00176     return sizeof(MC);
00177 #else
00178     size_t size = sizeof(MC);
00179     sError error;
00180     size_t page_size;
00181     error = GetPageSize(&page_size);
00182     if (error != sSUCCESS) {
00183       cout << "error: " << error << " getting page size in SharedMem" << endl;
00184       page_size = 4096;
00185     }
00186     
00187     int new_size,num_pages;
00188     num_pages = (size+page_size-1)/page_size;
00189     new_size = num_pages*page_size;
00190     //cout << "req" << size << "new" << new_size << "ps" << page_size << endl;
00191     /*
00192     cout << "data size is " << sizeof(MC) << endl;
00193     cout << "PAGE is " << page_size << endl;
00194     cout << "reserved " << new_size << " bytes" << endl;
00195     */
00196     return new_size;
00197 #endif //!PLATFORM_APERIOS
00198   }
00199 };
00200 
00201 /*! @file
00202  * @brief Defines SharedObject, a wrapper for objects in order to facilitate sending them between processes
00203  * @author ejt (Creator)
00204  */
00205 
00206 #endif //INCLUDED_SharedObject_h

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:51 2016 by Doxygen 1.6.3