Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:38:26

0001 //////////////////////////////////////////////////////////////////////////////
0002 //
0003 // (C) Copyright Ion Gaztanaga 2009-2012. Distributed under the Boost
0004 // Software License, Version 1.0. (See accompanying file
0005 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // See http://www.boost.org/libs/interprocess for documentation.
0008 //
0009 //////////////////////////////////////////////////////////////////////////////
0010 
0011 #ifndef BOOST_INTERPROCESS_PORTABLE_INTERMODULE_SINGLETON_HPP
0012 #define BOOST_INTERPROCESS_PORTABLE_INTERMODULE_SINGLETON_HPP
0013 
0014 #ifndef BOOST_CONFIG_HPP
0015 #  include <boost/config.hpp>
0016 #endif
0017 #
0018 #if defined(BOOST_HAS_PRAGMA_ONCE)
0019 #pragma once
0020 #endif
0021 
0022 #include <boost/interprocess/detail/config_begin.hpp>
0023 #include <boost/interprocess/detail/workaround.hpp>
0024 
0025 #include <boost/interprocess/detail/managed_global_memory.hpp>
0026 #include <boost/interprocess/detail/intermodule_singleton_common.hpp>
0027 #include <boost/interprocess/shared_memory_object.hpp>
0028 #include <boost/interprocess/detail/atomic.hpp>
0029 #include <boost/interprocess/detail/os_thread_functions.hpp>
0030 #include <boost/interprocess/detail/shared_dir_helpers.hpp>
0031 #include <boost/interprocess/detail/os_file_functions.hpp>
0032 #include <boost/interprocess/detail/file_locking_helpers.hpp>
0033 #include <boost/assert.hpp>
0034 #include <cstddef>
0035 #include <cstdio>
0036 #include <cstring>
0037 #include <string>
0038 
0039 namespace boost{
0040 namespace interprocess{
0041 namespace ipcdetail{
0042 
0043 typedef basic_managed_global_memory<shared_memory_object, true>    managed_global_memory;
0044 
0045 namespace intermodule_singleton_helpers {
0046 
0047 static void create_tmp_subdir_and_get_pid_based_filepath
0048    (const char *subdir_name, const char *file_prefix, OS_process_id_t pid, std::string &s, bool creation_time = false)
0049 {
0050    //Let's create a lock file for each process gmem that will mark if
0051    //the process is alive or not
0052    create_shared_dir_and_clean_old(s);
0053    s += "/";
0054    s += subdir_name;
0055    if(!open_or_create_shared_directory(s.c_str())){
0056       error_info err = system_error_code();
0057       throw interprocess_exception(err);
0058    }
0059    s += "/";
0060    s += file_prefix;
0061    if(creation_time){
0062       std::string sstamp;
0063       get_pid_creation_time_str(sstamp);
0064       s += sstamp;
0065    }
0066    else{
0067       pid_str_t pid_str;
0068       get_pid_str(pid_str, pid);
0069       s += pid_str;
0070    }
0071 }
0072 
0073 static bool check_if_filename_complies_with_pid
0074    (const char *filename, const char *prefix, OS_process_id_t pid, std::string &file_suffix, bool creation_time = false)
0075 {
0076    //Check if filename complies with lock file name pattern
0077    std::string fname(filename);
0078    std::string fprefix(prefix);
0079    if(fname.size() <= fprefix.size()){
0080       return false;
0081    }
0082    fname.resize(fprefix.size());
0083    if(fname != fprefix){
0084       return false;
0085    }
0086 
0087    //If not our lock file, delete it if we can lock it
0088    fname = filename;
0089    fname.erase(0, fprefix.size());
0090    pid_str_t pid_str;
0091    get_pid_str(pid_str, pid);
0092    file_suffix = pid_str;
0093    if(creation_time){
0094       std::size_t p = fname.find('_');
0095       if (p == std::string::npos){
0096          return false;
0097       }
0098       std::string save_suffix(fname);
0099       fname.erase(p);
0100       fname.swap(file_suffix);
0101       bool ret = (file_suffix == fname);
0102       file_suffix.swap(save_suffix);
0103       return ret;
0104    }
0105    else{
0106       fname.swap(file_suffix);
0107       return (file_suffix == fname);
0108    }
0109 }
0110 
0111 template<>
0112 struct thread_safe_global_map_dependant<managed_global_memory>
0113 {
0114    private:
0115    static const int GMemMarkToBeRemoved = -1;
0116    static const int GMemNotPresent      = -2;
0117 
0118    static const char *get_lock_file_subdir_name()
0119    {  return "gmem";  }
0120 
0121    static const char *get_lock_file_base_name()
0122    {  return "lck";  }
0123 
0124    static void create_and_get_singleton_lock_file_path(std::string &s)
0125    {
0126       create_tmp_subdir_and_get_pid_based_filepath
0127          (get_lock_file_subdir_name(), get_lock_file_base_name(), get_current_process_id(), s, true);
0128    }
0129 
0130    struct gmem_erase_func
0131    {
0132       gmem_erase_func(const char *shm_name, const char *singleton_lock_file_path, managed_global_memory & shm)
0133          :shm_name_(shm_name), singleton_lock_file_path_(singleton_lock_file_path), shm_(shm)
0134       {}
0135 
0136       void operator()()
0137       {
0138          locking_file_serial_id *pserial_id = shm_.find<locking_file_serial_id>("lock_file_fd").first;
0139          if(pserial_id){
0140             pserial_id->fd = GMemMarkToBeRemoved;
0141          }
0142          delete_file(singleton_lock_file_path_);
0143          shared_memory_object::remove(shm_name_);
0144       }
0145 
0146       const char * const shm_name_;
0147       const char * const singleton_lock_file_path_;
0148       managed_global_memory & shm_;
0149    };
0150 
0151    //This function applies shared memory erasure logic based on the passed lock file.
0152    static void apply_gmem_erase_logic(const char *filepath, const char *filename)
0153    {
0154       int fd = GMemMarkToBeRemoved;
0155       BOOST_TRY{
0156          std::string str;
0157          //If the filename is current process lock file, then avoid it
0158          if(check_if_filename_complies_with_pid
0159             (filename, get_lock_file_base_name(), get_current_process_id(), str, true)){
0160             return;
0161          }
0162          //Open and lock the other process' lock file
0163          fd = try_open_and_lock_file(filepath);
0164          if(fd < 0){
0165             return;
0166          }
0167          //If done, then the process is dead so take global shared memory name
0168          //(the name is based on the lock file name) and try to apply erasure logic
0169          str.insert(0, get_map_base_name());
0170          BOOST_TRY{
0171             managed_global_memory shm(open_only, str.c_str());
0172             gmem_erase_func func(str.c_str(), filepath, shm);
0173             shm.try_atomic_func(func);
0174          }
0175          BOOST_CATCH(interprocess_exception &e){
0176             //If shared memory is not found erase the lock file
0177             if(e.get_error_code() == not_found_error){
0178                delete_file(filepath);
0179             }
0180          } BOOST_CATCH_END
0181       }
0182       BOOST_CATCH(...){
0183 
0184       } BOOST_CATCH_END
0185       if(fd >= 0){
0186          close_lock_file(fd);
0187       }
0188    }
0189 
0190    public:
0191 
0192    static bool remove_old_gmem()
0193    {
0194       std::string refcstrRootDirectory;
0195       get_shared_dir(refcstrRootDirectory);
0196       refcstrRootDirectory += "/";
0197       refcstrRootDirectory += get_lock_file_subdir_name();
0198       return for_each_file_in_dir(refcstrRootDirectory.c_str(), apply_gmem_erase_logic);
0199    }
0200 
0201    struct lock_file_logic
0202    {
0203       lock_file_logic(managed_global_memory &shm)
0204          : mshm(shm)
0205       {  shm.atomic_func(*this); }
0206 
0207       void operator()(void)
0208       {
0209          retry_with_new_map = false;
0210 
0211          //First find the file locking descriptor id
0212          locking_file_serial_id *pserial_id =
0213             mshm.find<locking_file_serial_id>("lock_file_fd").first;
0214 
0215          int fd;
0216          //If not found schedule a creation
0217          if(!pserial_id){
0218             fd = GMemNotPresent;
0219          }
0220          //Else get it
0221          else{
0222             fd = pserial_id->fd;
0223          }
0224          //If we need to create a new one, do it
0225          if(fd == GMemNotPresent){
0226             std::string lck_str;
0227             //Create a unique current pid based lock file path
0228             create_and_get_singleton_lock_file_path(lck_str);
0229             //Open or create and lock file
0230             int fd_lockfile = open_or_create_and_lock_file(lck_str.c_str());
0231             //If failed, write a bad file descriptor to notify other modules that
0232             //something was wrong and unlink shared memory. Mark the function object
0233             //to tell caller to retry with another shared memory
0234             if(fd_lockfile < 0){
0235                this->register_lock_file(GMemMarkToBeRemoved);
0236                std::string s;
0237                get_map_name(s);
0238                shared_memory_object::remove(s.c_str());
0239                retry_with_new_map = true;
0240             }
0241             //If successful, register the file descriptor
0242             else{
0243                this->register_lock_file(fd_lockfile);
0244             }
0245          }
0246          //If the fd was invalid (maybe a previous try failed) notify caller that
0247          //should retry creation logic, since this shm might have been already
0248          //unlinked since the shm was removed
0249          else if (fd == GMemMarkToBeRemoved){
0250             retry_with_new_map = true;
0251          }
0252          //If the stored fd is not valid (a open fd, a normal file with the
0253          //expected size, or does not have the same file id number,
0254          //then it's an old shm from an old process with the same pid.
0255          //If that's the case, mark it as invalid
0256          else if(!is_valid_fd(fd) ||
0257                !is_normal_file(fd) ||
0258                0 != get_size(fd) ||
0259                !compare_file_serial(fd, *pserial_id)){
0260             pserial_id->fd = GMemMarkToBeRemoved;
0261             std::string s;
0262             get_map_name(s);
0263             shared_memory_object::remove(s.c_str());
0264             retry_with_new_map = true;
0265          }
0266          else{
0267             //If the lock file is ok, increment reference count of
0268             //attached modules to shared memory
0269             atomic_inc32(&pserial_id->modules_attached_to_gmem_count);
0270          }
0271       }
0272 
0273       bool retry() const { return retry_with_new_map; }
0274 
0275       private:
0276       locking_file_serial_id * register_lock_file(int fd)
0277       {
0278          locking_file_serial_id *pinfo = mshm.construct<locking_file_serial_id>("lock_file_fd")();
0279          fill_file_serial_id(fd, *pinfo);
0280          return pinfo;
0281       }
0282 
0283       managed_global_memory &mshm;
0284       bool retry_with_new_map;
0285    };
0286 
0287    static void construct_map(void *addr)
0288    {
0289       std::string s;
0290       intermodule_singleton_helpers::get_map_name(s);
0291       const char *MapName = s.c_str();
0292       const std::size_t MapSize = intermodule_singleton_helpers::get_map_size();;
0293       ::new (addr)managed_global_memory(open_or_create, MapName, MapSize);
0294    }
0295 
0296    struct unlink_map_logic
0297    {
0298       unlink_map_logic(managed_global_memory &mshm)
0299          : mshm_(mshm)
0300       {  mshm.atomic_func(*this);  }
0301 
0302       void operator()()
0303       {
0304          locking_file_serial_id *pserial_id =
0305             mshm_.find<locking_file_serial_id>
0306                ("lock_file_fd").first;
0307          BOOST_ASSERT(0 != pserial_id);
0308          if(1 == atomic_dec32(&pserial_id->modules_attached_to_gmem_count)){
0309             int fd = pserial_id->fd;
0310             if(fd > 0){
0311                pserial_id->fd = GMemMarkToBeRemoved;
0312                std::string s;
0313                create_and_get_singleton_lock_file_path(s);
0314                delete_file(s.c_str());
0315                close_lock_file(fd);
0316                intermodule_singleton_helpers::get_map_name(s);
0317                shared_memory_object::remove(s.c_str());
0318             }
0319          }
0320       }
0321 
0322       private:
0323       managed_global_memory &mshm_;
0324    };
0325 
0326    static ref_count_ptr *find(managed_global_memory &map, const char *name)
0327    {
0328       return map.find<ref_count_ptr>(name).first;
0329    }
0330 
0331    static ref_count_ptr *insert(managed_global_memory &map, const char *name, const ref_count_ptr &ref)
0332    {
0333       return map.construct<ref_count_ptr>(name)(ref);
0334    }
0335 
0336    static bool erase(managed_global_memory &map, const char *name)
0337    {
0338       return map.destroy<ref_count_ptr>(name);
0339    }
0340 
0341    template<class F>
0342    static void atomic_func(managed_global_memory &map, F &f)
0343    {
0344       map.atomic_func(f);
0345    }
0346 };
0347 
0348 }  //namespace intermodule_singleton_helpers {
0349 
0350 template<typename C, bool LazyInit = true, bool Phoenix = false>
0351 class portable_intermodule_singleton
0352    : public intermodule_singleton_impl<C, LazyInit, Phoenix, managed_global_memory>
0353 {};
0354 
0355 }  //namespace ipcdetail{
0356 }  //namespace interprocess{
0357 }  //namespace boost{
0358 
0359 #include <boost/interprocess/detail/config_end.hpp>
0360 
0361 #endif   //#ifndef BOOST_INTERPROCESS_PORTABLE_INTERMODULE_SINGLETON_HPP