annotate DEPENDENCIES/generic/include/boost/interprocess/detail/portable_intermodule_singleton.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents c530137014c0
children
rev   line source
Chris@16 1 //////////////////////////////////////////////////////////////////////////////
Chris@16 2 //
Chris@16 3 // (C) Copyright Ion Gaztanaga 2009-2012. Distributed under the Boost
Chris@16 4 // Software License, Version 1.0. (See accompanying file
Chris@16 5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Chris@16 6 //
Chris@16 7 // See http://www.boost.org/libs/interprocess for documentation.
Chris@16 8 //
Chris@16 9 //////////////////////////////////////////////////////////////////////////////
Chris@16 10
Chris@16 11 #ifndef BOOST_INTERPROCESS_PORTABLE_INTERMODULE_SINGLETON_HPP
Chris@16 12 #define BOOST_INTERPROCESS_PORTABLE_INTERMODULE_SINGLETON_HPP
Chris@16 13
Chris@101 14 #ifndef BOOST_CONFIG_HPP
Chris@101 15 # include <boost/config.hpp>
Chris@101 16 #endif
Chris@101 17 #
Chris@101 18 #if defined(BOOST_HAS_PRAGMA_ONCE)
Chris@16 19 #pragma once
Chris@16 20 #endif
Chris@16 21
Chris@16 22 #include <boost/interprocess/detail/config_begin.hpp>
Chris@16 23 #include <boost/interprocess/detail/workaround.hpp>
Chris@16 24
Chris@16 25 #include <boost/interprocess/detail/managed_global_memory.hpp>
Chris@16 26 #include <boost/interprocess/detail/intermodule_singleton_common.hpp>
Chris@16 27 #include <boost/interprocess/shared_memory_object.hpp>
Chris@16 28 #include <boost/interprocess/detail/atomic.hpp>
Chris@16 29 #include <boost/interprocess/detail/os_thread_functions.hpp>
Chris@101 30 #include <boost/interprocess/detail/shared_dir_helpers.hpp>
Chris@16 31 #include <boost/interprocess/detail/os_file_functions.hpp>
Chris@16 32 #include <boost/interprocess/detail/file_locking_helpers.hpp>
Chris@16 33 #include <boost/assert.hpp>
Chris@16 34 #include <cstddef>
Chris@16 35 #include <cstdio>
Chris@16 36 #include <cstring>
Chris@16 37 #include <string>
Chris@16 38
Chris@16 39 namespace boost{
Chris@16 40 namespace interprocess{
Chris@16 41 namespace ipcdetail{
Chris@16 42
Chris@16 43 typedef basic_managed_global_memory<shared_memory_object, true> managed_global_memory;
Chris@16 44
Chris@16 45 namespace intermodule_singleton_helpers {
Chris@16 46
Chris@16 47 static void create_tmp_subdir_and_get_pid_based_filepath
Chris@16 48 (const char *subdir_name, const char *file_prefix, OS_process_id_t pid, std::string &s, bool creation_time = false)
Chris@16 49 {
Chris@16 50 //Let's create a lock file for each process gmem that will mark if
Chris@16 51 //the process is alive or not
Chris@101 52 create_shared_dir_and_clean_old(s);
Chris@16 53 s += "/";
Chris@16 54 s += subdir_name;
Chris@16 55 if(!open_or_create_directory(s.c_str())){
Chris@101 56 error_info err = system_error_code();
Chris@101 57 throw interprocess_exception(err);
Chris@16 58 }
Chris@16 59 s += "/";
Chris@16 60 s += file_prefix;
Chris@16 61 if(creation_time){
Chris@16 62 std::string sstamp;
Chris@16 63 get_pid_creation_time_str(sstamp);
Chris@16 64 s += sstamp;
Chris@16 65 }
Chris@16 66 else{
Chris@16 67 pid_str_t pid_str;
Chris@16 68 get_pid_str(pid_str, pid);
Chris@16 69 s += pid_str;
Chris@16 70 }
Chris@16 71 }
Chris@16 72
Chris@16 73 static bool check_if_filename_complies_with_pid
Chris@16 74 (const char *filename, const char *prefix, OS_process_id_t pid, std::string &file_suffix, bool creation_time = false)
Chris@16 75 {
Chris@16 76 //Check if filename complies with lock file name pattern
Chris@16 77 std::string fname(filename);
Chris@16 78 std::string fprefix(prefix);
Chris@16 79 if(fname.size() <= fprefix.size()){
Chris@16 80 return false;
Chris@16 81 }
Chris@16 82 fname.resize(fprefix.size());
Chris@16 83 if(fname != fprefix){
Chris@16 84 return false;
Chris@16 85 }
Chris@16 86
Chris@16 87 //If not our lock file, delete it if we can lock it
Chris@16 88 fname = filename;
Chris@16 89 fname.erase(0, fprefix.size());
Chris@16 90 pid_str_t pid_str;
Chris@16 91 get_pid_str(pid_str, pid);
Chris@16 92 file_suffix = pid_str;
Chris@16 93 if(creation_time){
Chris@16 94 std::size_t p = fname.find('_');
Chris@16 95 if (p == std::string::npos){
Chris@16 96 return false;
Chris@16 97 }
Chris@16 98 std::string save_suffix(fname);
Chris@16 99 fname.erase(p);
Chris@16 100 fname.swap(file_suffix);
Chris@16 101 bool ret = (file_suffix == fname);
Chris@16 102 file_suffix.swap(save_suffix);
Chris@16 103 return ret;
Chris@16 104 }
Chris@16 105 else{
Chris@16 106 fname.swap(file_suffix);
Chris@16 107 return (file_suffix == fname);
Chris@16 108 }
Chris@16 109 }
Chris@16 110
Chris@16 111 template<>
Chris@16 112 struct thread_safe_global_map_dependant<managed_global_memory>
Chris@16 113 {
Chris@16 114 private:
Chris@16 115 static const int GMemMarkToBeRemoved = -1;
Chris@16 116 static const int GMemNotPresent = -2;
Chris@16 117
Chris@16 118 static const char *get_lock_file_subdir_name()
Chris@16 119 { return "gmem"; }
Chris@16 120
Chris@16 121 static const char *get_lock_file_base_name()
Chris@16 122 { return "lck"; }
Chris@16 123
Chris@16 124 static void create_and_get_singleton_lock_file_path(std::string &s)
Chris@16 125 {
Chris@16 126 create_tmp_subdir_and_get_pid_based_filepath
Chris@16 127 (get_lock_file_subdir_name(), get_lock_file_base_name(), get_current_process_id(), s, true);
Chris@16 128 }
Chris@16 129
Chris@16 130 struct gmem_erase_func
Chris@16 131 {
Chris@16 132 gmem_erase_func(const char *shm_name, const char *singleton_lock_file_path, managed_global_memory & shm)
Chris@16 133 :shm_name_(shm_name), singleton_lock_file_path_(singleton_lock_file_path), shm_(shm)
Chris@16 134 {}
Chris@16 135
Chris@16 136 void operator()()
Chris@16 137 {
Chris@16 138 locking_file_serial_id *pserial_id = shm_.find<locking_file_serial_id>("lock_file_fd").first;
Chris@16 139 if(pserial_id){
Chris@16 140 pserial_id->fd = GMemMarkToBeRemoved;
Chris@16 141 }
Chris@16 142 delete_file(singleton_lock_file_path_);
Chris@16 143 shared_memory_object::remove(shm_name_);
Chris@16 144 }
Chris@16 145
Chris@16 146 const char * const shm_name_;
Chris@16 147 const char * const singleton_lock_file_path_;
Chris@16 148 managed_global_memory & shm_;
Chris@16 149 };
Chris@16 150
Chris@16 151 //This function applies shared memory erasure logic based on the passed lock file.
Chris@16 152 static void apply_gmem_erase_logic(const char *filepath, const char *filename)
Chris@16 153 {
Chris@16 154 int fd = GMemMarkToBeRemoved;
Chris@16 155 try{
Chris@16 156 std::string str;
Chris@16 157 //If the filename is current process lock file, then avoid it
Chris@16 158 if(check_if_filename_complies_with_pid
Chris@16 159 (filename, get_lock_file_base_name(), get_current_process_id(), str, true)){
Chris@16 160 return;
Chris@16 161 }
Chris@16 162 //Open and lock the other process' lock file
Chris@16 163 fd = try_open_and_lock_file(filepath);
Chris@16 164 if(fd < 0){
Chris@16 165 return;
Chris@16 166 }
Chris@16 167 //If done, then the process is dead so take global shared memory name
Chris@16 168 //(the name is based on the lock file name) and try to apply erasure logic
Chris@16 169 str.insert(0, get_map_base_name());
Chris@16 170 try{
Chris@16 171 managed_global_memory shm(open_only, str.c_str());
Chris@16 172 gmem_erase_func func(str.c_str(), filepath, shm);
Chris@16 173 shm.try_atomic_func(func);
Chris@16 174 }
Chris@16 175 catch(interprocess_exception &e){
Chris@16 176 //If shared memory is not found erase the lock file
Chris@16 177 if(e.get_error_code() == not_found_error){
Chris@16 178 delete_file(filepath);
Chris@16 179 }
Chris@16 180 }
Chris@16 181 }
Chris@16 182 catch(...){
Chris@16 183
Chris@16 184 }
Chris@16 185 if(fd >= 0){
Chris@16 186 close_lock_file(fd);
Chris@16 187 }
Chris@16 188 }
Chris@16 189
Chris@16 190 public:
Chris@16 191
Chris@16 192 static bool remove_old_gmem()
Chris@16 193 {
Chris@16 194 std::string refcstrRootDirectory;
Chris@101 195 get_shared_dir(refcstrRootDirectory);
Chris@16 196 refcstrRootDirectory += "/";
Chris@16 197 refcstrRootDirectory += get_lock_file_subdir_name();
Chris@16 198 return for_each_file_in_dir(refcstrRootDirectory.c_str(), apply_gmem_erase_logic);
Chris@16 199 }
Chris@16 200
Chris@16 201 struct lock_file_logic
Chris@16 202 {
Chris@16 203 lock_file_logic(managed_global_memory &shm)
Chris@16 204 : mshm(shm)
Chris@16 205 { shm.atomic_func(*this); }
Chris@16 206
Chris@16 207 void operator()(void)
Chris@16 208 {
Chris@16 209 retry_with_new_map = false;
Chris@16 210
Chris@16 211 //First find the file locking descriptor id
Chris@16 212 locking_file_serial_id *pserial_id =
Chris@16 213 mshm.find<locking_file_serial_id>("lock_file_fd").first;
Chris@16 214
Chris@16 215 int fd;
Chris@16 216 //If not found schedule a creation
Chris@16 217 if(!pserial_id){
Chris@16 218 fd = GMemNotPresent;
Chris@16 219 }
Chris@16 220 //Else get it
Chris@16 221 else{
Chris@16 222 fd = pserial_id->fd;
Chris@16 223 }
Chris@16 224 //If we need to create a new one, do it
Chris@16 225 if(fd == GMemNotPresent){
Chris@16 226 std::string lck_str;
Chris@16 227 //Create a unique current pid based lock file path
Chris@16 228 create_and_get_singleton_lock_file_path(lck_str);
Chris@16 229 //Open or create and lock file
Chris@16 230 int fd_lockfile = open_or_create_and_lock_file(lck_str.c_str());
Chris@16 231 //If failed, write a bad file descriptor to notify other modules that
Chris@16 232 //something was wrong and unlink shared memory. Mark the function object
Chris@16 233 //to tell caller to retry with another shared memory
Chris@16 234 if(fd_lockfile < 0){
Chris@16 235 this->register_lock_file(GMemMarkToBeRemoved);
Chris@16 236 std::string s;
Chris@16 237 get_map_name(s);
Chris@16 238 shared_memory_object::remove(s.c_str());
Chris@16 239 retry_with_new_map = true;
Chris@16 240 }
Chris@16 241 //If successful, register the file descriptor
Chris@16 242 else{
Chris@16 243 this->register_lock_file(fd_lockfile);
Chris@16 244 }
Chris@16 245 }
Chris@16 246 //If the fd was invalid (maybe a previous try failed) notify caller that
Chris@16 247 //should retry creation logic, since this shm might have been already
Chris@16 248 //unlinked since the shm was removed
Chris@16 249 else if (fd == GMemMarkToBeRemoved){
Chris@16 250 retry_with_new_map = true;
Chris@16 251 }
Chris@16 252 //If the stored fd is not valid (a open fd, a normal file with the
Chris@16 253 //expected size, or does not have the same file id number,
Chris@16 254 //then it's an old shm from an old process with the same pid.
Chris@16 255 //If that's the case, mark it as invalid
Chris@16 256 else if(!is_valid_fd(fd) ||
Chris@16 257 !is_normal_file(fd) ||
Chris@16 258 0 != get_size(fd) ||
Chris@16 259 !compare_file_serial(fd, *pserial_id)){
Chris@16 260 pserial_id->fd = GMemMarkToBeRemoved;
Chris@16 261 std::string s;
Chris@16 262 get_map_name(s);
Chris@16 263 shared_memory_object::remove(s.c_str());
Chris@16 264 retry_with_new_map = true;
Chris@16 265 }
Chris@16 266 else{
Chris@16 267 //If the lock file is ok, increment reference count of
Chris@16 268 //attached modules to shared memory
Chris@16 269 atomic_inc32(&pserial_id->modules_attached_to_gmem_count);
Chris@16 270 }
Chris@16 271 }
Chris@16 272
Chris@16 273 bool retry() const { return retry_with_new_map; }
Chris@16 274
Chris@16 275 private:
Chris@16 276 locking_file_serial_id * register_lock_file(int fd)
Chris@16 277 {
Chris@16 278 locking_file_serial_id *pinfo = mshm.construct<locking_file_serial_id>("lock_file_fd")();
Chris@16 279 fill_file_serial_id(fd, *pinfo);
Chris@16 280 return pinfo;
Chris@16 281 }
Chris@16 282
Chris@16 283 managed_global_memory &mshm;
Chris@16 284 bool retry_with_new_map;
Chris@16 285 };
Chris@16 286
Chris@16 287 static void construct_map(void *addr)
Chris@16 288 {
Chris@16 289 std::string s;
Chris@16 290 intermodule_singleton_helpers::get_map_name(s);
Chris@16 291 const char *MapName = s.c_str();
Chris@16 292 const std::size_t MapSize = intermodule_singleton_helpers::get_map_size();;
Chris@16 293 ::new (addr)managed_global_memory(open_or_create, MapName, MapSize);
Chris@16 294 }
Chris@16 295
Chris@16 296 struct unlink_map_logic
Chris@16 297 {
Chris@16 298 unlink_map_logic(managed_global_memory &mshm)
Chris@16 299 : mshm_(mshm)
Chris@16 300 { mshm.atomic_func(*this); }
Chris@16 301
Chris@16 302 void operator()()
Chris@16 303 {
Chris@16 304 locking_file_serial_id *pserial_id =
Chris@16 305 mshm_.find<locking_file_serial_id>
Chris@16 306 ("lock_file_fd").first;
Chris@16 307 BOOST_ASSERT(0 != pserial_id);
Chris@16 308 if(1 == atomic_dec32(&pserial_id->modules_attached_to_gmem_count)){
Chris@16 309 int fd = pserial_id->fd;
Chris@16 310 if(fd > 0){
Chris@16 311 pserial_id->fd = GMemMarkToBeRemoved;
Chris@16 312 std::string s;
Chris@16 313 create_and_get_singleton_lock_file_path(s);
Chris@16 314 delete_file(s.c_str());
Chris@16 315 close_lock_file(fd);
Chris@16 316 intermodule_singleton_helpers::get_map_name(s);
Chris@16 317 shared_memory_object::remove(s.c_str());
Chris@16 318 }
Chris@16 319 }
Chris@16 320 }
Chris@16 321
Chris@16 322 private:
Chris@16 323 managed_global_memory &mshm_;
Chris@16 324 };
Chris@16 325
Chris@16 326 static ref_count_ptr *find(managed_global_memory &map, const char *name)
Chris@16 327 {
Chris@16 328 return map.find<ref_count_ptr>(name).first;
Chris@16 329 }
Chris@16 330
Chris@16 331 static ref_count_ptr *insert(managed_global_memory &map, const char *name, const ref_count_ptr &ref)
Chris@16 332 {
Chris@16 333 return map.construct<ref_count_ptr>(name)(ref);
Chris@16 334 }
Chris@16 335
Chris@16 336 static bool erase(managed_global_memory &map, const char *name)
Chris@16 337 {
Chris@16 338 return map.destroy<ref_count_ptr>(name);
Chris@16 339 }
Chris@16 340
Chris@16 341 template<class F>
Chris@16 342 static void atomic_func(managed_global_memory &map, F &f)
Chris@16 343 {
Chris@16 344 map.atomic_func(f);
Chris@16 345 }
Chris@16 346 };
Chris@16 347
Chris@16 348 } //namespace intermodule_singleton_helpers {
Chris@16 349
Chris@101 350 template<typename C, bool LazyInit = true, bool Phoenix = false>
Chris@16 351 class portable_intermodule_singleton
Chris@16 352 : public intermodule_singleton_impl<C, LazyInit, Phoenix, managed_global_memory>
Chris@16 353 {};
Chris@16 354
Chris@16 355 } //namespace ipcdetail{
Chris@16 356 } //namespace interprocess{
Chris@16 357 } //namespace boost{
Chris@16 358
Chris@16 359 #include <boost/interprocess/detail/config_end.hpp>
Chris@16 360
Chris@16 361 #endif //#ifndef BOOST_INTERPROCESS_PORTABLE_INTERMODULE_SINGLETON_HPP