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.
9 #ifndef BOOST_FLYWEIGHT_INTERMODULE_HOLDER_HPP
10 #define BOOST_FLYWEIGHT_INTERMODULE_HOLDER_HPP
12 #if defined(_MSC_VER)&&(_MSC_VER>=1200)
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>
29 /* intermodule_holder_class guarantees a unique instance across all dynamic
30 * modules of a program.
38 struct intermodule_holder_class
:holder_marker
42 static instantiator instance
;
43 return instance
.get();
50 mutex(interprocess::open_or_create
,compute_mutex_name()),
51 seg(interprocess::open_or_create
,compute_segment_name(),16384),
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);
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
);
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();
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){
106 C
& get()const{return *pc
;}
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()
121 "boost_flyweight_intermodule_holder_mutex_"
123 (long)detail::process_id(),
124 (unsigned)compute_hash(typeid(C
).name(),0),
125 (unsigned)compute_hash(typeid(C
).name(),1));
130 const char* compute_segment_name()
134 "boost_flyweight_intermodule_holder_segment_"
136 (long)detail::process_id(),
137 (unsigned)compute_hash(typeid(C
).name(),0),
138 (unsigned)compute_hash(typeid(C
).name(),1));
143 static std::size_t compute_hash(const char* str
,std::size_t off
)
145 std::size_t len
=std::strlen(str
);
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 */
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
180 typedef intermodule_holder_class
<C
> type
;
184 } /* namespace flyweights */
186 } /* namespace boost */