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