| ////////////////////////////////////////////////////////////////////////////// |
| // |
| // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost |
| // Software License, Version 1.0. (See accompanying file |
| // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| // |
| // See http://www.boost.org/libs/interprocess for documentation. |
| // |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| #ifndef BOOST_INTERPROCESS_DETAIL_SYNC_UTILS_HPP |
| #define BOOST_INTERPROCESS_DETAIL_SYNC_UTILS_HPP |
| |
| #ifndef BOOST_CONFIG_HPP |
| # include <boost/config.hpp> |
| #endif |
| # |
| #if defined(BOOST_HAS_PRAGMA_ONCE) |
| # pragma once |
| #endif |
| |
| #include <boost/interprocess/detail/config_begin.hpp> |
| #include <boost/interprocess/detail/workaround.hpp> |
| #include <boost/interprocess/detail/win32_api.hpp> |
| #include <boost/interprocess/sync/spin/mutex.hpp> |
| #include <boost/interprocess/exceptions.hpp> |
| #include <boost/interprocess/sync/scoped_lock.hpp> |
| #include <boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp> |
| #include <boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp> |
| |
| //Shield against external warnings |
| #include <boost/interprocess/detail/config_external_begin.hpp> |
| #include <boost/unordered/unordered_map.hpp> |
| #include <boost/interprocess/detail/config_external_end.hpp> |
| |
| |
| #include <boost/container/map.hpp> |
| #include <cstddef> |
| |
| namespace boost { |
| namespace interprocess { |
| namespace ipcdetail { |
| |
| inline bool bytes_to_str(const void *mem, const std::size_t mem_length, char *out_str, std::size_t &out_length) |
| { |
| const std::size_t need_mem = mem_length*2+1; |
| if(out_length < need_mem){ |
| out_length = need_mem; |
| return false; |
| } |
| |
| const char Characters [] = |
| { '0', '1', '2', '3', '4', '5', '6', '7' |
| , '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; |
| |
| std::size_t char_counter = 0; |
| const char *buf = (const char *)mem; |
| for(std::size_t i = 0; i != mem_length; ++i){ |
| out_str[char_counter++] = Characters[(buf[i]&0xF0)>>4]; |
| out_str[char_counter++] = Characters[(buf[i]&0x0F)]; |
| } |
| out_str[char_counter] = 0; |
| return true; |
| } |
| |
| class sync_id |
| { |
| public: |
| typedef __int64 internal_type; |
| sync_id(const void *map_addr) |
| : map_addr_(map_addr) |
| { winapi::query_performance_counter(&rand_); } |
| |
| explicit sync_id(internal_type val, const void *map_addr) |
| : map_addr_(map_addr) |
| { rand_ = val; } |
| |
| const internal_type &internal_pod() const |
| { return rand_; } |
| |
| internal_type &internal_pod() |
| { return rand_; } |
| |
| const void *map_address() const |
| { return map_addr_; } |
| |
| friend std::size_t hash_value(const sync_id &m) |
| { return boost::hash_value(m.rand_); } |
| |
| friend bool operator==(const sync_id &l, const sync_id &r) |
| { return l.rand_ == r.rand_ && l.map_addr_ == r.map_addr_; } |
| |
| private: |
| internal_type rand_; |
| const void * const map_addr_; |
| }; |
| |
| class sync_handles |
| { |
| public: |
| enum type { MUTEX, SEMAPHORE }; |
| |
| private: |
| struct address_less |
| { |
| bool operator()(sync_id const * const l, sync_id const * const r) const |
| { return l->map_address() < r->map_address(); } |
| }; |
| |
| typedef boost::unordered_map<sync_id, void*> umap_type; |
| typedef boost::container::map<const sync_id*, umap_type::iterator, address_less> map_type; |
| static const std::size_t LengthOfGlobal = sizeof("Global\\boost.ipc")-1; |
| static const std::size_t StrSize = LengthOfGlobal + (sizeof(sync_id)*2+1); |
| typedef char NameBuf[StrSize]; |
| |
| |
| void fill_name(NameBuf &name, const sync_id &id) |
| { |
| const char *n = "Global\\boost.ipc"; |
| std::size_t i = 0; |
| do{ |
| name[i] = n[i]; |
| ++i; |
| } while(n[i]); |
| std::size_t len = sizeof(NameBuf) - LengthOfGlobal; |
| bytes_to_str(&id.internal_pod(), sizeof(id.internal_pod()), &name[LengthOfGlobal], len); |
| } |
| |
| void throw_if_error(void *hnd_val) |
| { |
| if(!hnd_val){ |
| error_info err(winapi::get_last_error()); |
| throw interprocess_exception(err); |
| } |
| } |
| |
| void* open_or_create_semaphore(const sync_id &id, unsigned int initial_count) |
| { |
| NameBuf name; |
| fill_name(name, id); |
| permissions unrestricted_security; |
| unrestricted_security.set_unrestricted(); |
| winapi_semaphore_wrapper sem_wrapper; |
| bool created; |
| sem_wrapper.open_or_create |
| (name, (long)initial_count, winapi_semaphore_wrapper::MaxCount, unrestricted_security, created); |
| throw_if_error(sem_wrapper.handle()); |
| return sem_wrapper.release(); |
| } |
| |
| void* open_or_create_mutex(const sync_id &id) |
| { |
| NameBuf name; |
| fill_name(name, id); |
| permissions unrestricted_security; |
| unrestricted_security.set_unrestricted(); |
| winapi_mutex_wrapper mtx_wrapper; |
| mtx_wrapper.open_or_create(name, unrestricted_security); |
| throw_if_error(mtx_wrapper.handle()); |
| return mtx_wrapper.release(); |
| } |
| |
| public: |
| void *obtain_mutex(const sync_id &id, bool *popen_created = 0) |
| { |
| umap_type::value_type v(id, (void*)0); |
| scoped_lock<spin_mutex> lock(mtx_); |
| umap_type::iterator it = umap_.insert(v).first; |
| void *&hnd_val = it->second; |
| if(!hnd_val){ |
| map_[&it->first] = it; |
| hnd_val = open_or_create_mutex(id); |
| if(popen_created) *popen_created = true; |
| } |
| else if(popen_created){ |
| *popen_created = false; |
| } |
| return hnd_val; |
| } |
| |
| void *obtain_semaphore(const sync_id &id, unsigned int initial_count, bool *popen_created = 0) |
| { |
| umap_type::value_type v(id, (void*)0); |
| scoped_lock<spin_mutex> lock(mtx_); |
| umap_type::iterator it = umap_.insert(v).first; |
| void *&hnd_val = it->second; |
| if(!hnd_val){ |
| map_[&it->first] = it; |
| hnd_val = open_or_create_semaphore(id, initial_count); |
| if(popen_created) *popen_created = true; |
| } |
| else if(popen_created){ |
| *popen_created = false; |
| } |
| return hnd_val; |
| } |
| |
| void destroy_handle(const sync_id &id) |
| { |
| scoped_lock<spin_mutex> lock(mtx_); |
| umap_type::iterator it = umap_.find(id); |
| umap_type::iterator itend = umap_.end(); |
| |
| if(it != itend){ |
| winapi::close_handle(it->second); |
| const map_type::key_type &k = &it->first; |
| map_.erase(k); |
| umap_.erase(it); |
| } |
| } |
| |
| void destroy_syncs_in_range(const void *addr, std::size_t size) |
| { |
| const sync_id low_id(addr); |
| const sync_id hig_id(static_cast<const char*>(addr)+size); |
| scoped_lock<spin_mutex> lock(mtx_); |
| map_type::iterator itlow(map_.lower_bound(&low_id)), |
| ithig(map_.lower_bound(&hig_id)); |
| while(itlow != ithig){ |
| void * const hnd = umap_[*itlow->first]; |
| winapi::close_handle(hnd); |
| umap_.erase(*itlow->first); |
| itlow = map_.erase(itlow); |
| } |
| } |
| |
| private: |
| spin_mutex mtx_; |
| umap_type umap_; |
| map_type map_; |
| }; |
| |
| |
| } //namespace ipcdetail { |
| } //namespace interprocess { |
| } //namespace boost { |
| |
| #include <boost/interprocess/detail/config_end.hpp> |
| |
| #endif //BOOST_INTERPROCESS_DETAIL_SYNC_UTILS_HPP |