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:
Fischlurch 2013-10-21 02:42:43 +02:00
parent 52c83b860b
commit 7204c58680
2 changed files with 25 additions and 156 deletions

View file

@ -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

View file

@ -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