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

Tekkotsu v4.0
Generated Thu Nov 22 00:54:55 2007 by Doxygen 1.5.4