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

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