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