]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
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; | |
70 | sync_id(const void *map_addr) | |
71 | : map_addr_(map_addr) | |
72 | { winapi::query_performance_counter(&rand_); } | |
73 | ||
74 | explicit sync_id(internal_type val, const void *map_addr) | |
75 | : map_addr_(map_addr) | |
76 | { rand_ = val; } | |
77 | ||
78 | const internal_type &internal_pod() const | |
79 | { return rand_; } | |
80 | ||
81 | internal_type &internal_pod() | |
82 | { return rand_; } | |
83 | ||
84 | const void *map_address() const | |
85 | { return map_addr_; } | |
86 | ||
87 | friend std::size_t hash_value(const sync_id &m) | |
88 | { return boost::hash_value(m.rand_); } | |
89 | ||
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 | { | |
106 | 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 | ||
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 | ||
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 | ||
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 | ||
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: | |
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 | ||
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 | ||
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 | ||
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 |