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