draft the creation and lifecycle facilities

This commit is contained in:
Fischlurch 2013-10-19 00:07:06 +02:00
parent 78c7036678
commit ed7f975748
3 changed files with 162 additions and 16 deletions

View file

@ -123,15 +123,14 @@ namespace lib {
}
~DelStash ()
{
try { killAll(); }
catch(...)
{
Symbol errID = lumiera_error();
WARN (memory, "Problems on de-allocation: %s", errID.c());
}
}
try { killAll(); }
catch(...)
{
Symbol errID = lumiera_error();
WARN (memory, "Problems on de-allocation: %s", errID.c());
}
size_t
size () const

View file

@ -74,10 +74,10 @@ namespace lib {
public:
/** Interface to be used by SingletonFactory's clients.
* Manages internally the instance creation, lifecycle
* and access handling in a multithreaded context.
* @return "the" single instance of class S
/** Interface to be used by clients to access the service instance.
* Manages the instance creation, lifecycle and access in multithreaded context.
* @return instance of class SI. When used in default configuration,
* this service instance is a singleton
*/
SI&
operator() ()
@ -94,8 +94,20 @@ namespace lib {
}
typedef DependencyFactory::InstanceConstructor Constructor;
/**
* optionally, the instance creation process can be configured
* \em once per type. By default, a singleton instance will be created.
* Installing another factory function enables other kinds of dependency injection;
* this configuration must be done prior to any use the dependency factory.
* @remark typically the \c Depend<TY> factory will be placed into a static variable,
* embedded into some service interface type. In this case, actual storage
* for this static variable needs to be allocated within some translation unit.
* And this is the point where this ctor will be invoked, in the static
* initialisation phase of the respective translation unit (*.cpp)
*/
Depend (Constructor ctor = buildSingleton<SI>())
{
factory.installConstructorFunction (ctor);
@ -104,8 +116,20 @@ namespace lib {
// standard copy operations applicable
/* === Management / Test support interface === */
/** disable and destroy the actual service instance explicitly.
* Next access will re-invoke the factory to create a new instance.
* @warning this is a very dangerous operation. Concurrent accesses
* might get NULL or even a reference to the old instance,
* which, worse still, resides typically in the same memory
* location as the new instance. The only way to prevent this
* would be to synchronise any \em access (which is expensive)
* Thus it is the client's duty to ensure there is no such
* concurrent access, i.e. all clients of the old instance
* should be disabled prior to invoking this function.
*/
static void
shutdown()
{
@ -115,6 +139,14 @@ namespace lib {
instance = NULL;
}
/** temporarily shadow the service instance with the given replacement.
* The purpose of this operation is to support unit testing.
* @throw error::State in case there is already an installed replacement
* @param mock heap allocated instance of the replacement (mock).
* @warning not threadsafe. Same considerations as for \c shutdown() apply
* @note ownership of mock will be transferred; the mock instance
* will be destroyed automatically when deconfigured.
*/
static void
injectReplacement (SI* mock)
{
@ -135,6 +167,7 @@ namespace lib {
};
// Storage for SingletonFactory's static fields...
template<class SI>
SI* volatile Depend<SI>::instance;

View file

@ -29,26 +29,137 @@
#include "lib/nobug-init.hpp"
#include "lib/error.hpp"
//#include "lib/sync-classlock.hpp"
#include "lib/del-stash.hpp" ////////TODO
namespace lib {
namespace error = lumiera::error;
class AutoDestructor
{
typedef void KillFun(void*);
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, KillFun* customDeleter)
{
__lifecycleCheck();
instance().destructionExecutor_.manage (object, customDeleter);
}
static void
kill (void* object)
{
__lifecycleCheck();
instance().destructionExecutor_.kill (object);
}
};
bool AutoDestructor::shutdownLock = false;
template<typename TAR>
struct InstanceHolder
: boost::noncopyable
{
TAR*
buildInstance ()
{
#if NOBUG_MODE_ALPHA
static uint callCount = 0;
ASSERT ( 0 == callCount++ );
#endif
// place new instance into embedded buffer
TAR* newInstance = new(buff_) TAR;
try
{
AutoDestructor::schedule (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.");
}
}
private:
/** storage for the service instance */
char buff_[sizeof(TAR)];
static void
destroy_in_place (void* pInstance)
{
if (!pInstance) return;
static_cast<TAR*> (pInstance) -> ~TAR();
}
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);
}
};
/**
* Factory to generate and manage service objects classified by type.
*/
class DependencyFactory
{
public:
/** invoke the installed ctor function */
void*
buildInstance()
{
UNIMPLEMENTED("invoke the ctor function");
REQUIRE (ctorFunction_);
return ctorFunction_();
}
void
deconfigure (void* existingInstance)
{
UNIMPLEMENTED("deregister and destroy a managed product");
AutoDestructor::kill (existingInstance);
}
template<class TAR>
@ -85,7 +196,8 @@ namespace lib {
static void*
createSingletonInstance()
{
UNIMPLEMENTED("trampoline function to create a singleton");
static InstanceHolder<TAR> storage;
return storage.buildInstance();
}
@ -96,6 +208,8 @@ namespace lib {
return & createSingletonInstance<TAR>;
}
private:
InstanceConstructor ctorFunction_;
};