1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2005-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_DETAIL_SYNC_UTILS_HPP
12 #define BOOST_INTERPROCESS_DETAIL_SYNC_UTILS_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 #include <boost/interprocess/detail/win32_api.hpp>
25 #include <boost/interprocess/sync/spin/mutex.hpp>
26 #include <boost/interprocess/exceptions.hpp>
27 #include <boost/interprocess/sync/scoped_lock.hpp>
28 #include <boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp>
29 #include <boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp>
30
31 //Shield against external warnings
32 #include <boost/interprocess/detail/config_external_begin.hpp>
33 #include <boost/unordered/unordered_map.hpp>
34 #include <boost/interprocess/detail/config_external_end.hpp>
35
36
37 #include <boost/container/map.hpp>
38 #include <cstddef>
39
40 namespace boost {
41 namespace interprocess {
42 namespace ipcdetail {
43
bytes_to_str(const void * mem,const std::size_t mem_length,char * out_str,std::size_t & out_length)44 inline bool bytes_to_str(const void *mem, const std::size_t mem_length, char *out_str, std::size_t &out_length)
45 {
46 const std::size_t need_mem = mem_length*2+1;
47 if(out_length < need_mem){
48 out_length = need_mem;
49 return false;
50 }
51
52 const char Characters [] =
53 { '0', '1', '2', '3', '4', '5', '6', '7'
54 , '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
55
56 std::size_t char_counter = 0;
57 const char *buf = (const char *)mem;
58 for(std::size_t i = 0; i != mem_length; ++i){
59 out_str[char_counter++] = Characters[(buf[i]&0xF0)>>4];
60 out_str[char_counter++] = Characters[(buf[i]&0x0F)];
61 }
62 out_str[char_counter] = 0;
63 return true;
64 }
65
66 class sync_id
67 {
68 public:
69 typedef __int64 internal_type;
sync_id(const void * map_addr)70 sync_id(const void *map_addr)
71 : map_addr_(map_addr)
72 { winapi::query_performance_counter(&rand_); }
73
sync_id(internal_type val,const void * map_addr)74 explicit sync_id(internal_type val, const void *map_addr)
75 : map_addr_(map_addr)
76 { rand_ = val; }
77
internal_pod() const78 const internal_type &internal_pod() const
79 { return rand_; }
80
internal_pod()81 internal_type &internal_pod()
82 { return rand_; }
83
map_address() const84 const void *map_address() const
85 { return map_addr_; }
86
hash_value(const sync_id & m)87 friend std::size_t hash_value(const sync_id &m)
88 { return boost::hash_value(m.rand_); }
89
operator ==(const sync_id & l,const sync_id & r)90 friend bool operator==(const sync_id &l, const sync_id &r)
91 { return l.rand_ == r.rand_ && l.map_addr_ == r.map_addr_; }
92
93 private:
94 internal_type rand_;
95 const void * const map_addr_;
96 };
97
98 class sync_handles
99 {
100 public:
101 enum type { MUTEX, SEMAPHORE };
102
103 private:
104 struct address_less
105 {
operator ()boost::interprocess::ipcdetail::sync_handles::address_less106 bool operator()(sync_id const * const l, sync_id const * const r) const
107 { return l->map_address() < r->map_address(); }
108 };
109
110 typedef boost::unordered_map<sync_id, void*> umap_type;
111 typedef boost::container::map<const sync_id*, umap_type::iterator, address_less> map_type;
112 static const std::size_t LengthOfGlobal = sizeof("Global\\boost.ipc")-1;
113 static const std::size_t StrSize = LengthOfGlobal + (sizeof(sync_id)*2+1);
114 typedef char NameBuf[StrSize];
115
116
fill_name(NameBuf & name,const sync_id & id)117 void fill_name(NameBuf &name, const sync_id &id)
118 {
119 const char *n = "Global\\boost.ipc";
120 std::size_t i = 0;
121 do{
122 name[i] = n[i];
123 ++i;
124 } while(n[i]);
125 std::size_t len = sizeof(NameBuf) - LengthOfGlobal;
126 bytes_to_str(&id.internal_pod(), sizeof(id.internal_pod()), &name[LengthOfGlobal], len);
127 }
128
throw_if_error(void * hnd_val)129 void throw_if_error(void *hnd_val)
130 {
131 if(!hnd_val){
132 error_info err(winapi::get_last_error());
133 throw interprocess_exception(err);
134 }
135 }
136
open_or_create_semaphore(const sync_id & id,unsigned int initial_count)137 void* open_or_create_semaphore(const sync_id &id, unsigned int initial_count)
138 {
139 NameBuf name;
140 fill_name(name, id);
141 permissions unrestricted_security;
142 unrestricted_security.set_unrestricted();
143 winapi_semaphore_wrapper sem_wrapper;
144 bool created;
145 sem_wrapper.open_or_create
146 (name, (long)initial_count, winapi_semaphore_wrapper::MaxCount, unrestricted_security, created);
147 throw_if_error(sem_wrapper.handle());
148 return sem_wrapper.release();
149 }
150
open_or_create_mutex(const sync_id & id)151 void* open_or_create_mutex(const sync_id &id)
152 {
153 NameBuf name;
154 fill_name(name, id);
155 permissions unrestricted_security;
156 unrestricted_security.set_unrestricted();
157 winapi_mutex_wrapper mtx_wrapper;
158 mtx_wrapper.open_or_create(name, unrestricted_security);
159 throw_if_error(mtx_wrapper.handle());
160 return mtx_wrapper.release();
161 }
162
163 public:
obtain_mutex(const sync_id & id,bool * popen_created=0)164 void *obtain_mutex(const sync_id &id, bool *popen_created = 0)
165 {
166 umap_type::value_type v(id, (void*)0);
167 scoped_lock<spin_mutex> lock(mtx_);
168 umap_type::iterator it = umap_.insert(v).first;
169 void *&hnd_val = it->second;
170 if(!hnd_val){
171 map_[&it->first] = it;
172 hnd_val = open_or_create_mutex(id);
173 if(popen_created) *popen_created = true;
174 }
175 else if(popen_created){
176 *popen_created = false;
177 }
178 return hnd_val;
179 }
180
obtain_semaphore(const sync_id & id,unsigned int initial_count,bool * popen_created=0)181 void *obtain_semaphore(const sync_id &id, unsigned int initial_count, bool *popen_created = 0)
182 {
183 umap_type::value_type v(id, (void*)0);
184 scoped_lock<spin_mutex> lock(mtx_);
185 umap_type::iterator it = umap_.insert(v).first;
186 void *&hnd_val = it->second;
187 if(!hnd_val){
188 map_[&it->first] = it;
189 hnd_val = open_or_create_semaphore(id, initial_count);
190 if(popen_created) *popen_created = true;
191 }
192 else if(popen_created){
193 *popen_created = false;
194 }
195 return hnd_val;
196 }
197
destroy_handle(const sync_id & id)198 void destroy_handle(const sync_id &id)
199 {
200 scoped_lock<spin_mutex> lock(mtx_);
201 umap_type::iterator it = umap_.find(id);
202 umap_type::iterator itend = umap_.end();
203
204 if(it != itend){
205 winapi::close_handle(it->second);
206 const map_type::key_type &k = &it->first;
207 map_.erase(k);
208 umap_.erase(it);
209 }
210 }
211
destroy_syncs_in_range(const void * addr,std::size_t size)212 void destroy_syncs_in_range(const void *addr, std::size_t size)
213 {
214 const sync_id low_id(addr);
215 const sync_id hig_id(static_cast<const char*>(addr)+size);
216 scoped_lock<spin_mutex> lock(mtx_);
217 map_type::iterator itlow(map_.lower_bound(&low_id)),
218 ithig(map_.lower_bound(&hig_id));
219 while(itlow != ithig){
220 void * const hnd = umap_[*itlow->first];
221 winapi::close_handle(hnd);
222 umap_.erase(*itlow->first);
223 itlow = map_.erase(itlow);
224 }
225 }
226
227 private:
228 spin_mutex mtx_;
229 umap_type umap_;
230 map_type map_;
231 };
232
233
234 } //namespace ipcdetail {
235 } //namespace interprocess {
236 } //namespace boost {
237
238 #include <boost/interprocess/detail/config_end.hpp>
239
240 #endif //BOOST_INTERPROCESS_DETAIL_SYNC_UTILS_HPP
241