File indexing completed on 2026-09-17 08:51:58
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_INTERPROCESS_ROBUST_EMULATION_HPP
0012 #define BOOST_INTERPROCESS_ROBUST_EMULATION_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 #include <boost/interprocess/sync/interprocess_mutex.hpp>
0026 #include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
0027 #include <boost/interprocess/detail/atomic.hpp>
0028 #include <boost/interprocess/detail/os_file_functions.hpp>
0029 #include <boost/interprocess/detail/shared_dir_helpers.hpp>
0030 #include <boost/interprocess/detail/intermodule_singleton.hpp>
0031 #include <boost/interprocess/detail/portable_intermodule_singleton.hpp>
0032 #include <boost/interprocess/exceptions.hpp>
0033 #include <boost/interprocess/sync/spin/wait.hpp>
0034 #include <boost/interprocess/sync/detail/common_algorithms.hpp>
0035 #include <string>
0036
0037 namespace boost{
0038 namespace interprocess{
0039 namespace ipcdetail{
0040
0041 namespace robust_emulation_helpers {
0042
0043 template<class T>
0044 class mutex_traits
0045 {
0046 public:
0047 static void take_ownership(T &t)
0048 { t.take_ownership(); }
0049 };
0050
0051 inline void remove_if_can_lock_file(const char *file_path)
0052 {
0053 file_handle_t fhnd = open_existing_file(file_path, read_write);
0054
0055 if(fhnd != invalid_file()){
0056 bool acquired;
0057 if(try_acquire_file_lock(fhnd, acquired) && acquired){
0058 delete_file(file_path);
0059 }
0060 close_file(fhnd);
0061 }
0062 }
0063
0064 inline const char *robust_lock_subdir_path()
0065 { return "robust"; }
0066
0067 inline const char *robust_lock_prefix()
0068 { return "lck"; }
0069
0070 inline void robust_lock_path(std::string &s)
0071 {
0072 get_shared_dir(s);
0073 s += "/";
0074 s += robust_lock_subdir_path();
0075 }
0076
0077 inline void create_and_get_robust_lock_file_path(std::string &s, OS_process_id_t pid)
0078 {
0079 intermodule_singleton_helpers::create_tmp_subdir_and_get_pid_based_filepath
0080 (robust_lock_subdir_path(), robust_lock_prefix(), pid, s);
0081 }
0082
0083
0084
0085
0086
0087
0088
0089 class robust_mutex_lock_file
0090 {
0091 file_handle_t fd;
0092 std::string fname;
0093 public:
0094 robust_mutex_lock_file()
0095 {
0096 permissions p;
0097 p.set_unrestricted();
0098
0099 remove_old_robust_lock_files();
0100
0101 create_and_get_robust_lock_file_path(fname, get_current_process_id());
0102
0103
0104 fd = create_or_open_file(fname.c_str(), read_write, p);
0105
0106 if(fd == invalid_file()){
0107 throw interprocess_exception(other_error, "Robust emulation robust_mutex_lock_file constructor failed: could not open or create file");
0108 }
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118 while(1){
0119 bool acquired;
0120 if(!try_acquire_file_lock(fd, acquired) || !acquired ){
0121 throw interprocess_exception(other_error, "Robust emulation robust_mutex_lock_file constructor failed: try_acquire_file_lock");
0122 }
0123
0124
0125
0126 file_handle_t fd2 = create_new_file(fname.c_str(), read_write, p);
0127 if(fd2 != invalid_file()){
0128 close_file(fd);
0129 fd = fd2;
0130 continue;
0131 }
0132
0133 else if(error_info(system_error_code()).get_error_code() == already_exists_error){
0134
0135 break;
0136 }
0137
0138 else{
0139 close_file(fd);
0140 throw interprocess_exception(other_error, "Robust emulation robust_mutex_lock_file constructor failed: create_file filed with unexpected error");
0141 }
0142 }
0143 }
0144
0145 ~robust_mutex_lock_file()
0146 {
0147
0148
0149
0150 close_file(fd);
0151
0152
0153 delete_file(fname.c_str());
0154 }
0155
0156 private:
0157
0158 class other_process_lock_remover
0159 {
0160 public:
0161 void operator()(const char *filepath, const char *filename)
0162 {
0163 std::string pid_str;
0164
0165 if(!intermodule_singleton_helpers::check_if_filename_complies_with_pid
0166 (filename, robust_lock_prefix(), get_current_process_id(), pid_str)){
0167 remove_if_can_lock_file(filepath);
0168 }
0169 }
0170 };
0171
0172 bool remove_old_robust_lock_files()
0173 {
0174 std::string refcstrRootDirectory;
0175 robust_lock_path(refcstrRootDirectory);
0176 return for_each_file_in_dir(refcstrRootDirectory.c_str(), other_process_lock_remover());
0177 }
0178 };
0179
0180 }
0181
0182
0183
0184
0185 template<class Mutex>
0186 class robust_spin_mutex
0187 {
0188 public:
0189 static const boost::uint32_t correct_state = 0;
0190 static const boost::uint32_t fixing_state = 1;
0191 static const boost::uint32_t broken_state = 2;
0192
0193 typedef robust_emulation_helpers::mutex_traits<Mutex> mutex_traits_t;
0194
0195 robust_spin_mutex();
0196 void lock();
0197 bool try_lock();
0198 template<class TimePoint>
0199 bool timed_lock(const TimePoint &abs_time);
0200 void unlock();
0201 void consistent();
0202 bool previous_owner_dead();
0203
0204 private:
0205 static const unsigned int spin_threshold = 100u;
0206 bool lock_own_unique_file();
0207 bool robust_check();
0208 bool check_if_owner_dead_and_take_ownership_atomically();
0209 bool is_owner_dead(boost::uint32_t own);
0210 void owner_to_filename(boost::uint32_t own, std::string &s);
0211
0212 Mutex mtx;
0213
0214 volatile boost::uint32_t owner;
0215
0216 volatile boost::uint32_t state;
0217 };
0218
0219 template<class Mutex>
0220 inline robust_spin_mutex<Mutex>::robust_spin_mutex()
0221 : mtx(), owner((boost::uint32_t)get_invalid_process_id()), state(correct_state)
0222 {}
0223
0224 template<class Mutex>
0225 inline void robust_spin_mutex<Mutex>::lock()
0226 { try_based_lock(*this); }
0227
0228 template<class Mutex>
0229 inline bool robust_spin_mutex<Mutex>::try_lock()
0230 {
0231
0232 if(atomic_read32(&this->state) == broken_state){
0233 throw interprocess_exception(lock_error, "Broken id");
0234 }
0235
0236 if(!this->lock_own_unique_file()){
0237 throw interprocess_exception(lock_error, "Broken id");
0238 }
0239
0240 if (mtx.try_lock()){
0241 atomic_write32(&this->owner, static_cast<boost::uint32_t>(get_current_process_id()));
0242 return true;
0243 }
0244 else{
0245 if(!this->robust_check()){
0246 return false;
0247 }
0248 else{
0249 return true;
0250 }
0251 }
0252 }
0253
0254 template<class Mutex>
0255 template<class TimePoint>
0256 inline bool robust_spin_mutex<Mutex>::timed_lock
0257 (const TimePoint &abs_time)
0258 { return try_based_timed_lock(*this, abs_time); }
0259
0260 template<class Mutex>
0261 inline void robust_spin_mutex<Mutex>::owner_to_filename(boost::uint32_t own, std::string &s)
0262 {
0263 robust_emulation_helpers::create_and_get_robust_lock_file_path(s, (OS_process_id_t)own);
0264 }
0265
0266 template<class Mutex>
0267 inline bool robust_spin_mutex<Mutex>::robust_check()
0268 {
0269
0270
0271
0272 if(!this->check_if_owner_dead_and_take_ownership_atomically()){
0273 return false;
0274 }
0275 atomic_write32(&this->state, fixing_state);
0276 return true;
0277 }
0278
0279 template<class Mutex>
0280 inline bool robust_spin_mutex<Mutex>::check_if_owner_dead_and_take_ownership_atomically()
0281 {
0282 boost::uint32_t cur_owner = static_cast<boost::uint32_t>(get_current_process_id());
0283 boost::uint32_t old_owner = atomic_read32(&this->owner), old_owner2;
0284
0285
0286 do{
0287
0288 if(!this->is_owner_dead(old_owner)){
0289 return false;
0290 }
0291
0292 old_owner2 = old_owner;
0293 old_owner = atomic_cas32(&this->owner, cur_owner, old_owner);
0294 }while(old_owner2 != old_owner);
0295
0296 mutex_traits_t::take_ownership(mtx);
0297 return true;
0298 }
0299
0300 template<class Mutex>
0301 inline bool robust_spin_mutex<Mutex>::is_owner_dead(boost::uint32_t own)
0302 {
0303
0304 if(own == static_cast<boost::uint32_t>(get_invalid_process_id())){
0305 return true;
0306 }
0307
0308
0309 std::string file;
0310 this->owner_to_filename(own, file);
0311
0312
0313 file_handle_t fhnd = open_existing_file(file.c_str(), read_write);
0314
0315 if(fhnd != invalid_file()){
0316
0317 bool acquired;
0318 if(try_acquire_file_lock(fhnd, acquired) && acquired){
0319
0320 delete_file(file.c_str());
0321 close_file(fhnd);
0322 return true;
0323 }
0324
0325 close_file(fhnd);
0326 }
0327 else{
0328
0329
0330
0331 if(error_info(system_error_code()).get_error_code() == not_found_error){
0332 return true;
0333 }
0334 }
0335 return false;
0336 }
0337
0338 template<class Mutex>
0339 inline void robust_spin_mutex<Mutex>::consistent()
0340 {
0341
0342
0343 if(atomic_read32(&this->state) != fixing_state &&
0344 atomic_read32(&this->owner) != (boost::uint32_t)get_current_process_id()){
0345 throw interprocess_exception(lock_error, "Broken id");
0346 }
0347
0348 atomic_write32(&this->state, correct_state);
0349 }
0350
0351 template<class Mutex>
0352 inline bool robust_spin_mutex<Mutex>::previous_owner_dead()
0353 {
0354
0355 return atomic_read32(&this->state) == fixing_state;
0356 }
0357
0358 template<class Mutex>
0359 inline void robust_spin_mutex<Mutex>::unlock()
0360 {
0361
0362
0363
0364 if(atomic_read32(&this->state) == fixing_state){
0365 atomic_write32(&this->state, broken_state);
0366 }
0367
0368 atomic_write32(&this->owner, static_cast<boost::uint32_t>(get_invalid_process_id()));
0369 mtx.unlock();
0370 }
0371
0372 template<class Mutex>
0373 inline bool robust_spin_mutex<Mutex>::lock_own_unique_file()
0374 {
0375
0376 robust_emulation_helpers::robust_mutex_lock_file* dummy =
0377 &ipcdetail::intermodule_singleton
0378 <robust_emulation_helpers::robust_mutex_lock_file>::get();
0379 return dummy != 0;
0380 }
0381
0382 }
0383 }
0384 }
0385
0386 #include <boost/interprocess/detail/config_end.hpp>
0387
0388 #endif