Tekkotsu Homepage | Demos | Overview | Downloads | Dev. Resources | Reference | Credits |
RCRegion.hGo to the documentation of this file.00001 //-*-c++-*- 00002 #ifdef PLATFORM_APERIOS 00003 # include <OPENR/RCRegion.h> 00004 #else 00005 # ifndef INCLUDED_RCRegion_h_ 00006 # define INCLUDED_RCRegion_h_ 00007 00008 #include "Shared/ReferenceCounter.h" 00009 #include "ProcessID.h" 00010 #include "Shared/plist.h" 00011 #include <sys/types.h> 00012 #include <map> 00013 #include <exception> 00014 00015 /* Do you want to use the SysV shared memory call interface 00016 * or the POSIX shared memory interface? They have different 00017 * strengths/weaknesses on different platforms... :-/ */ 00018 00019 /*! @def POSIX_SHM 00020 * @brief If TEKKOTSU_SHM_STYLE is set to POSIX_SHM, POSIX style shared memory will be used (shm_open, shm_unlink, mmap, munmap, ...); 00021 * This is the default shared memory interface, both portable and stable. By default, regular open() and unlink() 00022 * will be used to implement the regions using file-backed shared memory. If you define USE_UNBACKED_SHM, 00023 * RCRegion will use shm_open/shm_unlink instead. Unbacked shared memory is nice because there's no 00024 * interaction with your filesystem, but isn't quite as portable. (Cygwin didn't seem to like it too much...) */ 00025 00026 /*! @def SYSV_SHM 00027 * @brief If TEKKOTSU_SHM_STYLE is set to SYSV_SHM, SysV style shared memory will be used (shmget, shmctl, shmat, shmdt, ...) 00028 * SysV style seems to stick around following a program crash, and can't be unlinked pre-emptively while still in use. 00029 * Since it appears many systems also limit the number of shared memory regions (via a sysctl configuration), leaking 00030 * regions following repeated crashes during development gets annoying. */ 00031 00032 /*! @def NO_SHM 00033 * @brief If TEKKOTSU_SHM_STYLE is set to NO_SHM, all shared memory operations become straight new/delete's; this restricts the program to using threads in a single process */ 00034 00035 /*! @def TEKKOTSU_SHM_STYLE 00036 * @brief Can be set to one of POSIX_SHM, SYSV_SHM, or NO_SHM */ 00037 00038 #ifndef POSIX_SHM 00039 # define POSIX_SHM 1 00040 #endif 00041 #ifndef SYSV_SHM 00042 # define SYSV_SHM 2 00043 #endif 00044 #ifndef NO_SHM 00045 # define NO_SHM 3 00046 #endif 00047 #ifndef TEKKOTSU_SHM_STYLE 00048 # define TEKKOTSU_SHM_STYLE POSIX_SHM 00049 #endif 00050 00051 #if TEKKOTSU_SHM_STYLE!=SYSV_SHM && TEKKOTSU_SHM_STYLE!=POSIX_SHM && TEKKOTSU_SHM_STYLE!=NO_SHM 00052 # error Unknown TEKKOTSU_SHM_STYLE setting 00053 #endif 00054 00055 namespace ThreadNS { 00056 class Lock; 00057 } 00058 00059 //! provides compatability with the OPEN-R type of the same name 00060 class RCRegion { 00061 public: 00062 00063 // The type of region Identifier depends on the style of shared memory being used 00064 00065 #if TEKKOTSU_SHM_STYLE==SYSV_SHM 00066 //! contains all information needed to attach this region from a different process 00067 struct Identifier { 00068 Identifier() : key(), shmid(), size(0) {} 00069 key_t key; //!< key_t is defined by system headers, contains system region info 00070 int shmid; //!< an integer key value which identifies the region 00071 size_t size; //!< the size of the region 00072 }; 00073 00074 #elif TEKKOTSU_SHM_STYLE==POSIX_SHM || TEKKOTSU_SHM_STYLE==NO_SHM 00075 //! maximum guaranteed length for users' region names (might have a little leeway depending on process ID prefix or tmp path prefix) 00076 static const unsigned int MAX_NAME_LEN=64; 00077 00078 //! contains all information needed to attach this region from a different process 00079 struct Identifier { 00080 Identifier() : size(0) {} //!< constructor 00081 char key[MAX_NAME_LEN]; //!< a string name for the key 00082 size_t size; //!< size of the region 00083 }; 00084 00085 # if TEKKOTSU_SHM_STYLE==POSIX_SHM 00086 # ifndef USE_UNBACKED_SHM 00087 static plist::Primitive<std::string> shmRoot; //!< determines location of the file backing within file system 00088 # endif 00089 static plist::Primitive<bool> useUniqueMemoryRegions; //!< if true, prefixes region names with #rootPID 00090 static pid_t rootPID; //!< this is the pid of the original process, used for unique names of memory regions; pid_t is from sys/types.h 00091 # endif 00092 #endif 00093 00094 00095 // The constructors, offering either an Aperios-compatable version, 00096 // or a linux-specific version offering explicit control over the 00097 // key value, aids better debugging 00098 00099 #if TEKKOTSU_SHM_STYLE==SYSV_SHM 00100 //! constructor (OPEN-R compatability) 00101 explicit RCRegion(size_t sz) 00102 : id(), base(NULL), references(NULL) 00103 { init(sz,nextKey,true); } 00104 //! constructor, name isn't used for sysv-style shared memory (not OPEN-R compatable) 00105 /*! could hash the name to generate key...? */ 00106 RCRegion(const std::string&, size_t sz) 00107 : id(), base(NULL), references(NULL) 00108 { init(sz,nextKey,true); } 00109 00110 #elif TEKKOTSU_SHM_STYLE==POSIX_SHM || TEKKOTSU_SHM_STYLE==NO_SHM 00111 //! constructor (OPEN-R compatability, name is autogenerated) 00112 explicit RCRegion(size_t sz) 00113 : id(), base(NULL), references(NULL) 00114 { 00115 char name[RCRegion::MAX_NAME_LEN]; 00116 snprintf(name,RCRegion::MAX_NAME_LEN,"Rgn.%d.%u",ProcessID::getID(),static_cast<unsigned int>(++nextKey)); 00117 name[RCRegion::MAX_NAME_LEN-1]='\0'; 00118 init(sz,name,true); 00119 } 00120 //! constructor, specify your own name for better debugging accountability (not OPEN-R compatable) 00121 RCRegion(const std::string& name, size_t sz) 00122 : id(), base(NULL), references(NULL) 00123 { init(sz,name,true); } 00124 #endif 00125 00126 //! requests that a specified RCRegion be loaded into the current process's memory space 00127 static RCRegion * attach(const Identifier& rid); 00128 00129 char * Base() const { return base; } //!< the pointer to the shared memory region 00130 size_t Size() const { return id.size; } //!< the size of the shared memory region 00131 static void setNextKey(key_t k) { nextKey=k; } //!< sets the next key to be used for automatic assignment to new regions 00132 static key_t getNextKey() { return nextKey+1; } //!< 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 00133 const Identifier& ID() const { return id; } //!< returns the identifier of this region 00134 00135 int NumberOfReference() const { return references[ProcessID::NumProcesses]; } //!< number of total references to this region, total of all processes 00136 int NumberOfLocalReference() const { return references[ProcessID::getID()]; } //!< number of references to the region from the current process (in the ProcessID threadgroup sense, not necessarily system-process) 00137 void AddReference(); //!< adds a reference from the current process 00138 void RemoveReference(); //!< removes a reference from the current process 00139 void AddSharedReference(); //!< adds a reference which is held by another shared memory region 00140 void RemoveSharedReference(); //!< removes a reference which is held by another shared memory region 00141 00142 static void aboutToFork(ProcessID::ProcessID_t newID); //!< does housekeeping to mark the region as attached and the same number of references in the new process as well 00143 static void faultShutdown(); //!< try to unload all regions in a clean manner 00144 00145 #if TEKKOTSU_SHM_STYLE==SYSV_SHM 00146 //! a map from the shared memory key type to the actual region structure 00147 typedef std::map<key_t,RCRegion*> attachedRegions_t; 00148 #elif TEKKOTSU_SHM_STYLE==POSIX_SHM || TEKKOTSU_SHM_STYLE==NO_SHM 00149 //! a map from the shared memory key type to the actual region structure 00150 typedef std::map<std::string,RCRegion*> attachedRegions_t; 00151 #endif 00152 static unsigned int NumberOfAttach() { return attachedRegions.size(); } //!< returns the number of regions which are currently attached in the process 00153 00154 //! Returns an iterator to the beginning of the attached regions mapping -- it->first is the key, it->second is the RCRegion* 00155 /*! If you need thread-safety (i.e. another thread may attach/detach while you are iterating), pass true, and be sure to use attachedAdvance() to increment the iterator! 00156 * This doesn't prevent other threads from attaching/detaching regions, it only prevents detaching the one you're on. 00157 * When you're done with a thread-safe iterator, either attachedAdvance() it off the end, or manually call RemoveReference() on the iterator's final region */ 00158 static attachedRegions_t::const_iterator attachedBegin(bool threadSafe); 00159 //! Returns an iterator to the end of the attached regions -- it->first is the key, it->second is the RCRegion* 00160 /*! If you need thread-safety (i.e. another thread may attach/detach while you are iterating), be sure to use attachedAdvance() to decrement the iterator! 00161 * This doesn't prevent other threads from attaching/detaching regions, it only prevents detaching the one you're on. */ 00162 static attachedRegions_t::const_iterator attachedEnd(); 00163 //! Increments the attached region iterator in a thread-safe way -- only use this if you previously passed 'true' to begin(), or are decrementing from end() 00164 /*! If you are using an iterator obtained without thread-safety, just increment it normally -- don't switch to this or it will screw up reference counting. 00165 * If you insist on switching back and forth between thread-safe advance (this function) and normal iterator advancing, you will need to add a reference to the current iterator's region before calling this. 00166 * When you're done, either advance off the end, or manually call RemoveReference() on the iterator's final region */ 00167 static void attachedAdvance(attachedRegions_t::const_iterator& it, int x=1); 00168 00169 //! Different methods of handling regions with conflicting keys 00170 enum ConflictResolutionStrategy { 00171 RENAME, //!< try another key until we find one that works (better for SYSV, maybe not so smart for POSIX) 00172 REPLACE, //!< delete the other region and try again (better for POSIX, maybe not so smart for SYSV) 00173 EXIT //!< go home and cry about it 00174 }; 00175 00176 static void setConflictResolution(ConflictResolutionStrategy crs) { conflictStrategy=crs; } //!< sets #conflictStrategy 00177 static ConflictResolutionStrategy getConflictResolution() { return conflictStrategy; } //!< returns #conflictStrategy 00178 00179 static void setMultiprocess(bool mp) { multiprocess=mp; } //!< sets #multiprocess 00180 static bool getMultiprocess() { return multiprocess; } //!< returns #multiprocess 00181 00182 00183 protected: 00184 //! this protected constructor is used for attaching regions previously created by another process (see attach()) 00185 RCRegion(const Identifier& rid) 00186 : id(), base(NULL), references(NULL) 00187 { init(rid.size,rid.key,false); } 00188 00189 ~RCRegion(); //!< prevents stack allocation -- needs to be heap allocated and reference counted 00190 00191 //! the alignment multiple of the extra space at the end of the region 00192 static const unsigned int align=sizeof(unsigned int); 00193 //! the amount of space to leave at the end of the region for housekeeping (reference counts) 00194 static const unsigned int extra=sizeof(unsigned int)*(ProcessID::NumProcesses+1); 00195 //! returns the size of the region to be allocated, given the size requested by the client 00196 static unsigned int calcRealSize(unsigned int size); 00197 00198 //! intializes and returns #staticLock 00199 static ThreadNS::Lock& getStaticLock(); 00200 00201 #if TEKKOTSU_SHM_STYLE==SYSV_SHM 00202 //! initializes the region's information, either creating a new shared memory region or attempting to connect to a pre-existing one 00203 void init(size_t sz, key_t sug_key, bool create); 00204 #elif TEKKOTSU_SHM_STYLE==POSIX_SHM 00205 //! returns the qualified version of this region's key (see getQualifiedName(const std::string& key) ) 00206 std::string getQualifiedName() const { return getQualifiedName(id.key); } 00207 //! wraps the region's key with a root path prefix and optionally a PID suffix (see #useUniqueMemoryRegions and #shmRoot) 00208 static std::string getQualifiedName(const std::string& key); 00209 //! opens a region either in "pure" shared memory, or in file-backed shared memory, based on whether USE_UNBACKED_SHM is defined 00210 int openRegion(int mode) const; 00211 //! unlinks a region either in "pure" shared memory, or in file-backed shared memory, based on whether USE_UNBACKED_SHM is defined 00212 bool unlinkRegion() const; 00213 //! initializes the region's information, either creating a new shared memory region or attempting to connect to a pre-existing one 00214 void init(size_t sz, const std::string& name, bool create); 00215 #elif TEKKOTSU_SHM_STYLE==NO_SHM 00216 //! initializes the region's information, either pointing to an existing region or allocating a new one 00217 void init(size_t sz, const std::string& name, bool create); 00218 #endif 00219 00220 //! controls what to do about creating a region with a conflicting key (i.e. another region already exists with the same key) 00221 static ConflictResolutionStrategy conflictStrategy; 00222 //! set to true if we are shutting down because of an error, and trying to unload shared regions to avoid leaking beyond program scope 00223 static bool isFaultShutdown; 00224 //! set to false if the different "processes" are just threads (and thus the last process reference shouldn't actually trigger unlinking a region 00225 static bool multiprocess; 00226 00227 static ThreadNS::Lock* staticLock; //!< a lock over all static RCRegion members for the current process, must be obtained before changing reference counts or attaching/detaching regions 00228 00229 static key_t nextKey; //!< serial number of next key -- starts at 1024 for TEKKOTSU_SHM_STYLE==SYSV_SHM, 0 for POSIX_SHM 00230 static attachedRegions_t attachedRegions; //!< a mapping of key values to RCRegion pointers of the attached region 00231 00232 Identifier id; //!< key values for the region, namely the system key type (either an integer or string depending on TEKKOTSU_SHM_STYLE) and the size of the region 00233 char * base; //!< pointer to the region's user data 00234 unsigned int * references; //!< pointer to the per-process reference counts (stored within the shared region!) 00235 00236 private: 00237 RCRegion(const RCRegion& r); //!< don't call 00238 RCRegion& operator=(const RCRegion& r); //!< don't call 00239 }; 00240 00241 /*! @file 00242 * @brief Describes RCRegion, which provides compatability with the OPEN-R type of the same name 00243 * @author ejt (Creator) 00244 * 00245 * $Author: ejt $ 00246 * $Name: tekkotsu-4_0 $ 00247 * $Revision: 1.12 $ 00248 * $State: Exp $ 00249 * $Date: 2007/11/13 16:17:46 $ 00250 */ 00251 00252 # endif 00253 #endif |
Tekkotsu v4.0 |
Generated Thu Nov 22 00:54:55 2007 by Doxygen 1.5.4 |