ShmFactory.h

Go to the documentation of this file.
00001 // Copyright CERN 2012 - Developed in collaboration with GSI
00002 
00003 #ifndef SHM_FACTORY_H
00004 #define SHM_FACTORY_H
00005 
00006 #include <fesa-core/DataStore/DeviceFactoryImp.h>
00007 #include <fesa-core/DataStore/EquipmentData.h>
00008 #include <fesa-core/Utilities/Semaphore.h>
00009 
00010 #include <cmw-log/Logger.h>
00011 
00012 #include <cstring>
00013 #include <string>
00014 #include <iostream>
00015 #include <cerrno>
00016 #include <sys/mman.h>
00017 #include <fcntl.h>
00018 
00019 namespace fesa
00020 {
00021 
00022 template<typename GlobalDeviceType, typename DomainStoreType, typename DevInstType> class DeviceFactoryImp;
00023 
00028 typedef struct
00029 {
00030     int32_t shmSize;
00031     int32_t globalDeviceSize;
00032     int32_t domainStoreSize;
00033     int32_t devicesSize;
00034     int32_t muxManagersSize;
00035     int32_t equipmentSize;
00036 } ShmHeader_t;
00037 
00045 template<typename GlobalDeviceType, typename DomainStoreType, typename DevInstType>
00046 class ShmFactory : public DeviceFactoryImp<GlobalDeviceType, DomainStoreType, DevInstType>
00047 {
00048   public:
00053     ShmFactory(const std::string& className);
00054 
00060     bool setUpMemory();
00061 
00065     void createSharedMemory();
00066 
00071     bool attachSharedMemory(int32_t fd);
00072 
00076     void removeSharedMemory();
00077 
00082     ShmHeader_t* pShmHeader_;
00083 
00088     int32_t shmSize_;
00089 
00094     std::string shmName_;
00095 
00100     char* pAddrMuxManagersSpace_;
00101 
00106     char* pAddrDeviceInstanceSpace_;
00107 
00112     char* pAddrGlobalDeviceSpace_;
00113 
00117     char* pAddrDomainStoreSpace_;
00118 
00119 
00123     char* pAddrEquipmentDataSpace_;
00124 
00125   private:
00126     static CMW::Log::Logger& logger_; // we're in a template => can't have it file-scoped
00127 
00128 };
00129 
00130 //******************************************************************
00131 template<typename GlobalDeviceType, typename DomainStoreType, typename DevInstType>
00132 CMW::Log::Logger& ShmFactory<GlobalDeviceType, DomainStoreType, DevInstType>::logger_ = CMW::Log::LoggerFactory::getLogger("FESA.FWK.fesa-core.DataStore.ShmFactory"); // we're in a header => can't have it file-scoped
00133 
00134 template<typename GlobalDeviceType, typename DomainStoreType, typename DevInstType>
00135 inline ShmFactory<GlobalDeviceType, DomainStoreType, DevInstType>::ShmFactory(const std::string& className) :
00136     DeviceFactoryImp<GlobalDeviceType, DomainStoreType, DevInstType> (className)
00137 {
00138     shmName_ = className + "EquipmentShm";
00139 }
00140 
00141 template<typename GlobalDeviceType, typename DomainStoreType, typename DevInstType>
00142 inline void ShmFactory<GlobalDeviceType, DomainStoreType, DevInstType>::removeSharedMemory()
00143 {
00144     try
00145     {
00146         if ((munmap(pShmHeader_, sizeof(shmSize_))) != -1)
00147         {
00148             shm_unlink(shmName_.c_str());
00149         }
00150     }
00151     catch (...)
00152     {
00153         throw FesaException(__FILE__, __LINE__, FesaErrorRemovingSharedMemory.c_str(), shmName_.c_str());
00154     }
00155     {
00156         std::ostringstream message;
00157         message << "\nShared Memory " << shmName_ << " destroyed!" << std::endl;
00158         LOG_TRACE_IF(logger_, message.str());
00159     }
00160 }
00161 
00162 template<typename GlobalDeviceType, typename DomainStoreType, typename DevInstType>
00163 inline bool ShmFactory<GlobalDeviceType, DomainStoreType, DevInstType>::setUpMemory()
00164 {
00165     // set up of the memory must be protected as Server and RT
00166     // part in mode split could run in parallel doing each one its own initialization.
00167     // Only one shared semaphore per equipment
00168     Semaphore sem("Shm" + AbstractEquipment::getInstance()->getEquipmentName(), 1);
00169     sem.wait();
00170     int32_t fd;
00171     bool shmHasBeenCreated = false;
00172     try
00173     {
00174         // Check if the shared memory exist
00175         if ((fd = shm_open(shmName_.c_str(), O_RDWR, S_IRWXU)) == -1)
00176         {
00177             // Check errno to see if it is not a question of permission
00178             if (errno == EACCES)
00179             {
00180                 throw FesaException(__FILE__, __LINE__, FesaErrorOpeningSharedMemory.c_str(), shmName_.c_str());
00181             }
00182 
00183             createSharedMemory();
00184             this->mapFields(pAddrMuxManagersSpace_, true);
00185             shmHasBeenCreated = true;
00186             {
00187                 std::ostringstream message;
00188                 message << "Created shared-memory: " << shmName_ << std::endl;
00189                 LOG_TRACE_IF(logger_, message.str());
00190             }
00191         }
00192         else // shm exists
00193         {
00194             if (attachSharedMemory(fd))
00195             {
00196                 EquipmentData* eqData = EquipmentData::getInstance();
00197 
00198                 // If it is the first time the current process check the shared memory
00199                 // we need to check if we need to re-created
00200                 bool checkProcessesAttachedShm = (eqData->isInitialize_ == NULL);
00201                 this->mapFields(pAddrMuxManagersSpace_, false);
00202                 shmHasBeenCreated = false;
00203 
00204                 if (checkProcessesAttachedShm == true) // only checked once per process, no matter the number of DeviceClass it contains
00205                 {
00206                     bool isRTProcessRegistered = (*(eqData->rtProcessID_ )!= 0);
00207                     bool isServerProcessRegistered = (*(eqData->serverProcessID_ )!= 0);
00208                     bool isRegisteredRTProcessUp = false;
00209                     bool isRegisteredServerProcessUp = false;
00210                     if (isRTProcessRegistered)
00211                     {
00212                         // is the rt process up?
00213                         if(kill(*(eqData->rtProcessID_), SIGFESA_CHECK_PROCESS_ALIVE) == 0) // if the signal is  successfully sent means that the process is  up
00214                         {
00215                             isRegisteredRTProcessUp = true;
00216                         }
00217                         else
00218                         {
00219                             if (errno != ESRCH)  // errno = ESRCH means that the process is not running
00220                             {
00221                                 // If the error is different that ESRCH (i.e. no rights to send signal) we should abort
00222                                 throw FesaException(__FILE__, __LINE__, FesaErrorNoPermissionToSendSignals.c_str());
00223                             }
00224                         }
00225                     }
00226                     if (isServerProcessRegistered)
00227                     {
00228                         // is the server process up?
00229                         if(kill(*(eqData->serverProcessID_), SIGFESA_CHECK_PROCESS_ALIVE) == 0) // if the signal is  successfully sent means that the process is  up
00230                         {
00231                             isRegisteredServerProcessUp = true;
00232                         }
00233                         else
00234                         {
00235                             if (errno != ESRCH)  // errno = ESRCH means that the process is not running
00236                             {
00237                                 // If the error is different that ESRCH (i.e. no rights to send signal) we should abort
00238                                 throw FesaException(__FILE__, __LINE__, FesaErrorNoPermissionToSendSignals.c_str());
00239                             }
00240                         }
00241                     }
00242                     if ( (!isRTProcessRegistered && !isServerProcessRegistered ) || // if shm created but no process registered
00243                          ( !isRegisteredServerProcessUp && !isRegisteredRTProcessUp) ) // if none of the registered process runs
00244                     {
00245                         this->unmapFields(); // as fields were mapped, we need to unmap them
00246                         removeSharedMemory();
00247                         createSharedMemory();
00248                         this->mapFields(pAddrMuxManagersSpace_, true);
00249                         shmHasBeenCreated = true;
00250                     }
00251                 }
00252                 {
00253                     std::ostringstream message;
00254                     message <<"Attached Shared Memory: " << shmName_<< std::endl;
00255                     LOG_TRACE_IF(logger_, message.str());
00256                 }
00257             } 
00258             else 
00259             {
00260                 removeSharedMemory();
00261                 createSharedMemory();
00262                 this->mapFields(pAddrMuxManagersSpace_, true);
00263                 shmHasBeenCreated = true;
00264                 {
00265                     std::ostringstream message;
00266                     message << "Remove and Created shared-memory: " << shmName_ << std::endl;
00267                     LOG_TRACE_IF(logger_, message.str());
00268                 }
00269             }
00270         }
00271         if(logger_.isLoggable(CMW::Log::Level::LL_TRACE)) {
00272             std::ostringstream message;
00273             message <<"Space allocated for mux managers :" << this->muxManagersSize_<< std::endl;
00274             message <<"Space allocated for GlobalDevice :" << this->globalDeviceSize_<< std::endl;
00275             message <<"Space allocated for DomainStore :" << this->domainStoreSize_<< std::endl;
00276             message <<"Space allocated for devices :" << this->devicesSize_<< std::endl;
00277             message <<"Total size of the SHM: " << shmSize_<< std::endl;
00278             LOG_TRACE_IF(logger_, message.str());
00279         }
00280     }
00281     catch (FesaException& ex)
00282     {
00283         close(fd);
00284         sem.post();
00285         throw FesaException(ex.getFileName(), ex.getLineNumber(), FesaErrorShmFactorySettingUpMemory.c_str());
00286     }
00287     close(fd);
00288     sem.post();
00289     return (shmHasBeenCreated);
00290 }
00291 
00292 template<typename GlobalDeviceType, typename DomainStoreType, typename DevInstType>
00293 inline void ShmFactory<GlobalDeviceType, DomainStoreType, DevInstType>::createSharedMemory()
00294 
00295 {
00296     int32_t org_mask = umask(0); // set the user mask to 0 in order to create the semaphore with the wanted rights
00297     int32_t fd;
00298     if ((fd = shm_open(shmName_.c_str(), O_CREAT | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO)) == -1)
00299     {
00300         umask(org_mask); // restore the original umask
00301         throw FesaException(__FILE__, __LINE__, FesaErrorCreatingSharedMemory.c_str(), shmName_.c_str());
00302     }
00303     umask(org_mask); // restore the original umask
00304 
00305     this->computeMemorySize();
00306 
00307     // Compute the size: of static members
00308     shmSize_ = 0;
00309     shmSize_ += sizeof(ShmHeader_t);
00310     shmSize_ += this->muxManagersSize_;
00311     shmSize_ += this->globalDeviceSize_;
00312     shmSize_ += this->domainStoreSize_;
00313     shmSize_ += this->devicesSize_;
00314     shmSize_ += this->equimentDataSize_;
00315 
00316     // Resize it to fit the header and the requested space.
00317     if ((ftruncate(fd, shmSize_)) < 0)
00318     {
00319         throw FesaException(__FILE__, __LINE__, FesaErrorResizingSharedMemory.c_str(), shmName_.c_str());
00320     }
00321 
00322     // Map header space to the process
00323     if ((pShmHeader_ = (ShmHeader_t*) mmap(0, shmSize_, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == 0)
00324     {
00325         throw FesaException(__FILE__, __LINE__, FesaErrorMappingSharedMemory.c_str(), shmName_.c_str());
00326     }
00327 
00328     // Reset the memory
00329     std::memset(pShmHeader_, 0, shmSize_);
00330 
00331     // Fill the requested size for later use by the link.
00332     pShmHeader_->shmSize = shmSize_;
00333     pShmHeader_->muxManagersSize = this->muxManagersSize_;
00334     pShmHeader_->globalDeviceSize = this->globalDeviceSize_;
00335     pShmHeader_->domainStoreSize = this->domainStoreSize_;
00336     pShmHeader_->devicesSize = this->devicesSize_;
00337     pShmHeader_->equipmentSize = this->equimentDataSize_;
00338 
00339     // Compute the userSpace address : address of the first device instance
00340     pAddrMuxManagersSpace_ = (char*) ((char*) pShmHeader_ + sizeof(ShmHeader_t));
00341     pAddrGlobalDeviceSpace_ = pAddrMuxManagersSpace_ + this->muxManagersSize_;
00342     pAddrDomainStoreSpace_ = pAddrGlobalDeviceSpace_ + this->globalDeviceSize_;
00343     pAddrDeviceInstanceSpace_ = pAddrDomainStoreSpace_ + this->domainStoreSize_;
00344     pAddrEquipmentDataSpace_ = pAddrDeviceInstanceSpace_ + this->devicesSize_;
00345     close(fd);
00346 }
00347 
00348 template<typename GlobalDeviceType, typename DomainStoreType, typename DevInstType>
00349 inline bool ShmFactory<GlobalDeviceType, DomainStoreType, DevInstType>::attachSharedMemory(int32_t fd)
00350 
00351 {
00352     // Map header space to the process *
00353     if ((pShmHeader_ = (ShmHeader_t *) mmap(0, sizeof(ShmHeader_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0))
00354         == 0)
00355     {
00356         throw FesaException(__FILE__, __LINE__, FesaErrorMappingSharedMemory.c_str(), shmName_.c_str());
00357     }
00358     this->computeMemorySize();
00359 
00360     // Compute the size: of static members
00361     shmSize_ = 0;
00362     shmSize_ += sizeof(ShmHeader_t);
00363     shmSize_ += this->muxManagersSize_;
00364     shmSize_ += this->globalDeviceSize_;
00365     shmSize_ += this->domainStoreSize_;
00366     shmSize_ += this->devicesSize_;
00367     shmSize_ += this->equimentDataSize_;
00368 
00369     if (shmSize_ != pShmHeader_->shmSize || this->muxManagersSize_ != pShmHeader_->muxManagersSize
00370         || this->globalDeviceSize_ != pShmHeader_->globalDeviceSize || this->domainStoreSize_
00371         != pShmHeader_->domainStoreSize || this->devicesSize_ != pShmHeader_->devicesSize || this->equimentDataSize_ != pShmHeader_->equipmentSize)
00372     {
00373         // Unmap the header
00374         if ((munmap(pShmHeader_, sizeof(ShmHeader_t))) == -1)
00375         {
00376             throw FesaException(__FILE__, __LINE__, FesaErrorUnMappingSharedMemory.c_str(), shmName_.c_str());
00377         }
00378         return false;
00379     }
00380 
00381     // Unmap the header
00382     if ((munmap(pShmHeader_, sizeof(ShmHeader_t))) == -1)
00383     {
00384         throw FesaException(__FILE__, __LINE__, FesaErrorUnMappingSharedMemory.c_str(), shmName_.c_str());
00385     }
00386 
00387     // Map shared memory user space to the process
00388     char* pAddr;
00389     if ((pAddr = (char *) mmap(0, shmSize_, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == 0)
00390     {
00391         throw FesaException(__FILE__, __LINE__, FesaErrorMappingSharedMemory.c_str(), shmName_.c_str());
00392     }
00393 
00394     // Set pointer to user space
00395     pAddrMuxManagersSpace_ = pAddr + sizeof(ShmHeader_t);
00396     pAddrGlobalDeviceSpace_ = pAddrMuxManagersSpace_ + this->muxManagersSize_;
00397     pAddrDomainStoreSpace_ = pAddrGlobalDeviceSpace_ + this->globalDeviceSize_;
00398     pAddrDeviceInstanceSpace_ = pAddrDomainStoreSpace_ + this->domainStoreSize_;
00399     pAddrEquipmentDataSpace_ = pAddrDeviceInstanceSpace_ + this->devicesSize_;
00400 
00401     return true;
00402 }
00403 } // fesa
00404 #endif // SHM_FACTORY_H

Generated on 18 Jan 2013 for Fesa by  doxygen 1.6.1