237 lines
6.9 KiB
C++
237 lines
6.9 KiB
C++
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// (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
|
|
|
|
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
|
|
# 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
|