Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

RCRegion.cc

Go to the documentation of this file.
00001 #ifndef PLATFORM_APERIOS
00002 #include "RCRegion.h"
00003 #include "Shared/MarkScope.h"
00004 #include "Shared/debuget.h"
00005 #include "Shared/plist.h"
00006 #include "Thread.h"
00007 #include <unistd.h>
00008 #include <sstream>
00009 #include <sys/stat.h>
00010 #include <errno.h>
00011 
00012 #if TEKKOTSU_SHM_STYLE!=SYSV_SHM && TEKKOTSU_SHM_STYLE!=POSIX_SHM && TEKKOTSU_SHM_STYLE!=NO_SHM
00013 #  error Unknown TEKKOTSU_SHM_STYLE setting
00014 #endif
00015 
00016 #if TEKKOTSU_SHM_STYLE==SYSV_SHM
00017 #  include <sys/ipc.h>
00018 #  include <sys/shm.h>
00019 #elif TEKKOTSU_SHM_STYLE==POSIX_SHM
00020 #  include <sys/mman.h>
00021 #  include <sys/fcntl.h>
00022 #  ifdef USE_UNBACKED_SHM
00023 plist::Primitive<bool> RCRegion::useUniqueMemoryRegions(false);
00024 #  else
00025 plist::Primitive<std::string> RCRegion::shmRoot("/tmp/tekkotsu_sim/");
00026 plist::Primitive<bool> RCRegion::useUniqueMemoryRegions(true);
00027 #  endif
00028 pid_t RCRegion::rootPID(::getpid());
00029 #endif
00030 
00031 using namespace std;
00032 
00033 #if TEKKOTSU_SHM_STYLE==SYSV_SHM
00034 key_t RCRegion::nextKey=1024;
00035 #elif TEKKOTSU_SHM_STYLE==POSIX_SHM || TEKKOTSU_SHM_STYLE==NO_SHM
00036 key_t RCRegion::nextKey=0;
00037 #endif
00038 
00039 RCRegion::attachedRegions_t RCRegion::attachedRegions;
00040 bool RCRegion::isFaultShutdown=false;
00041 bool RCRegion::multiprocess=true;
00042 Thread::Lock* RCRegion::staticLock=NULL;
00043 
00044 
00045 #if TEKKOTSU_SHM_STYLE==SYSV_SHM
00046 //under SYSV shared memory, the keys are just numbers, and it's just as likely that the conflicted
00047 //region belongs to an unrelated process as it is that the region is from a previous run -- so we
00048 //take the safe route and rename our own keys
00049 RCRegion::ConflictResolutionStrategy RCRegion::conflictStrategy=RCRegion::RENAME;
00050 
00051 #elif TEKKOTSU_SHM_STYLE==POSIX_SHM
00052 //under POSIX shared memory, the keys are names, so we can have some confidence that a region
00053 //with the same name is ours from a previous run, so we replace it to avoid leaking (although
00054 //it's still possible we're conflicting with another application, but good name choices should
00055 //mitigate this)
00056 RCRegion::ConflictResolutionStrategy RCRegion::conflictStrategy=RCRegion::REPLACE;
00057 
00058 #elif TEKKOTSU_SHM_STYLE==NO_SHM
00059 //with shared memory disabled, a conflict indicates we're reusing the same name... this is probably
00060 //a bug, so we should fail-fast
00061 RCRegion::ConflictResolutionStrategy RCRegion::conflictStrategy=RCRegion::EXIT;
00062 
00063 #endif
00064 
00065 RCRegion * RCRegion::attach(const Identifier& rid) {
00066   MarkScope l(getStaticLock());
00067   attachedRegions_t::iterator it=attachedRegions.find(rid.key);
00068   if(it==attachedRegions.end())
00069     return new RCRegion(rid); // the constructor will add entry to attachedRegions
00070   else {
00071     ASSERTRETVAL((*it).second!=NULL,"ERROR: attached region is NULL!",NULL);
00072     (*it).second->AddReference();
00073     return (*it).second;
00074   }
00075 }
00076 
00077 void RCRegion::AddReference() {
00078   MarkScope l(getStaticLock());
00079   //cout << "AddReference " << id.shmid << ' ' << ProcessID::getID();
00080   references[ProcessID::getID()]++;
00081   references[ProcessID::NumProcesses]++;
00082   //cout << " counts are now:";
00083   //for(unsigned int i=0; i<ProcessID::NumProcesses+1; i++)
00084   //  cout << ' ' << references[i];
00085   //cout << endl;
00086 }
00087 
00088 void RCRegion::RemoveReference() {
00089   //cout << "RemoveReference " << id.key << ' ' << ProcessID::getID();
00090   Thread::Lock * old=NULL;
00091   {
00092     MarkScope l(getStaticLock());
00093     if(references[ProcessID::getID()] == 0) {
00094       cerr << "Warning: RCRegion reference count underflow on " << id.key << " by " << ProcessID::getID() << "!  ";
00095       for(unsigned int i=0; i<ProcessID::NumProcesses+1; i++)
00096         cerr << ' ' << references[i];
00097       cerr << endl;
00098       return;
00099     }
00100     bool wasLastProcRef=(--references[ProcessID::getID()] == 0);
00101     bool wasLastAnyRef=(--references[ProcessID::NumProcesses] == 0);
00102     ASSERT(wasLastProcRef || !wasLastAnyRef,"global reference decremented beyond process reference");
00103 #if TEKKOTSU_SHM_STYLE==NO_SHM
00104     wasLastProcRef=wasLastAnyRef;
00105 #else
00106     if(!multiprocess)
00107       wasLastProcRef=wasLastAnyRef;
00108 #endif
00109     /*if(isFaultShutdown) {
00110       cerr << "Process " << ProcessID::getID() << " dereferenced " << id.key << ".  Counts are now:";
00111       for(unsigned int i=0; i<ProcessID::NumProcesses+1; i++)
00112         cerr << ' ' << references[i];
00113       cerr << endl;
00114     }*/
00115     if(wasLastProcRef) {
00116       //cout << " detach";
00117 #if TEKKOTSU_SHM_STYLE==SYSV_SHM
00118       if(shmdt(base)<0)
00119         perror("Warning: Region detach");
00120       base=NULL;
00121       references=NULL;
00122       if(wasLastAnyRef) {
00123         //cout << " delete" << endl;
00124         if(shmctl(id.shmid,IPC_RMID,NULL)<0)
00125           perror("Warning: Region delete");
00126       }
00127 #elif TEKKOTSU_SHM_STYLE==POSIX_SHM
00128       if(munmap(base,calcRealSize(id.size))<0) {
00129         perror("Warning: Shared memory unmap (munmap)");
00130       }
00131       base=NULL;
00132       references=NULL;
00133       if(wasLastAnyRef) {
00134         //cout << " delete" << endl;
00135         if(!unlinkRegion()) {
00136           int err=errno;
00137           if(isFaultShutdown && (err==EINVAL || err==ENOENT))
00138             //On a fault shutdown, we initially try to unlink everything right away,
00139             // so an error now is just confirmation that it worked
00140             cerr << "Region " << id.key << " appears to have been successfully unlinked" << endl;
00141           else {
00142             cerr << "Warning: Shared memory unlink of region " << id.key << " returned " << strerror(err);
00143             if(err==EINVAL || err==ENOENT)
00144               cerr << "\n         May have already been unlinked by a dying process.";
00145             cerr << endl;
00146           }
00147         } else if(isFaultShutdown)
00148           //That shouldn't have succeeded on a faultShutdown...
00149           cerr << "Region " << id.key << " appears to have been successfully unlinked (nonstandard)" << endl;
00150       }
00151 #elif TEKKOTSU_SHM_STYLE==NO_SHM
00152       delete base;
00153       base=NULL;
00154       references=NULL;
00155 #else
00156 #  error "Unknown TEKKOTSU_SHM_STYLE setting"
00157 #endif
00158       delete this;
00159       if(attachedRegions.size()==0 && !isFaultShutdown) {
00160         //was last attached region, clean up lock for good measure
00161         old=staticLock;
00162         staticLock=NULL;
00163       }
00164     }
00165   }
00166   delete old;
00167   //cout << endl;
00168 }
00169 
00170 void RCRegion::AddSharedReference() {
00171   MarkScope l(getStaticLock());
00172   //cout << "AddSharedReference " << id.shmid << ' ' << ProcessID::getID();
00173   references[ProcessID::NumProcesses]++;
00174   //cout << " counts are now:";
00175   //for(unsigned int i=0; i<ProcessID::NumProcesses+1; i++)
00176   //  cout << ' ' << references[i];
00177   //cout << endl;
00178 }
00179 
00180 void RCRegion::RemoveSharedReference() {
00181   MarkScope l(getStaticLock());
00182   //cout << "RemoveSharedReference " << id.shmid << ' ' << ProcessID::getID();
00183   if(references[ProcessID::NumProcesses]==0) {
00184     cerr << "Warning: RCRegion shared reference count underflow on " << id.key << " by " << ProcessID::getID() << "!  ";
00185     for(unsigned int i=0; i<ProcessID::NumProcesses+1; i++)
00186       cerr << ' ' << references[i];
00187     cerr << endl;
00188     return;
00189   }
00190   references[ProcessID::NumProcesses]--;
00191   ASSERT(references[ProcessID::NumProcesses]>0,"removal of shared reference was last reference -- should have local reference as well");
00192   //cout << " counts are now:";
00193   //for(unsigned int i=0; i<ProcessID::NumProcesses+1; i++)
00194   //  cout << ' ' << references[i];
00195   //cout << endl;
00196 }
00197 
00198 
00199 void RCRegion::aboutToFork(ProcessID::ProcessID_t newID) {
00200   //cout << "RCRegion aboutToFork to " << newID << endl;
00201   Thread::Lock* old;
00202   {
00203     MarkScope l(getStaticLock());
00204     attachedRegions_t::const_iterator it=attachedRegions.begin();
00205     for(; it!=attachedRegions.end(); ++it) {
00206       //cout << "Duplicating attachments for " << (*it).first;
00207       (*it).second->references[newID]=(*it).second->references[ProcessID::getID()];
00208       (*it).second->references[ProcessID::NumProcesses]+=(*it).second->references[newID];
00209       //cout << " counts are now:";
00210       //for(unsigned int i=0; i<ProcessID::NumProcesses+1; i++)
00211       //  cout << ' ' << (*it).second->references[i];
00212       //cout << endl;
00213     }
00214     old=staticLock;
00215     staticLock=NULL;
00216   }
00217   delete old;
00218 }
00219 
00220 void RCRegion::faultShutdown() {
00221   MarkScope l(getStaticLock());
00222   if(isFaultShutdown) {
00223     cerr << "WARNING: RCRegion::faultShutdown() called again... ignoring" << endl;
00224     return;
00225   }
00226   isFaultShutdown=true;
00227   if(attachedRegions.size()==0) {
00228     cerr << "WARNING: RCRegion::faultShutdown() called without any attached regions (may be a good thing?)" << endl;
00229     return;
00230   }
00231 #if TEKKOTSU_SHM_STYLE==POSIX_SHM
00232   //this may not really work, but it's worth a last-ditch attempt
00233   //in case the reference counts are screwed up.
00234   attachedRegions_t::const_iterator it=attachedRegions.begin();
00235   for(; it!=attachedRegions.end(); ++it) {
00236     cerr << "RCRegion::faultShutdown(): Process " << ProcessID::getID() << " unlinking " << (*it).second->id.key << endl;
00237 #ifdef USE_UNBACKED_SHM
00238     shm_unlink(getQualifiedName((*it).second->id.key).c_str());
00239 #else
00240     unlink(getQualifiedName((*it).second->id.key).c_str());
00241 #endif
00242   }
00243 #endif
00244   for(unsigned int i=0; i<100; i++) {
00245     unsigned int attempts=ProcessID::NumProcesses;
00246     unsigned int lastSize=attachedRegions.size();
00247     while(attachedRegions.size()==lastSize && attempts-->0)
00248       (*attachedRegions.begin()).second->RemoveReference();
00249     if(attempts==-1U) {
00250       cout << "Warning: could not dereference " << attachedRegions.begin()->second->id.key << endl;
00251       attachedRegions.erase(attachedRegions.begin());
00252     }
00253     if(attachedRegions.size()==0)
00254       break;
00255   }
00256 }
00257 
00258 RCRegion::attachedRegions_t::const_iterator RCRegion::attachedBegin(bool threadSafe) {
00259   if(threadSafe) {
00260     MarkScope l(getStaticLock());
00261     attachedRegions.begin()->second->AddReference();
00262     return attachedRegions.begin();
00263   } else
00264     return attachedRegions.begin();
00265 }
00266 RCRegion::attachedRegions_t::const_iterator RCRegion::attachedEnd() {
00267   return attachedRegions.end();
00268 }
00269 void RCRegion::attachedAdvance(RCRegion::attachedRegions_t::const_iterator& it, int x/*=1*/) {
00270   MarkScope l(getStaticLock());
00271   if(it!=attachedRegions.end())
00272     it->second->RemoveReference();
00273   std::advance(it,x);
00274   if(it!=attachedRegions.end())
00275     it->second->AddReference();
00276 }
00277 
00278 RCRegion::~RCRegion() {
00279   MarkScope l(getStaticLock());
00280   attachedRegions.erase(id.key);
00281   ASSERT(base==NULL,"destructed with attachment!");
00282   ASSERT(references==NULL,"destructed with local references!");
00283   //cout << "~RCRegion " << id.shmid << ' ' << ProcessID::getID() << endl;
00284 }
00285   
00286 unsigned int RCRegion::calcRealSize(unsigned int size) {
00287   size=((size+align-1)/align)*align; //round up for field alignment
00288   size+=extra; //add room for the reference count
00289   unsigned int pagesize=::getpagesize();
00290   unsigned int pages=(size+pagesize-1)/pagesize;
00291   return pages*pagesize; //round up to the nearest page
00292 }
00293 
00294 
00295 Thread::Lock& RCRegion::getStaticLock() {
00296   if(staticLock==NULL)
00297     staticLock=new Thread::Lock;
00298   return *staticLock;
00299 }
00300 
00301 #if TEKKOTSU_SHM_STYLE==SYSV_SHM
00302 
00303 void RCRegion::init(size_t sz, key_t sug_key, bool create) {
00304   MarkScope l(getStaticLock());
00305   id.size=sz;
00306   sz=calcRealSize(sz);
00307   if(create) {
00308     int flags = 0666 | IPC_CREAT | IPC_EXCL;
00309     if(sug_key==IPC_PRIVATE) {
00310       if((id.shmid=shmget(sug_key, sz, flags)) < 0) {
00311         int err=errno;
00312         if(err != EEXIST) {
00313           cerr << "ERROR: Getting new private region " << key << " of size " << sz ": " << strerror(err) << " (shmget)" << endl;
00314           exit(EXIT_FAILURE);
00315         }
00316       }
00317       id.key=sug_key;
00318     } else {
00319       nextKey=sug_key;
00320       switch(conflictStrategy) {
00321         case RENAME:
00322           while((id.shmid=shmget(id.key=nextKey++, sz, flags)) < 0) {
00323             int err=errno;
00324             if(err != EEXIST) {
00325               cerr << "ERROR: Getting new region " << key << " of size " << sz ": " << strerror(err) << " (shmget)" << endl;
00326               exit(EXIT_FAILURE);
00327             }
00328           }
00329           break;
00330         case REPLACE:
00331           if((id.shmid=shmget(id.key=nextKey, sz, flags)) >= 0)
00332             break;
00333           int err=errno;
00334           if(err != EEXIST) {
00335             cerr << "ERROR: Getting new region " << key << " of size " << sz ": " << strerror(err) << " (shmget)" << endl;
00336             exit(EXIT_FAILURE);
00337           }
00338 #ifdef DEBUG
00339           cerr << "Warning: conflicted key " << key << ", attempting to replace\n"
00340              << "         (may have been leftover from a previous crash)" << endl;
00341 #endif
00342           if(shmctl(id.shmid,IPC_RMID,NULL)<0)
00343             perror("Warning: Region delete from conflict - is another simulator running?");
00344           //note fall-through from REPLACE into EXIT - only try delete once, and then recreate and exit if it fails again
00345         case EXIT: 
00346           if((id.shmid=shmget(id.key=nextKey, sz, flags)) < 0) {
00347             int err=errno;
00348             cerr << "ERROR: Getting new region " << key << " of size " << sz ": " << strerror(err) << " (shmget)" << endl;
00349             exit(EXIT_FAILURE);
00350           }
00351       }
00352     }
00353   } else {
00354     int flags = 0666;
00355     if((id.shmid=shmget(sug_key, sz, flags)) < 0) {
00356       int err=errno;
00357       cerr << "ERROR: Getting existing region " << key << " of size " << sz ": " << strerror(err) << " (shmget)" << endl;
00358       exit(EXIT_FAILURE);
00359     }
00360     id.key=sug_key;
00361   }
00362   //cout << "ATTACHING " << id.shmid << " NOW" << endl;
00363   base=static_cast<char*>(shmat(id.shmid, NULL, SHM_RND));
00364   int err=errno;
00365   //cout << "Base is " << (void*)base << endl;
00366   if (base == reinterpret_cast<char*>(-1)) {
00367     cerr << "ERROR: Attaching region " << key << " of size " << sz << ": " << strerror(err) << " (shmat)" << endl;
00368     if(shmctl(id.shmid,IPC_RMID,NULL)<0)
00369       perror("Region delete");
00370     exit(EXIT_FAILURE);
00371   }
00372   references=reinterpret_cast<unsigned int*>(base+sz-extra);
00373   if(create) {
00374     for(unsigned int i=0; i<ProcessID::NumProcesses+1; i++)
00375       references[i]=0;
00376   }
00377   AddReference();
00378   attachedRegions[id.key]=this;
00379 }
00380 
00381 #elif TEKKOTSU_SHM_STYLE==POSIX_SHM
00382   
00383 std::string RCRegion::getQualifiedName(const std::string& key) {
00384 #ifdef USE_UNBACKED_SHM
00385   string idval="/";
00386 #else
00387   string idval=shmRoot;
00388 #endif
00389   if(useUniqueMemoryRegions) {
00390     char pidstr[10];
00391     snprintf(pidstr,10,"%d-",rootPID);
00392     idval+=pidstr;
00393   }
00394   idval+=key;
00395   return idval;
00396 }
00397 int RCRegion::openRegion(int mode) const {
00398 #ifdef USE_UNBACKED_SHM
00399   return shm_open(getQualifiedName().c_str(),mode,0666);
00400 #else
00401   return open(getQualifiedName().c_str(),mode,0666);
00402 #endif
00403 }
00404 bool RCRegion::unlinkRegion() const {
00405 #ifdef USE_UNBACKED_SHM
00406   return shm_unlink(getQualifiedName().c_str())==0;
00407 #else
00408   return unlink(getQualifiedName().c_str())==0;
00409 #endif
00410 }
00411 void RCRegion::init(size_t sz, const std::string& name, bool create) {
00412   MarkScope l(getStaticLock());
00413   id.size=sz; //size of requested region
00414   sz=calcRealSize(sz); //add some additional space for region lock and reference counts
00415 #ifndef USE_UNBACKED_SHM
00416   struct stat statbuf;
00417   //cout << "Checking " << shmRoot.substr(0,shmRoot.rfind('/')) << endl;
00418   if(stat(shmRoot.substr(0,shmRoot.rfind('/')).c_str(),&statbuf)) {
00419     for(string::size_type c=shmRoot.find('/',1); c!=string::npos; c=shmRoot.find('/',c+1)) {
00420       //cout << "Checking " << shmRoot.substr(0,c) << endl;
00421       if(stat(shmRoot.substr(0,c).c_str(),&statbuf)) {
00422         mkdir(shmRoot.substr(0,c).c_str(),0777);
00423       } else if(!(statbuf.st_mode&S_IFDIR)) {
00424         cerr << "*** ERROR " << shmRoot.substr(0,c) << " exists and is not a directory" << endl;
00425         cerr << "           Cannot create file-backed shared memory regions in " << shmRoot << endl;
00426         exit(EXIT_FAILURE);
00427       }
00428     }
00429     cout << "Created '" << shmRoot.substr(0,shmRoot.rfind('/')) << "' for file-backed shared memory storage" << endl;
00430   } else if(!(statbuf.st_mode&S_IFDIR)) {
00431     cerr << "*** ERROR " << shmRoot.substr(0,shmRoot.rfind('/')) << " exists and is not a directory" << endl;
00432     cerr << "           Cannot create file-backed shared memory regions with prefix " << shmRoot << endl;
00433     exit(EXIT_FAILURE);
00434   }
00435 #endif
00436   int fd=-1;
00437   if(name.size()>=MAX_NAME_LEN)
00438     cerr << "*** WARNING RCRegion named " << name << " will be clipped to " << name.substr(0,MAX_NAME_LEN-1) << endl;
00439   strncpy(id.key,name.c_str(),MAX_NAME_LEN-1);
00440   id.key[MAX_NAME_LEN-1]='\0';
00441   if(create) {
00442     static unsigned int renameSN=0;
00443     switch(conflictStrategy) {
00444       case RENAME: {
00445         char origName[MAX_NAME_LEN];
00446         strncpy(origName,id.key,MAX_NAME_LEN);
00447         if((fd=openRegion(O_RDWR|O_CREAT|O_EXCL))>=0)
00448           break;
00449         do {
00450           int err=errno;
00451           if(err!=EEXIST) {
00452             cerr << "ERROR: Opening new region " << id.key << ": " << strerror(err) << " (shm_open)" << endl;
00453             exit(EXIT_FAILURE);
00454           }
00455           unsigned int p=snprintf(id.key,MAX_NAME_LEN,"%s-%d",origName,++renameSN);
00456           if(p>=MAX_NAME_LEN) {
00457             cerr << "ERROR: conflicted key " << origName << ", attempting to rename, but generated name is too long" << endl;
00458             exit(EXIT_FAILURE);
00459           }
00460           //id.key[MAX_NAME_LEN-1]='\0';
00461 #ifdef DEBUG
00462           cerr << "Warning: conflicted key " << origName << ", attempting to rename as " << id.key << "\n"
00463             << "         (may have been leftover from a previous crash)" << endl;
00464 #endif
00465         } while((fd=openRegion(O_RDWR|O_CREAT|O_EXCL))<0);
00466         break;
00467       }
00468       case REPLACE: {
00469         if((fd=openRegion(O_RDWR|O_CREAT|O_EXCL))>=0)
00470           break;
00471         int err=errno;
00472         if(err!=EEXIST) {
00473           cerr << "ERROR: Opening new region " << id.key << ": " << strerror(err) << " (shm_open)" << endl;
00474           exit(EXIT_FAILURE);
00475         }
00476 #ifdef DEBUG
00477         cerr << "Warning: conflicted key " << id.key << ", attempting to replace\n"
00478              << "         (may have been leftover from a previous crash)" << endl;
00479 #endif
00480         if(!unlinkRegion())
00481           perror("Warning: Shared memory unlink");
00482       }
00483       //note fall-through from REPLACE into EXIT - only try delete once, and then recreate and exit if it fails again
00484       case EXIT: {
00485         if((fd=openRegion(O_RDWR|O_CREAT|O_EXCL))<0) {
00486           int err=errno;
00487           cerr << "ERROR: Opening new region " << id.key << ": " << strerror(err) << " (shm_open)" << endl;
00488           if(err==EEXIST)
00489             cerr << "This error suggests a leaked memory region, perhaps from a bad crash on a previous run.\n"
00490 #ifdef USE_UNBACKED_SHM
00491               << "You may either be able to use shm_unlink to remove the region, or reboot.\n"
00492 #endif
00493               << "Also make sure that no other copies of the simulator are already running." << endl;
00494           exit(EXIT_FAILURE);
00495         }
00496       }
00497     }
00498     if (ftruncate(fd,sz)<0) {
00499       int err=errno;
00500       cerr << "ERROR: Sizing region " << id.key << " to " << sz << ": " << strerror(err) << " (ftruncate)" << endl;
00501       if(close(fd)<0)
00502         perror("Warning: Closing temporary file descriptor from shm_open");
00503       if(!unlinkRegion())
00504         perror("Warning: Shared memory unlink");
00505       exit(EXIT_FAILURE);
00506     }
00507   } else {
00508     if((fd=openRegion(O_RDWR))<0) {
00509       int err=errno;
00510       cerr << "ERROR: Opening existing region " << id.key << ": " << strerror(err) << " (shm_open)" << endl;
00511       exit(EXIT_FAILURE);
00512     }
00513   }
00514   base=static_cast<char*>(mmap(NULL,sz,PROT_READ|PROT_WRITE,MAP_SHARED,fd,(off_t)0)); 
00515   int err=errno;
00516   if (base == MAP_FAILED) { /* MAP_FAILED generally defined as ((void*)-1) */
00517     cerr << "ERROR: Attaching region " << id.key << " of size " << sz << ": " << strerror(err) << " (mmap)" << endl;
00518     if(close(fd)<0)
00519       perror("Warning: Closing temporary file descriptor from shm_open");
00520     if(!unlinkRegion())
00521       perror("Warning: Shared memory unlink");
00522     exit(EXIT_FAILURE);
00523   }
00524   if(close(fd)<0) {
00525     perror("Warning: Closing temporary file descriptor from shm_open");
00526   }
00527   references=reinterpret_cast<unsigned int*>(base+sz-extra);
00528   if(create) {
00529     for(unsigned int i=0; i<ProcessID::NumProcesses+1; i++)
00530       references[i]=0;
00531   }
00532   AddReference();
00533   attachedRegions[id.key]=this;
00534 }
00535 
00536 #elif TEKKOTSU_SHM_STYLE==NO_SHM
00537 
00538 void RCRegion::init(size_t sz, const std::string& name, bool create) {
00539   MarkScope l(getStaticLock());
00540   id.size=sz; //size of requested region
00541   sz=calcRealSize(sz); //add some additional space for region lock and reference counts
00542   if(name.size()>=MAX_NAME_LEN)
00543     cerr << "*** WARNING RCRegion named " << name << " will be clipped to " << name.substr(0,MAX_NAME_LEN-1) << endl;
00544   strncpy(id.key,name.c_str(),MAX_NAME_LEN-1);
00545   id.key[MAX_NAME_LEN-1]='\0';
00546   if(create) {
00547     static unsigned int renameSN=0;
00548     switch(conflictStrategy) {
00549       case RENAME: {
00550         if(attachedRegions.find(id.key)==attachedRegions.end())
00551           break;
00552         char origName[MAX_NAME_LEN];
00553         strncpy(origName,id.key,MAX_NAME_LEN);
00554         do {
00555           int err=errno;
00556           if(err!=EEXIST) {
00557             cerr << "ERROR: Opening new region " << id.key << ": " << strerror(err) << " (shm_open)" << endl;
00558             exit(EXIT_FAILURE);
00559           }
00560           unsigned int p=snprintf(id.key,MAX_NAME_LEN,"%s-%d",origName,++renameSN);
00561           if(p>=MAX_NAME_LEN) {
00562             cerr << "ERROR: conflicted key " << origName << ", attempting to rename, but generated name is too long" << endl;
00563             exit(EXIT_FAILURE);
00564           }
00565           //id.key[MAX_NAME_LEN-1]='\0';
00566 #ifdef DEBUG
00567           cerr << "Warning: conflicted key " << origName << ", attempting to rename as " << id.key << "\n"
00568             << "         (may have been leftover from a previous crash)" << endl;
00569 #endif
00570         } while(attachedRegions.find(id.key)!=attachedRegions.end());
00571         break;
00572       }
00573       case REPLACE: {
00574         if(attachedRegions.find(id.key)==attachedRegions.end())
00575           break;
00576 #ifdef DEBUG
00577         cerr << "Warning: conflicted key " << id.key << ", attempting to replace" << endl;
00578 #endif
00579       }
00580         //note fall-through from REPLACE into EXIT - only try delete once, and then recreate and exit if it fails again
00581       case EXIT: {
00582         if(attachedRegions.find(id.key)!=attachedRegions.end()) {
00583           cerr << "ERROR: Opening new region " << id.key << ": conflicted with existing region." << endl;
00584           exit(EXIT_FAILURE);
00585         }
00586       }
00587     }
00588     base=new char[sz];
00589   } else {
00590     attachedRegions_t::const_iterator it=attachedRegions.find(id.key);
00591     ASSERT(it==attachedRegions.end(),"attachment not found with disabled shared mem (TEKKOTSU_SHM_STYLE==NO_SHM)");
00592     if(it==attachedRegions.end()) {
00593       base=new char[sz];
00594     } else {
00595       base=it->second->base;
00596     }
00597   }
00598   references=reinterpret_cast<unsigned int*>(base+sz-extra);
00599   if(create) {
00600     for(unsigned int i=0; i<ProcessID::NumProcesses+1; i++)
00601       references[i]=0;
00602   }
00603   AddReference();
00604   attachedRegions[id.key]=this;
00605 }
00606 
00607 
00608 #else
00609 #  error "Unknown TEKKOTSU_SHM_STYLE setting"
00610 #endif
00611 
00612 /*
00613  class syserr : public std::exception {
00614 public:
00615 #if TEKKOTSU_SHM_STYLE==SYSV_SHM
00616    syserr(int errnum, const key_t& key, const std::string& msg) throw() : info()
00617 #elif TEKKOTSU_SHM_STYLE==POSIX_SHM
00618    syserr(int errnum, const std::string& key, const std::string& msg) throw() : info()
00619 #endif
00620  {
00621      stringstream tmp;
00622      tmp << "Exception regarding region " << key << ": " << msg << '(' << strerror(errnum) << ')';
00623      info=tmp.c_str();
00624  }
00625    virtual ~syserr() throw() {}
00626    virtual const char * what() const throw() { return info.c_str(); }
00627 protected:
00628       std::string info;
00629  };
00630  */
00631 
00632 /*! @file
00633 * @brief Implements RCRegion, which provides compatability with the OPEN-R type of the same name
00634 * @author ejt (Creator)
00635 */
00636 
00637 #endif

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