• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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