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