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

Tekkotsu v2.4.1
Generated Tue Aug 16 16:32:48 2005 by Doxygen 1.4.4