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_();
|
||||
}
|
||||
|
||||
static void scheduleDestruction (void*, KillFun);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -146,61 +143,39 @@ namespace lib {
|
|||
{
|
||||
/** storage for the service instance */
|
||||
char buff_[sizeof(TAR)];
|
||||
|
||||
#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);
|
||||
}
|
||||
uint lifecycle_;
|
||||
|
||||
|
||||
public:
|
||||
InstanceHolder()
|
||||
: lifecycle_(0)
|
||||
{ }
|
||||
|
||||
~InstanceHolder()
|
||||
{
|
||||
lifecycle_ |= 4;
|
||||
if (1 & lifecycle_)
|
||||
{
|
||||
std::cerr << "--dtor-- "<<typeid(TAR).name() <<"\n";
|
||||
reinterpret_cast<TAR&> (buff_). ~TAR();
|
||||
--lifecycle_;
|
||||
} }
|
||||
|
||||
|
||||
TAR*
|
||||
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";
|
||||
// place new instance into embedded buffer
|
||||
TAR* newInstance = create_in_buffer<TAR>(buff_);
|
||||
|
||||
ENSURE (0 == createCnt++, "runtime system or compiler broken");
|
||||
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.");
|
||||
}
|
||||
++lifecycle_;
|
||||
return newInstance;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -210,7 +185,7 @@ namespace lib {
|
|||
static void*
|
||||
createSingletonInstance()
|
||||
{
|
||||
static InstanceHolder<TAR> storage;
|
||||
static InstanceHolder<TAR> storage; // note: the singleton(s) live here
|
||||
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
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue