/* Copyright 2006-2009 Joaquin M Lopez Munoz. * 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/flyweight for library home page. */ #ifndef BOOST_FLYWEIGHT_INTERMODULE_HOLDER_HPP #define BOOST_FLYWEIGHT_INTERMODULE_HOLDER_HPP #if defined(_MSC_VER)&&(_MSC_VER>=1200) #pragma once #endif #include /* keep it first to prevent nasty warns in MSVC */ #include #include #include #include #include #include #include #include #include #include #include /* intermodule_holder_class guarantees a unique instance across all dynamic * modules of a program. */ namespace boost{ namespace flyweights{ template struct intermodule_holder_class:holder_marker { static C& get() { static instantiator instance; return instance.get(); } private: struct instantiator { instantiator(): mutex(interprocess::open_or_create,compute_mutex_name()), seg(interprocess::open_or_create,compute_segment_name(),16384), ppref(0), pc(0) { /* Instance creation is done according to a two-phase protocol so * that we call "new" in an unlocked situation, thus minimizing the * chance of leaving dangling locks due to catastrophic failure. */ { interprocess::scoped_lock lock(mutex); ppref=seg.find_or_construct( typeid(C).name())((referenced_instance*)0); if(*ppref){ /* As in some OSes Boost.Interprocess memory segments can outlive * their associated processes, there is a possibility that we * retrieve a dangling pointer (coming from a previous aborted run, * for instance). Try to protect against this by checking that * the contents of the pointed object are consistent. */ if(std::strcmp(segment_name,(*ppref)->segment_name)!=0){ *ppref=0; /* dangling pointer! */ } else ++((*ppref)->ref); } } if(!*ppref){ std::auto_ptr apc( new referenced_instance(segment_name)); interprocess::scoped_lock lock(mutex); ppref=seg.find_or_construct( typeid(C).name())((referenced_instance*)0); if(!*ppref)*ppref=apc.release(); ++((*ppref)->ref); } pc=&(*ppref)->c; } ~instantiator() { /* As in construction time, actual deletion is performed outside the * lock to avoid leaving the lock dangling in case of crash. */ referenced_instance* pref=0; { interprocess::scoped_lock lock(mutex); if(--((*ppref)->ref)==0){ pref=*ppref; *ppref=0; } } if(pref)delete pref; } C& get()const{return *pc;} private: /* Although mutex and seg are system-wide, their names intend to * make them specific for the current process and type, hence their * containing process id and type id info. */ char mutex_name[128]; char segment_name[128]; const char* compute_mutex_name() { std::sprintf( mutex_name, "boost_flyweight_intermodule_holder_mutex_" "%ld_%u_%u", (long)detail::process_id(), (unsigned)compute_hash(typeid(C).name(),0), (unsigned)compute_hash(typeid(C).name(),1)); return mutex_name; } const char* compute_segment_name() { std::sprintf( segment_name, "boost_flyweight_intermodule_holder_segment_" "%ld_%u_%u", (long)detail::process_id(), (unsigned)compute_hash(typeid(C).name(),0), (unsigned)compute_hash(typeid(C).name(),1)); return segment_name; } static std::size_t compute_hash(const char* str,std::size_t off) { std::size_t len=std::strlen(str); if(off>len)off=len; return hash_range(str+off,str+len); } interprocess::named_mutex mutex; interprocess::managed_shared_memory seg; struct referenced_instance { referenced_instance(const char* segment_name_):ref(0) { std::strcpy(segment_name,segment_name_); } ~referenced_instance(){segment_name[0]='\0';} char segment_name[128]; /* used to detect dangling pointers */ mutable long ref; C c; }** ppref; C* pc; }; public: typedef intermodule_holder_class type; BOOST_MPL_AUX_LAMBDA_SUPPORT(1,intermodule_holder_class,(C)) }; /* intermodule_holder_class specifier */ struct intermodule_holder:holder_marker { template struct apply { typedef intermodule_holder_class type; }; }; } /* namespace flyweights */ } /* namespace boost */ #endif