File indexing completed on 2025-07-09 08:13:44
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_INTERPROCESS_DETAIL_SYNC_UTILS_HPP
0012 #define BOOST_INTERPROCESS_DETAIL_SYNC_UTILS_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/detail/win32_api.hpp>
0025 #include <boost/interprocess/sync/spin/mutex.hpp>
0026 #include <boost/interprocess/exceptions.hpp>
0027 #include <boost/interprocess/sync/scoped_lock.hpp>
0028 #include <boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp>
0029 #include <boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp>
0030
0031
0032 #include <boost/interprocess/detail/config_external_begin.hpp>
0033 #include <boost/container/map.hpp>
0034 #include <boost/interprocess/detail/config_external_end.hpp>
0035 #include <boost/container/flat_map.hpp>
0036
0037 #include <cstddef>
0038
0039 namespace boost {
0040 namespace interprocess {
0041 namespace ipcdetail {
0042
0043 inline bool bytes_to_str(const void *mem, const std::size_t mem_length, char *out_str, std::size_t &out_length)
0044 {
0045 const std::size_t need_mem = mem_length*2+1;
0046 if(out_length < need_mem){
0047 out_length = need_mem;
0048 return false;
0049 }
0050
0051 const char Characters [] =
0052 { '0', '1', '2', '3', '4', '5', '6', '7'
0053 , '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
0054
0055 std::size_t char_counter = 0;
0056 const char *buf = (const char *)mem;
0057 for(std::size_t i = 0; i != mem_length; ++i){
0058 out_str[char_counter++] = Characters[(buf[i]&0xF0)>>4];
0059 out_str[char_counter++] = Characters[(buf[i]&0x0F)];
0060 }
0061 out_str[char_counter] = 0;
0062 return true;
0063 }
0064
0065 inline bool bytes_to_str(const void *mem, const std::size_t mem_length, wchar_t *out_str, std::size_t &out_length)
0066 {
0067 const std::size_t need_mem = mem_length*2+1;
0068 if(out_length < need_mem){
0069 out_length = need_mem;
0070 return false;
0071 }
0072
0073 const wchar_t Characters [] =
0074 { L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7'
0075 , L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F' };
0076
0077 std::size_t char_counter = 0;
0078 const char *buf = (const char *)mem;
0079 for(std::size_t i = 0; i != mem_length; ++i){
0080 out_str[char_counter++] = Characters[(buf[i]&0xF0)>>4];
0081 out_str[char_counter++] = Characters[(buf[i]&0x0F)];
0082 }
0083 out_str[char_counter] = 0;
0084 return true;
0085 }
0086
0087 class sync_id
0088 {
0089 public:
0090 typedef __int64 internal_type;
0091 sync_id()
0092 { winapi::query_performance_counter(&rand_); }
0093
0094 explicit sync_id(internal_type val)
0095 { rand_ = val; }
0096
0097 const internal_type &internal_pod() const
0098 { return rand_; }
0099
0100 internal_type &internal_pod()
0101 { return rand_; }
0102
0103 friend std::size_t hash_value(const sync_id &m)
0104 { return static_cast<std::size_t>(m.rand_); }
0105
0106 friend bool operator==(const sync_id &l, const sync_id &r)
0107 { return l.rand_ == r.rand_; }
0108
0109 friend bool operator<(const sync_id &l, const sync_id &r)
0110 { return l.rand_ < r.rand_; }
0111
0112 private:
0113 internal_type rand_;
0114 };
0115
0116 class sync_handles
0117 {
0118 public:
0119 enum type { MUTEX, SEMAPHORE };
0120
0121 private:
0122
0123
0124 typedef boost::container::flat_map<sync_id, void*> id_map_type;
0125
0126 typedef boost::container::flat_map<const void*, id_map_type::iterator> addr_map_type;
0127 static const std::size_t LengthOfGlobal = sizeof("Global\\boost.ipc")-1;
0128 static const std::size_t StrSize = LengthOfGlobal + (sizeof(sync_id)*2+1);
0129 typedef char NameBuf[StrSize];
0130
0131 void fill_name(NameBuf &name, const sync_id &id)
0132 {
0133 const char *n = "Global\\boost.ipc";
0134 std::size_t i = 0;
0135 do{
0136 name[i] = n[i];
0137 ++i;
0138 } while(n[i]);
0139 std::size_t len = sizeof(NameBuf) - LengthOfGlobal;
0140 bytes_to_str(&id.internal_pod(), sizeof(id.internal_pod()), &name[LengthOfGlobal], len);
0141 }
0142
0143 void throw_if_error(void *hnd_val)
0144 {
0145 if(!hnd_val){
0146 error_info err(static_cast<int>(winapi::get_last_error()));
0147 throw interprocess_exception(err);
0148 }
0149 }
0150
0151 void* open_or_create_semaphore(const sync_id &id, unsigned int initial_count)
0152 {
0153 NameBuf name;
0154 fill_name(name, id);
0155 permissions unrestricted_security;
0156 unrestricted_security.set_unrestricted();
0157 winapi_semaphore_wrapper sem_wrapper;
0158 bool created;
0159 sem_wrapper.open_or_create
0160 (name, (long)initial_count, winapi_semaphore_wrapper::MaxCount, unrestricted_security, created);
0161 throw_if_error(sem_wrapper.handle());
0162 return sem_wrapper.release();
0163 }
0164
0165 void* open_or_create_mutex(const sync_id &id)
0166 {
0167 NameBuf name;
0168 fill_name(name, id);
0169 permissions unrestricted_security;
0170 unrestricted_security.set_unrestricted();
0171 winapi_mutex_wrapper mtx_wrapper;
0172 mtx_wrapper.open_or_create(name, unrestricted_security);
0173 throw_if_error(mtx_wrapper.handle());
0174 return mtx_wrapper.release();
0175 }
0176
0177 public:
0178 sync_handles()
0179 : num_handles_()
0180 {}
0181
0182 ~sync_handles()
0183 {
0184 BOOST_ASSERT(num_handles_ == 0);
0185 }
0186
0187 void *obtain_mutex(const sync_id &id, const void *mapping_address, bool *popen_created = 0)
0188 {
0189 id_map_type::value_type v(id, (void*)0);
0190 scoped_lock<spin_mutex> lock(mtx_);
0191 id_map_type::iterator it = umap_.insert(v).first;
0192 void *&hnd_val = it->second;
0193 if(!hnd_val){
0194 BOOST_ASSERT(map_.find(mapping_address) == map_.end());
0195 map_[mapping_address] = it;
0196 hnd_val = open_or_create_mutex(id);
0197 if(popen_created) *popen_created = true;
0198 ++num_handles_;
0199 }
0200 else if(popen_created){
0201 BOOST_ASSERT(map_.find(mapping_address) != map_.end());
0202 *popen_created = false;
0203 }
0204
0205 return hnd_val;
0206 }
0207
0208 void *obtain_semaphore(const sync_id &id, const void *mapping_address, unsigned int initial_count, bool *popen_created = 0)
0209 {
0210 id_map_type::value_type v(id, (void*)0);
0211 scoped_lock<spin_mutex> lock(mtx_);
0212 id_map_type::iterator it = umap_.insert(v).first;
0213 void *&hnd_val = it->second;
0214 if(!hnd_val){
0215 BOOST_ASSERT(map_.find(mapping_address) == map_.end());
0216 map_[mapping_address] = it;
0217 hnd_val = open_or_create_semaphore(id, initial_count);
0218 if(popen_created) *popen_created = true;
0219 ++num_handles_;
0220 }
0221 else if(popen_created){
0222 BOOST_ASSERT(map_.find(mapping_address) != map_.end());
0223 *popen_created = false;
0224 }
0225 return hnd_val;
0226 }
0227
0228 void destroy_handle(const sync_id &id, const void *mapping_address)
0229 {
0230 scoped_lock<spin_mutex> lock(mtx_);
0231 id_map_type::iterator it = umap_.find(id);
0232 id_map_type::iterator itend = umap_.end();
0233
0234 if(it != itend){
0235 winapi::close_handle(it->second);
0236 --num_handles_;
0237 std::size_t i = map_.erase(mapping_address);
0238 (void)i;
0239 BOOST_ASSERT(i == 1);
0240 umap_.erase(it);
0241 }
0242 }
0243
0244 void destroy_syncs_in_range(const void *addr, std::size_t size)
0245 {
0246 const void *low_id(addr);
0247 const void *hig_id(static_cast<const char*>(addr)+size);
0248 scoped_lock<spin_mutex> lock(mtx_);
0249 addr_map_type::iterator itlow(map_.lower_bound(low_id)),
0250 ithig(map_.lower_bound(hig_id)),
0251 it(itlow);
0252 for (; it != ithig; ++it){
0253 id_map_type::iterator uit = it->second;
0254 void * const hnd = uit->second;
0255 umap_.erase(uit);
0256 int ret = winapi::close_handle(hnd);
0257 --num_handles_;
0258 BOOST_ASSERT(ret != 0); (void)ret;
0259 }
0260
0261 map_.erase(itlow, ithig);
0262 }
0263
0264 private:
0265 spin_mutex mtx_;
0266 id_map_type umap_;
0267 addr_map_type map_;
0268 std::size_t num_handles_;
0269 };
0270
0271
0272 }
0273 }
0274 }
0275
0276 #include <boost/interprocess/detail/config_end.hpp>
0277
0278 #endif