Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/boost/interprocess/detail/portable_intermodule_singleton.hpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

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