diff --git a/src/lib/depend.hpp b/src/lib/depend.hpp index 6fd8fd92b..c628f52f9 100644 --- a/src/lib/depend.hpp +++ b/src/lib/depend.hpp @@ -44,13 +44,15 @@ namespace lib { * Access point to singletons and other kinds of dependencies. * Actually this is a Factory object, which is typically placed into a static field * of the Singleton (target) class or some otherwise suitable interface. - * @note internally uses static fields, so all factory instances share pInstance_ - * @note there is an ongoing discussion regarding Double Checked Locking pattern, - * which in this case boils down to the question: does \c pthread_mutex_lock/unlock - * constitute a memory barrier, such as to force any memory writes done within - * the singleton ctor to be flushed and visible to other threads when releasing - * the lock? To my understanding, the answer is yes. See - * http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap04.html#tag_04_10 + * @note uses static fields internally, so all factory instances share pInstance_ + * @remark there is an ongoing discussion regarding the viability of the + * Double Checked Locking pattern, which requires either the context of a clearly defined + * language memory model (as in Java), or needs to be supplemented by memory barriers. + * In our case, this debate boils down to the question: does \c pthread_mutex_lock/unlock + * constitute a memory barrier, such as to force any memory writes happening \em within + * the singleton ctor to be flushed and visible to other threads when releasing the lock? + * To my understanding, the answer is yes. See + * [posix](http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap04.html#tag_04_10) * @param SI the class of the Singleton instance * @param Create policy defining how to create/destroy the instance * @param Life policy defining how to manage Singleton Lifecycle @@ -58,9 +60,11 @@ namespace lib { template class Depend { - typedef lib::ClassLock ThreadLock; + typedef ClassLock ThreadLock; + typedef DependencyFactory Factory; - static SI* volatile pInstance_; + static SI* volatile instance; + static Factory factory; public: @@ -72,55 +76,59 @@ namespace lib { SI& operator() () { - if (!pInstance_) + if (!instance) { ThreadLock guard; - if (!pInstance_) - { - if (isDead_) - { - Life::onDeadReference(); - isDead_ = false; - } - pInstance_ = Create::create(); - Life::scheduleDelete (&destroy); - } } - ENSURE (pInstance_); - ENSURE (!isDead_); - return *pInstance_; + if (!instance) + instance = factory.buildInstance(); + } + ENSURE (instance); + return *instance; } - private: - /** @internal helper used to delegate destroying the single instance - * to the Create policy, at the same time allowing the Life policy - * to control the point in the Application lifecycle when the - * destruction of this instance occurs. - */ - static void destroy() + void + shutdown() { - REQUIRE (!isDead_); - Create::destroy (pInstance_); - pInstance_ = 0; - isDead_ = true; + ThreadLock guard; + + factory.deconfigure (instance); + instance = NULL; } + + void + injectReplacement (SI* mock) + { + if (mock) + { + factory.takeOwnership (mock); // EX_SANE + + ThreadLock guard; + factory.shaddow (instance); + instance = mock; + } + else + { + factory.discardMock (instance); // EX_FREE + + ThreadLock guard; + instance = factory.restore (); // EX_SANE + } + } + + Depend (); + Depend (typename Factory::Constructor ctor); + + private: }; // Storage for SingletonFactory's static fields... template - SI* volatile Depend::pInstance_; + SI* volatile Depend::instance; -///// Question: can we get rid of the static fields? -///// this is tricky because of invoking the destructors. If we rely on instance vars, -///// the object may already have been released when the runtime system calls the -///// destructors of static objects at shutdown. -///// It seems this would either cost us much of the flexibility or get complicated -///// to a point where we could as well implement our own Dependency Injection Manager. -///// But the whole point of my pervasive use of this singleton template is to remain -///// below this borderline of integration ("IoC yes, but avoid DI"). } // namespace lib #endif diff --git a/tests/library/dependency-factory-test.cpp b/tests/library/dependency-factory-test.cpp index 250b41fc2..ca72d4861 100644 --- a/tests/library/dependency-factory-test.cpp +++ b/tests/library/dependency-factory-test.cpp @@ -87,7 +87,13 @@ namespace test{ virtual void run (Arg) { - UNIMPLEMENTED ("dependency creation"); + verify_defaultSingletonCreation(); + verify_renewal(); + verify_SubclassCreation(); + verify_FactoryDefinition_is_sticky(); + verify_customFactory(); + verify_temporaryReplacement(); + verify_automaticReplacement(); }