Ticket #934: refactor DependencyFactory back to local memory management
This removes the central clean-up registry; Instead, now the InstanceHolder manages the lifecycle of the service instances placed into static memory; the net effect is that DependencyFactory and instances are created and destroyed together, locally for each usage scope
This commit is contained in:
parent
52c83b860b
commit
7204c58680
2 changed files with 25 additions and 156 deletions
|
|
@ -1,98 +0,0 @@
|
||||||
/*
|
|
||||||
DependencyFactory - managing the lifecycle of singletons and dependencies
|
|
||||||
|
|
||||||
Copyright (C) Lumiera.org
|
|
||||||
2013, Hermann Vosseler <Ichthyostega@web.de>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License as
|
|
||||||
published by the Free Software Foundation; either version 2 of
|
|
||||||
the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
|
|
||||||
* *****************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
/** @file dependency-factory.cpp
|
|
||||||
** This compilation unit holds the common backend of all singleton and dependency factories.
|
|
||||||
** Especially the code for tracking and clean-up of all service instance is located here.
|
|
||||||
** This clean-up is triggered by the invocation of \c ~AutoDestructor() -- at this point
|
|
||||||
** a special \c shutdownLock is set, which prevents any further singleton service creation.
|
|
||||||
**
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "lib/dependency-factory.hpp"
|
|
||||||
#include "lib/del-stash.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
namespace lib {
|
|
||||||
namespace error = lumiera::error;
|
|
||||||
|
|
||||||
|
|
||||||
namespace { // private implementation details...
|
|
||||||
|
|
||||||
class AutoDestructor
|
|
||||||
{
|
|
||||||
DelStash destructionExecutor_;
|
|
||||||
static bool shutdownLock;
|
|
||||||
|
|
||||||
|
|
||||||
static AutoDestructor&
|
|
||||||
instance()
|
|
||||||
{
|
|
||||||
static AutoDestructor _instance_;
|
|
||||||
return _instance_;
|
|
||||||
}
|
|
||||||
|
|
||||||
~AutoDestructor()
|
|
||||||
{
|
|
||||||
shutdownLock = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
__lifecycleCheck()
|
|
||||||
{
|
|
||||||
if (shutdownLock)
|
|
||||||
throw error::Fatal("Attempt to re-access a service, "
|
|
||||||
"while Application is already in shutdown"
|
|
||||||
,error::LUMIERA_ERROR_LIFECYCLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
static void
|
|
||||||
schedule (void* object, DependencyFactory::KillFun customDeleter)
|
|
||||||
{
|
|
||||||
__lifecycleCheck();
|
|
||||||
instance().destructionExecutor_.manage (object, customDeleter);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
bool AutoDestructor::shutdownLock = false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** hook to install a deleter function to clean up a service object.
|
|
||||||
* The standard constructor function uses this hook to schedule the
|
|
||||||
* destructor invocation on application shutdown; custom constructors
|
|
||||||
* are free to use this mechanism (or care for clean-up otherwise)
|
|
||||||
* @see lib::DelStash
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
DependencyFactory::scheduleDestruction (void* object, KillFun customDeleter)
|
|
||||||
{
|
|
||||||
AutoDestructor::schedule (object, customDeleter);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}// lib
|
|
||||||
|
|
@ -111,9 +111,6 @@ namespace lib {
|
||||||
return ctorFunction_();
|
return ctorFunction_();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scheduleDestruction (void*, KillFun);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -146,61 +143,39 @@ namespace lib {
|
||||||
{
|
{
|
||||||
/** storage for the service instance */
|
/** storage for the service instance */
|
||||||
char buff_[sizeof(TAR)];
|
char buff_[sizeof(TAR)];
|
||||||
|
uint lifecycle_;
|
||||||
#if NOBUG_MODE_ALPHA
|
|
||||||
static int createCnt;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** deleter function to invoke the destructor
|
|
||||||
* of the embedded service object instance.
|
|
||||||
* A pointer to this deleter function will be
|
|
||||||
* enrolled for execution at application shutdown
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
destroy_in_place (void* pInstance)
|
|
||||||
{
|
|
||||||
if (!pInstance) return;
|
|
||||||
|
|
||||||
std::cerr << "--dtor-- "<<typeid(TAR).name() <<"\n";
|
|
||||||
static_cast<TAR*> (pInstance) -> ~TAR();
|
|
||||||
ENSURE (0 == --createCnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
_kill_immediately (void* allocatedObject)
|
|
||||||
{
|
|
||||||
destroy_in_place (allocatedObject);
|
|
||||||
const char* errID = lumiera_error();
|
|
||||||
WARN (memory, "Failure in DependencyFactory. Error flag was: %s", errID);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
InstanceHolder()
|
||||||
|
: lifecycle_(0)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
~InstanceHolder()
|
||||||
|
{
|
||||||
|
lifecycle_ |= 4;
|
||||||
|
if (1 & lifecycle_)
|
||||||
|
{
|
||||||
|
std::cerr << "--dtor-- "<<typeid(TAR).name() <<"\n";
|
||||||
|
reinterpret_cast<TAR&> (buff_). ~TAR();
|
||||||
|
--lifecycle_;
|
||||||
|
} }
|
||||||
|
|
||||||
|
|
||||||
TAR*
|
TAR*
|
||||||
buildInstance ()
|
buildInstance ()
|
||||||
{
|
{
|
||||||
|
if (0 < lifecycle_)
|
||||||
|
throw error::Fatal("Attempt to double-create a singleton service. "
|
||||||
|
"Either the application logic, or the compiler "
|
||||||
|
"or runtime system is seriously broken"
|
||||||
|
,error::LUMIERA_ERROR_LIFECYCLE);
|
||||||
|
|
||||||
std::cerr << "++ctor++ "<<typeid(TAR).name() <<"\n";
|
std::cerr << "++ctor++ "<<typeid(TAR).name() <<"\n";
|
||||||
// place new instance into embedded buffer
|
// place new instance into embedded buffer
|
||||||
TAR* newInstance = create_in_buffer<TAR>(buff_);
|
TAR* newInstance = create_in_buffer<TAR>(buff_);
|
||||||
|
++lifecycle_;
|
||||||
ENSURE (0 == createCnt++, "runtime system or compiler broken");
|
return newInstance;
|
||||||
try
|
|
||||||
{
|
|
||||||
scheduleDestruction (newInstance, &destroy_in_place);
|
|
||||||
return newInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (std::exception& problem)
|
|
||||||
{
|
|
||||||
_kill_immediately (newInstance);
|
|
||||||
throw error::State (problem, "Failed to install a deleter function "
|
|
||||||
"for clean-up at application shutdown.");
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
_kill_immediately (newInstance);
|
|
||||||
throw error::State ("Unknown error while installing a deleter function.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -210,7 +185,7 @@ namespace lib {
|
||||||
static void*
|
static void*
|
||||||
createSingletonInstance()
|
createSingletonInstance()
|
||||||
{
|
{
|
||||||
static InstanceHolder<TAR> storage;
|
static InstanceHolder<TAR> storage; // note: the singleton(s) live here
|
||||||
return storage.buildInstance();
|
return storage.buildInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -240,13 +215,5 @@ namespace lib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if NOBUG_MODE_ALPHA
|
|
||||||
/** sanity check to guard against re-entrance while instance is still alive.
|
|
||||||
* This helped us in 2013 to spot a compiler bug. */
|
|
||||||
template<typename TAR>
|
|
||||||
int DependencyFactory::InstanceHolder<TAR>::createCnt;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace lib
|
} // namespace lib
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue