sync_utils.hpp 8.6 KB

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