Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

singleton: Allocate singleton instance on heap #79

Closed
wants to merge 13 commits into from
20 changes: 19 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,32 @@ matrix:
sources:
- ubuntu-toolchain-r-test

- os: linux
compiler: g++-7
env: TOOLSET=gcc-7 LINK=static
addons:
apt:
packages:
- g++-7
sources:
- ubuntu-toolchain-r-test

- os: linux
compiler: clang++
env: TOOLSET=clang

- os: linux
compiler: clang++
env: TOOLSET=clang LINK=static

- os: osx
compiler: clang++
env: TOOLSET=clang

- os: osx
compiler: clang++
env: TOOLSET=clang LINK=static

install:
- BOOST_BRANCH=develop && [ "$TRAVIS_BRANCH" == "master" ] && BOOST_BRANCH=master || true
- cd ..
Expand All @@ -78,7 +96,7 @@ install:
- ./b2 headers

script:
- ./b2 -j 3 libs/serialization/test toolset=$TOOLSET
- ./b2 -j 3 libs/serialization/test toolset=$TOOLSET link=${LINK:-shared}

notifications:
email:
Expand Down
14 changes: 13 additions & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@ branches:
- develop
# - master

environment:
matrix:
- BUILD_TOOLSET: gcc
BUILD_LINK: static
- BUILD_TOOLSET: gcc
BUILD_LINK: shared
- BUILD_TOOLSET: msvc-14.0
BUILD_LINK: static
- BUILD_TOOLSET: msvc-14.0
BUILD_LINK: shared

install:
- cd ..
- git clone -b %APPVEYOR_REPO_BRANCH% https://github.com/boostorg/boost.git boost-root
Expand All @@ -24,6 +35,7 @@ install:
- git submodule init libs/concept_check
- git submodule init libs/config
- git submodule init libs/container
- git submodule init libs/container_hash
- git submodule init libs/core
- git submodule init libs/detail
- git submodule init libs/filesystem
Expand Down Expand Up @@ -65,4 +77,4 @@ build: off

test_script:
- cd libs/serialization/test
- b2 toolset=gcc link=static,shared
- b2 -j2 toolset=%BUILD_TOOLSET% link=%BUILD_LINK%
58 changes: 44 additions & 14 deletions include/boost/serialization/singleton.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,20 +112,55 @@ template <class T>
class singleton : public singleton_module
{
private:
static T & m_instance;
static void cleanup_func() {
delete static_cast<singleton_wrapper*> (&get_instance());
}

// use a wrapper so that types T with protected constructors
// can be used
class singleton_wrapper : public T {
public:
singleton_wrapper () {
#if !defined(BOOST_ALL_DYN_LINK) && !defined(BOOST_SERIALIZATION_DYN_LINK)
/* Static builds: We're in a single module, use atexit() to
* ensure destruction in reverse of construction.
* (In static builds the compiler-generated order may be wrong...) */
atexit(&cleanup_func);
#endif
}
};

/* This wrapper ensures the instance is cleaned up when the
* module is wound down. (The cleanup of the static variable
* in get_instance() may happen at the wrong time.) */
struct instance_and_cleanup
{
T& x;

instance_and_cleanup(T& x) : x(x) {
}
~instance_and_cleanup() {
#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_SERIALIZATION_DYN_LINK)
/* Shared builds: The ordering through global variables is
* sufficient.
* However, avoid atexit() as it may cause destruction order
* issues here. */
singleton<T>::cleanup_func();
#endif
}
};
static instance_and_cleanup m_instance_and_cleanup;
// include this to provoke instantiation at pre-execution time
static void use(T const *) {}
static T & get_instance() {
// use a wrapper so that types T with protected constructors
// can be used
class singleton_wrapper : public T {};

// Use a heap-allocated instance to work around static variable
// destruction order issues: this inner singleton_wrapper<>
// instance may be destructed before the singleton<> instance.
// Using a 'dumb' static variable lets us precisely choose the
// time destructor is invoked.
static singleton_wrapper *t = 0;
// The destruction itself is handled by m_instance_cleanup (for
// shared builds) or in an atexit() function (static builds).
static singleton_wrapper* t = new singleton_wrapper;

// refer to instance, causing it to be instantiated (and
// initialized at startup on working compilers)
Expand All @@ -136,10 +171,7 @@ class singleton : public singleton_module
// construct the instance at pre-execution time. This would prevent
// our usage/implementation of "locking" and introduce uncertainty into
// the sequence of object initializaition.
use(& m_instance);

if (!t)
t = new singleton_wrapper;
use(& m_instance_and_cleanup.x);
return static_cast<T &>(*t);
}
static bool & get_is_destroyed(){
Expand All @@ -162,15 +194,13 @@ class singleton : public singleton_module
get_is_destroyed() = false;
}
BOOST_DLLEXPORT ~singleton() {
if (!get_is_destroyed()) {
delete &(get_instance());
}
get_is_destroyed() = true;
}
};

template<class T>
T & singleton< T >::m_instance = singleton< T >::get_instance();
typename singleton< T >::instance_and_cleanup singleton< T >::m_instance_and_cleanup (
singleton< T >::get_instance());

} // namespace serialization
} // namespace boost
Expand Down
9 changes: 5 additions & 4 deletions include/boost/serialization/void_cast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,13 +181,14 @@ void_caster_primitive<Derived, Base>::void_caster_primitive() :
void_caster(
& type_info_implementation<Derived>::type::get_const_instance(),
& type_info_implementation<Base>::type::get_const_instance(),
// note:I wanted to displace from 0 here, but at least one compiler
// treated 0 by not shifting it at all.
/* note about displacement:
* displace 0: at least one compiler treated 0 by not shifting it at all
* displace by small value (8): caused ICE on certain mingw gcc versions */
reinterpret_cast<std::ptrdiff_t>(
static_cast<Derived *>(
reinterpret_cast<Base *>(8)
reinterpret_cast<Base *>(1 << 20)
)
) - 8
) - (1 << 20)
)
{
recursive_register();
Expand Down