fix doc example typo
[boost.git] / boost / flyweight / intermodule_holder.hpp
blobe8a968eb6d00b3a3068c009f540b829f4b865914
1 /* Copyright 2006-2009 Joaquin M Lopez Munoz.
2 * Distributed under the Boost Software License, Version 1.0.
3 * (See accompanying file LICENSE_1_0.txt or copy at
4 * http://www.boost.org/LICENSE_1_0.txt)
6 * See http://www.boost.org/libs/flyweight for library home page.
7 */
9 #ifndef BOOST_FLYWEIGHT_INTERMODULE_HOLDER_HPP
10 #define BOOST_FLYWEIGHT_INTERMODULE_HOLDER_HPP
12 #if defined(_MSC_VER)&&(_MSC_VER>=1200)
13 #pragma once
14 #endif
16 #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
17 #include <boost/flyweight/holder_tag.hpp>
18 #include <boost/flyweight/intermodule_holder_fwd.hpp>
19 #include <boost/flyweight/detail/process_id.hpp>
20 #include <boost/functional/hash.hpp>
21 #include <boost/interprocess/sync/named_mutex.hpp>
22 #include <boost/interprocess/sync/scoped_lock.hpp>
23 #include <boost/interprocess/managed_shared_memory.hpp>
24 #include <boost/mpl/aux_/lambda_support.hpp>
25 #include <cstdio>
26 #include <cstring>
27 #include <memory>
29 /* intermodule_holder_class guarantees a unique instance across all dynamic
30 * modules of a program.
33 namespace boost{
35 namespace flyweights{
37 template<typename C>
38 struct intermodule_holder_class:holder_marker
40 static C& get()
42 static instantiator instance;
43 return instance.get();
46 private:
47 struct instantiator
49 instantiator():
50 mutex(interprocess::open_or_create,compute_mutex_name()),
51 seg(interprocess::open_or_create,compute_segment_name(),16384),
52 ppref(0),
53 pc(0)
55 /* Instance creation is done according to a two-phase protocol so
56 * that we call "new" in an unlocked situation, thus minimizing the
57 * chance of leaving dangling locks due to catastrophic failure.
61 interprocess::scoped_lock<interprocess::named_mutex> lock(mutex);
62 ppref=seg.find_or_construct<referenced_instance*>(
63 typeid(C).name())((referenced_instance*)0);
64 if(*ppref){
65 /* As in some OSes Boost.Interprocess memory segments can outlive
66 * their associated processes, there is a possibility that we
67 * retrieve a dangling pointer (coming from a previous aborted run,
68 * for instance). Try to protect against this by checking that
69 * the contents of the pointed object are consistent.
71 if(std::strcmp(segment_name,(*ppref)->segment_name)!=0){
72 *ppref=0; /* dangling pointer! */
74 else ++((*ppref)->ref);
77 if(!*ppref){
78 std::auto_ptr<referenced_instance> apc(
79 new referenced_instance(segment_name));
80 interprocess::scoped_lock<interprocess::named_mutex> lock(mutex);
81 ppref=seg.find_or_construct<referenced_instance*>(
82 typeid(C).name())((referenced_instance*)0);
83 if(!*ppref)*ppref=apc.release();
84 ++((*ppref)->ref);
86 pc=&(*ppref)->c;
89 ~instantiator()
91 /* As in construction time, actual deletion is performed outside the
92 * lock to avoid leaving the lock dangling in case of crash.
95 referenced_instance* pref=0;
97 interprocess::scoped_lock<interprocess::named_mutex> lock(mutex);
98 if(--((*ppref)->ref)==0){
99 pref=*ppref;
100 *ppref=0;
103 if(pref)delete pref;
106 C& get()const{return *pc;}
108 private:
109 /* Although mutex and seg are system-wide, their names intend to
110 * make them specific for the current process and type, hence their
111 * containing process id and type id info.
114 char mutex_name[128];
115 char segment_name[128];
117 const char* compute_mutex_name()
119 std::sprintf(
120 mutex_name,
121 "boost_flyweight_intermodule_holder_mutex_"
122 "%ld_%u_%u",
123 (long)detail::process_id(),
124 (unsigned)compute_hash(typeid(C).name(),0),
125 (unsigned)compute_hash(typeid(C).name(),1));
127 return mutex_name;
130 const char* compute_segment_name()
132 std::sprintf(
133 segment_name,
134 "boost_flyweight_intermodule_holder_segment_"
135 "%ld_%u_%u",
136 (long)detail::process_id(),
137 (unsigned)compute_hash(typeid(C).name(),0),
138 (unsigned)compute_hash(typeid(C).name(),1));
140 return segment_name;
143 static std::size_t compute_hash(const char* str,std::size_t off)
145 std::size_t len=std::strlen(str);
146 if(off>len)off=len;
147 return hash_range(str+off,str+len);
150 interprocess::named_mutex mutex;
151 interprocess::managed_shared_memory seg;
152 struct referenced_instance
154 referenced_instance(const char* segment_name_):ref(0)
156 std::strcpy(segment_name,segment_name_);
159 ~referenced_instance(){segment_name[0]='\0';}
161 char segment_name[128]; /* used to detect dangling pointers */
162 mutable long ref;
163 C c;
164 }** ppref;
165 C* pc;
168 public:
169 typedef intermodule_holder_class type;
170 BOOST_MPL_AUX_LAMBDA_SUPPORT(1,intermodule_holder_class,(C))
173 /* intermodule_holder_class specifier */
175 struct intermodule_holder:holder_marker
177 template<typename C>
178 struct apply
180 typedef intermodule_holder_class<C> type;
184 } /* namespace flyweights */
186 } /* namespace boost */
188 #endif