sync_utils.hpp 6.9 KB

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