File indexing completed on 2025-01-18 09:38:26
0001
0002
0003
0004
0005
0006
0007
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
0051
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
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
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
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
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
0163 fd = try_open_and_lock_file(filepath);
0164 if(fd < 0){
0165 return;
0166 }
0167
0168
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
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
0212 locking_file_serial_id *pserial_id =
0213 mshm.find<locking_file_serial_id>("lock_file_fd").first;
0214
0215 int fd;
0216
0217 if(!pserial_id){
0218 fd = GMemNotPresent;
0219 }
0220
0221 else{
0222 fd = pserial_id->fd;
0223 }
0224
0225 if(fd == GMemNotPresent){
0226 std::string lck_str;
0227
0228 create_and_get_singleton_lock_file_path(lck_str);
0229
0230 int fd_lockfile = open_or_create_and_lock_file(lck_str.c_str());
0231
0232
0233
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
0242 else{
0243 this->register_lock_file(fd_lockfile);
0244 }
0245 }
0246
0247
0248
0249 else if (fd == GMemMarkToBeRemoved){
0250 retry_with_new_map = true;
0251 }
0252
0253
0254
0255
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
0268
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 }
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 }
0356 }
0357 }
0358
0359 #include <boost/interprocess/detail/config_end.hpp>
0360
0361 #endif