From 9f9ef10c1134390871c1ba45d00739069a96b62a Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 28 Dec 2008 02:05:04 +0100 Subject: [PATCH 01/35] add a temporary impl for recursive conditions just for test (can be removed when the implemented in the backend) --- src/lib/sync.hpp | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/lib/sync.hpp b/src/lib/sync.hpp index 347106a3d..ea0496be9 100644 --- a/src/lib/sync.hpp +++ b/src/lib/sync.hpp @@ -106,7 +106,7 @@ namespace lib { : public lumiera_mutex { protected: - Wrapped_LumieraRecMutex() { lumiera_recmutex_init (this, "Obj.Monitor ExclMutex", &NOBUG_FLAG(sync)); } + Wrapped_LumieraRecMutex() { lumiera_recmutex_init (this, "Obj.Monitor RecMutex", &NOBUG_FLAG(sync)); } ~Wrapped_LumieraRecMutex() { lumiera_mutex_destroy (this, &NOBUG_FLAG(sync)); } //------------------Resource-Tracking------ @@ -120,7 +120,7 @@ namespace lib { : public lumiera_condition { protected: - Wrapped_LumieraExcCond() { lumiera_condition_init (this, "Obj.Monitor Condition", &NOBUG_FLAG(sync) ); } + Wrapped_LumieraExcCond() { lumiera_condition_init (this, "Obj.Monitor ExclCondition", &NOBUG_FLAG(sync) ); } ~Wrapped_LumieraExcCond() { lumiera_condition_destroy (this, &NOBUG_FLAG(sync) ); } //------------------Resource-Tracking------ @@ -133,8 +133,41 @@ namespace lib { struct Wrapped_LumieraRecCond : public lumiera_condition //////////////////////////////////////////TODO use correct implementation here! { + + ///////////////////////////////////////////////////////////////////////////////TODO temporary hack until implemented in the backend + static pthread_mutexattr_t* + getMutexAttr() + { + static pthread_mutexattr_t recursive_mutexattr; + return &recursive_mutexattr; + } + + static void + recursive_mutexattr_init() + { + pthread_mutexattr_init (getMutexAttr()); + pthread_mutexattr_settype (getMutexAttr(), PTHREAD_MUTEX_RECURSIVE); + } + + static LumieraCondition + lumiera_reccondition_init (LumieraCondition self, const char* purpose, struct nobug_flag* flag) + { + if (self) + { + static pthread_once_t recursive_mutexattr_once = PTHREAD_ONCE_INIT; + pthread_once(&recursive_mutexattr_once, recursive_mutexattr_init); + pthread_mutex_init (&self->mutex, getMutexAttr()); + + pthread_cond_init (&self->cond, NULL); + NOBUG_RESOURCE_HANDLE_INIT (self->rh); + NOBUG_RESOURCE_ANNOUNCE_RAW (flag, "cond_var", purpose, self, self->rh); + } + return self; + } + ///////////////////////////////////////////////////////////////////////////////TODO temporary hack until implemented in the backend + protected: - Wrapped_LumieraRecCond() { lumiera_condition_init (this, "Obj.Monitor Condition", &NOBUG_FLAG(sync) ); } ////////TODO + Wrapped_LumieraRecCond() { lumiera_reccondition_init (this, "Obj.Monitor RecCondition", &NOBUG_FLAG(sync) ); } ////////TODO ~Wrapped_LumieraRecCond() { lumiera_condition_destroy (this, &NOBUG_FLAG(sync) ); } //------------------Resource-Tracking------ From 00a5e7028d95ae61a4dcc1eb8cee048518af96b6 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 28 Dec 2008 02:05:51 +0100 Subject: [PATCH 02/35] care for copy operations --- src/lib/sync.hpp | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/lib/sync.hpp b/src/lib/sync.hpp index c86883210..ef08e7f83 100644 --- a/src/lib/sync.hpp +++ b/src/lib/sync.hpp @@ -77,9 +77,12 @@ extern "C" { #include "lib/reccondition.h" } +#include +#include #include #include +using boost::noncopyable; namespace lib { @@ -158,6 +161,11 @@ namespace lib { using MTX::__enter; using MTX::__leave; + ~Mutex () { } + Mutex () { } + Mutex (const Mutex&); ///< noncopyable... + const Mutex& operator= (const Mutex&); + public: void acquire() @@ -283,6 +291,8 @@ namespace lib { /** * Object Monitor for synchronisation and waiting. + * Implemented by a (wrapped) set of sync primitives, + * which are default constructible and noncopyable. */ template class Monitor @@ -294,6 +304,11 @@ namespace lib { Monitor() {} ~Monitor() {} + /** allow copy, without interfering with the identity of IMPL */ + Monitor (Monitor const& ref) : IMPL(), timeout_(ref.timeout_) { } + const Monitor& operator= (Monitor const& ref) { timeout_ = ref.timeout_; } + + void acquireLock() { IMPL::acquire(); } void releaseLock() { IMPL::release(); } @@ -371,13 +386,13 @@ namespace lib { public: class Lock + : private noncopyable { Monitor& mon_; public: template Lock(X* it) : mon_(getMonitor(it)){ mon_.acquireLock(); } - Lock(Monitor& m) : mon_(m) { mon_.acquireLock(); } ~Lock() { mon_.releaseLock(); } void notify() { mon_.signal(false);} @@ -386,11 +401,12 @@ namespace lib { template bool wait (C& cond, ulong time=0) { return mon_.wait(cond,time);} + bool isTimedWait() { return mon_.isTimedWait(); } + /** convenience shortcut: * Locks and immediately enters wait state, - * observing a condition defined as member function. - */ + * observing a condition defined as member function. */ template Lock(X* it, bool (X::*method)(void)) : mon_(getMonitor(it)) @@ -398,6 +414,11 @@ namespace lib { mon_.acquireLock(); mon_.wait(*it,method); } + + protected: + /** for creating a ClassLock */ + Lock(Monitor& m) : mon_(m) + { mon_.acquireLock(); } }; From e801c324bfa59fb29cdd92b7a76b55e572049e80 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 28 Dec 2008 02:06:30 +0100 Subject: [PATCH 03/35] add a test to ensure the timed wait feature is working properly --- tests/lib/sync-timedwait-test.cpp | 140 ++++++++++++++++++++++++++++++ tests/lib/visitingtoolconcept.cpp | 2 +- 2 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 tests/lib/sync-timedwait-test.cpp diff --git a/tests/lib/sync-timedwait-test.cpp b/tests/lib/sync-timedwait-test.cpp new file mode 100644 index 000000000..21dc41b0c --- /dev/null +++ b/tests/lib/sync-timedwait-test.cpp @@ -0,0 +1,140 @@ +/* + SyncTimedwait(Test) - check the monitor object based timed condition wait + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + 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. + +* *****************************************************/ + + +#include "lib/test/run.hpp" +#include "lib/error.hpp" + +#include "lib/sync.hpp" + +#include + +using std::cout; +using test::Test; + + +namespace lib { + namespace test { + + namespace { // private test classes and data... + + const uint WAIT_mSec = 200; ///< milliseconds to wait before timeout + + } // (End) test classes and data.... + + + + + + + + + + + /******************************************************************************** + * @test timeout feature on condition wait as provided by pthread and accessible + * via the object monitor based locking/waiting mechanism. Without creating + * multiple threads, we engage into a blocking wait, which aborts due to + * setting a timeout. (Note it is discouraged to use the timed wait feature; + * when possible, you should prefer relying on the Lumiera scheduler) + * + * @see SyncWaiting_test + * @see sync::Timeout + * @see sync.hpp + */ + class SyncTimedwait_test + : public Test, + Sync + { + + friend class Lock; // allows inheriting privately from Sync + + + virtual void + run (Arg) + { + checkTimeoutStruct(); + + Lock block(this, &SyncTimedwait_test::neverHappens); + + cout << "back from LaLaLand, alive and thriving!\n"; + ASSERT (block.isTimedWait()); + } + + + volatile bool + neverHappens() ///< the "condition test" used for waiting.... + { + Lock currentLock(this); // get the Lock recursively + if (!currentLock.isTimedWait()) // right from within the condition test: + currentLock.setTimeout(WAIT_mSec); // switch waiting mode to timed wait and set timeout + + return false; + } + + + + void + checkTimeoutStruct() + { + sync::Timeout tout; + + ASSERT (!tout); + ASSERT (0 == tout.tv_sec); + ASSERT (0 == tout.tv_nsec); + + tout.setOffset (0); + ASSERT (!tout); + ASSERT (0 == tout.tv_sec); + ASSERT (0 == tout.tv_nsec); + + timespec ref; + clock_gettime(CLOCK_REALTIME, &ref); + tout.setOffset (1); + ASSERT (tout); + ASSERT (0 < tout.tv_sec); + ASSERT (ref.tv_sec <= tout.tv_sec); + ASSERT (ref.tv_nsec <= 1000000 + tout.tv_nsec || ref.tv_nsec > 1000000000-100000); + + clock_gettime(CLOCK_REALTIME, &ref); + tout.setOffset (1000); + ASSERT (tout); + if (ref.tv_nsec!=0) // should have gotten an overflow to the seconds part + { + ASSERT (ref.tv_sec <= 2 + tout.tv_sec ); + ASSERT ((ref.tv_nsec + 1000000 * 999) % 1000000000 + <= tout.tv_nsec); + } + } + + }; + + + + /** Register this test class... */ + LAUNCHER (SyncTimedwait_test, "unit common"); + + + + } // namespace test + +} // namespace lumiera diff --git a/tests/lib/visitingtoolconcept.cpp b/tests/lib/visitingtoolconcept.cpp index 94ad6ad98..3d625c1c5 100644 --- a/tests/lib/visitingtoolconcept.cpp +++ b/tests/lib/visitingtoolconcept.cpp @@ -410,7 +410,7 @@ namespace lumiera */ class VisitingTool_concept : public Test { - virtual void run(Arg arg) + virtual void run(Arg) { known_visitor_known_class(); visitor_not_visiting_some_class(); From 75bdc877dcff1066859e8e6d4333e71c018f5773 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 28 Dec 2008 05:20:35 +0100 Subject: [PATCH 04/35] reconsider synchronisation and switch some parts to instance based locks. --- src/common/guifacade.cpp | 11 +++--- src/common/subsys.cpp | 9 ----- src/common/subsys.hpp | 1 + src/common/subsystemrunner.hpp | 42 ++++++++++++++++------- src/lib/allocationcluster.cpp | 22 ++++++------ src/lib/allocationcluster.hpp | 6 ++++ src/lib/singletonpolicies.hpp | 2 +- src/lib/visitordispatcher.hpp | 4 ++- src/proc/mobject/session/defsregistry.hpp | 22 ++++++------ 9 files changed, 70 insertions(+), 49 deletions(-) diff --git a/src/common/guifacade.cpp b/src/common/guifacade.cpp index 39404fce5..6efdfb9f3 100644 --- a/src/common/guifacade.cpp +++ b/src/common/guifacade.cpp @@ -23,6 +23,7 @@ #include "gui/guifacade.hpp" #include "include/guinotificationfacade.h" +#include "lib/sync.hpp" #include "lib/error.hpp" #include "lib/singleton.hpp" #include "lib/functorutil.hpp" @@ -42,6 +43,7 @@ namespace gui { using lumiera::Subsys; using lumiera::InstanceHandle; using util::dispatchSequenced; + using lib::Sync; @@ -79,7 +81,8 @@ namespace gui { scoped_ptr facade (0); class GuiSubsysDescriptor - : public lumiera::Subsys + : public lumiera::Subsys, + public Sync<> { operator string () const { return "Lumiera GTK GUI"; } @@ -98,7 +101,7 @@ namespace gui { bool start (lumiera::Option&, Subsys::SigTerm termination) { - //Lock guard (*this); + Lock guard (this); if (facade) return false; // already started facade.reset ( @@ -119,14 +122,14 @@ namespace gui { bool checkRunningState () throw() { - //Lock guard (*this); + Lock guard (this); return (facade); } void closeGuiModule (lumiera::Error *) { - //Lock guard (*this); + Lock guard (this); if (!facade) { WARN (operate, "Termination signal invoked, but GUI is currently closed. " diff --git a/src/common/subsys.cpp b/src/common/subsys.cpp index 2becff32b..68850f4c8 100644 --- a/src/common/subsys.cpp +++ b/src/common/subsys.cpp @@ -23,19 +23,12 @@ #include "common/subsys.hpp" -#include "lib/error.hpp" -//#include "lib/util.hpp" - - -//using util::isnil; -//using util::cStr; namespace lumiera { - Subsys::~Subsys() { } @@ -43,7 +36,6 @@ namespace lumiera { Subsys& Subsys::depends (Subsys& prereq) { - TODO ("anything else to care when defining a dependency on the prerequisite subsystem??");/////////////////////TODO prereq_.push_back(&prereq); return *this; } @@ -53,7 +45,6 @@ namespace lumiera { bool Subsys::isRunning() { - //Lock guard (this); return checkRunningState(); } diff --git a/src/common/subsys.hpp b/src/common/subsys.hpp index 4808f134b..e59d2db28 100644 --- a/src/common/subsys.hpp +++ b/src/common/subsys.hpp @@ -65,6 +65,7 @@ namespace lumiera { * Dependencies and lifecycle of a partially independent Subsystem of the Application. * Using such descriptors, AppState as activated from main() is able to pull up, * maintain and shut down the primary parts of the Application. + * @note synchronisation is up to the implementor. */ class Subsys : private noncopyable diff --git a/src/common/subsystemrunner.hpp b/src/common/subsystemrunner.hpp index 363b4c8cc..7c6762694 100644 --- a/src/common/subsystemrunner.hpp +++ b/src/common/subsystemrunner.hpp @@ -44,8 +44,16 @@ namespace lumiera { using util::and_all; using util::for_each; using util::removeall; + using lib::Sync; + using lib::RecursiveLock_Waitable; namespace { + + /** limit waiting for subsystem shutdown in case of + * an emergency shutdown to max 2 seconds */ + const uint EMERGENCYTIMEOUT = 2000; + + function isRunning() { return bind (&Subsys::isRunning, _1); @@ -76,10 +84,9 @@ namespace lumiera { * Usually, the startup process is conducted from one (main) thread, which enters * a blocking wait() after starting the subsystems. Awakened by some termination * signal from one of the subsystems, termination of any remaining subsystems - * will be triggered. The wait() function returns after shutdown of all subsystems, + * will be triggered. The #wait() function returns after shutdown of all subsystems, * signalling an emergency exit (caused by an exception) with its return value. * - * @todo implement an object monitor primitive based on a mutex and a condition. Inherit from this privately and create local instances of the embedded Lock class to activate the locking and wait/notify * @todo maybe use my refArray (see builder) to use Subsys& instead of Subsys* ?? * * @see lumiera::AppState @@ -87,7 +94,7 @@ namespace lumiera { * @see main.cpp */ class SubsystemRunner -// : Sync + : public Sync { Option& opts_; volatile bool emergency_; @@ -109,7 +116,7 @@ namespace lumiera { void maybeRun (Subsys& susy) { - //Lock guard (this); + Lock guard (this); if (!susy.isRunning() && susy.shouldStart (opts_)) triggerStartup (&susy); @@ -120,23 +127,28 @@ namespace lumiera { void shutdownAll () { - //Lock guard (this); + Lock guard (this); for_each (running_, killIt_); } + void + triggerEmergency (bool cond) + { + Lock guard (this); + emergency_ |= cond; + } + bool wait () { - //Lock(this).wait (&SubsystemRunner::allDead); + Lock wait_blocking(this, &SubsystemRunner::allDead); return isEmergencyExit(); } - bool isEmergencyExit () { return emergency_; } - void triggerEmergency (bool cond) { emergency_ |= cond; } - private: + bool isEmergencyExit () { return emergency_; } void triggerStartup (Subsys* susy) @@ -161,20 +173,24 @@ namespace lumiera { sigTerm (Subsys* susy, Error* problem) ///< called from subsystem on termination { ASSERT (susy); - //Lock guard (this); + Lock sync (this); triggerEmergency(problem); ERROR_IF (susy->isRunning(), lumiera, "Subsystem '%s' signals termination, " "without resetting running state", cStr(*susy)); removeall (running_, susy); shutdownAll(); - //guard.notify(); + sync.notify(); } - bool + volatile bool allDead () { if (isEmergencyExit()) - ; //Lock(this).setTimeout(EMERGENCYTIMEOUT); + { + Lock sync(this); + if (!sync.isTimedWait()) + sync.setTimeout(EMERGENCYTIMEOUT); + } return isnil (running_); // end wait if no running subsystem left } diff --git a/src/lib/allocationcluster.cpp b/src/lib/allocationcluster.cpp index f60fd56a8..1e210d80d 100644 --- a/src/lib/allocationcluster.cpp +++ b/src/lib/allocationcluster.cpp @@ -24,6 +24,7 @@ #include "lib/allocationcluster.hpp" #include "lib/error.hpp" #include "lib/util.hpp" +#include "lib/sync.hpp" using util::isnil; @@ -38,9 +39,9 @@ namespace lib { * successful ctor call of the object being allocated. Allocations and commits * can be assumed to come in pairs, thus if an allocation immediately follows * another one (without commit), the previous allocation can be considered - * a failure and can be dropped silently. After an allocation has succeeds + * a failure and can be dropped silently. After an allocation succeeds * (i.e. was committed), the MemoryManager is in charge for the lifecycle - * of the object within the allocated spaces and has to guarantee calling + * of the object within the allocated space and has to guarantee calling * it's dtor, either on shutdown or on explicit #purge() -- the type info * structure handed in on initialisation provides a means for invoking * the dtor without actually knowing the object's type. @@ -55,6 +56,7 @@ namespace lib { * on real-world measurements, not guessing. */ class AllocationCluster::MemoryManager + : public Sync { typedef std::vector MemTable; TypeInfo type_; @@ -81,7 +83,7 @@ namespace lib { void AllocationCluster::MemoryManager::reset (TypeInfo info) { - ClassLock guard(); + Lock instance(); if (0 < mem_.size()) purge(); type_ = info; @@ -96,7 +98,7 @@ namespace lib { void AllocationCluster::MemoryManager::purge() { - ClassLock guard(); + Lock instance(); REQUIRE (type_.killIt, "we need a deleter function"); REQUIRE (0 < type_.allocSize, "allocation size unknown"); @@ -120,7 +122,7 @@ namespace lib { inline void* AllocationCluster::MemoryManager::allocate() { - ClassLock guard(); + Lock instance(); REQUIRE (0 < type_.allocSize); REQUIRE (top_ <= mem_.size()); @@ -140,7 +142,7 @@ namespace lib { inline void AllocationCluster::MemoryManager::commit (void* pendingAlloc) { - ClassLock guard(); + Lock instance(); REQUIRE (pendingAlloc); ASSERT (top_ < mem_.size()); @@ -174,8 +176,8 @@ namespace lib { AllocationCluster::~AllocationCluster() throw() { try - { - ClassLock guard(); + { // avoiding a per-instance lock for now. + ClassLock guard(); // (see note in the class description) TRACE (memory, "shutting down AllocationCluster"); for (size_t i = typeHandlers_.size(); 0 < i; --i) @@ -213,8 +215,8 @@ namespace lib { { ASSERT (0 < slot); - { - ClassLock guard(); /////TODO: decide tradeoff: lock just the instance, or lock the AllocationCluster class? + { // avoiding a per-instance lock for now. + ClassLock guard(); // (see note in the class description) if (slot > typeHandlers_.size()) typeHandlers_.resize(slot); diff --git a/src/lib/allocationcluster.hpp b/src/lib/allocationcluster.hpp index 8b639199c..a9593316e 100644 --- a/src/lib/allocationcluster.hpp +++ b/src/lib/allocationcluster.hpp @@ -76,6 +76,12 @@ namespace lib { * the object families are to be discarded. Currently * they are just purged in reverse order defined by * the first request for allocating a certain type. + * @todo should we use an per-instance lock? We can't avoid + * the class-wide lock, unless also the type-ID registration + * is done on a per-instance base. AllocationCluster is intended + * to be used within the builder, which executes in a dedicated + * thread. Thus I doubt lock contention could be a problem and + * we can avoid using a mutex per instance. Re-evaluate this! */ class AllocationCluster : boost::noncopyable diff --git a/src/lib/singletonpolicies.hpp b/src/lib/singletonpolicies.hpp index ba63d4a99..ef2342c17 100644 --- a/src/lib/singletonpolicies.hpp +++ b/src/lib/singletonpolicies.hpp @@ -133,7 +133,7 @@ namespace lumiera { /** * Policy for handling multithreaded access to the singleton instance - * @todo actually implement this policy using the Lumiera databackend. + * @todo we could consider using a single shared lock for all singleton types... */ template struct Multithreaded diff --git a/src/lib/visitordispatcher.hpp b/src/lib/visitordispatcher.hpp index 37bee9007..0eae85168 100644 --- a/src/lib/visitordispatcher.hpp +++ b/src/lib/visitordispatcher.hpp @@ -105,6 +105,8 @@ namespace lumiera { * For each possible call entry point via some subclass of the visitable hierarchy, * we maintain a dispatcher table to keep track of all concrete tool implementations * able to receive and process calls on objects of this subclass. + * @param TAR the concrete target (subclass) type within the visitable hierarchy + * @param TOOL the overall tool family (base class of all concrete tools) */ template class Dispatcher @@ -140,7 +142,7 @@ namespace lumiera { void accomodate (size_t index) { - ClassLock guard(); + ClassLock guard(); // note: this lock is also used for the singleton! if (index > table_.size()) table_.resize (index); // performance bottleneck?? TODO: measure the real impact! } diff --git a/src/proc/mobject/session/defsregistry.hpp b/src/proc/mobject/session/defsregistry.hpp index 06133b292..3fbd4aa1f 100644 --- a/src/proc/mobject/session/defsregistry.hpp +++ b/src/proc/mobject/session/defsregistry.hpp @@ -25,7 +25,7 @@ ** A piece of implementation code factored out into a separate header (include). ** Only used in defsmanager.cpp and for the unit tests. We can't place it into ** a separate compilation unit, because defsmanager.cpp defines some explicit - ** template instantiaton, which cause the different Slots of the DefsrRegistry#table_ + ** template instantiation, which cause the different Slots of the DefsrRegistry#table_ ** to be filled with data and defaults for the specific Types. ** ** @see mobject::session::DefsManager @@ -80,7 +80,7 @@ namespace mobject { }; /** we maintain an independent defaults registry - * for every participating kind of objects */ + * for every participating kind of object. */ typedef std::vector< P > Table; @@ -180,8 +180,8 @@ namespace mobject { /** - * @internal Helper for organizing preconfigured default objects. - * Maintaines a collection of objects known or encountered as "default" + * @internal Helper for organising preconfigured default objects. + * Maintains a collection of objects known or encountered as "default" * for a given type. This collection is ordered by "degree of constriction", * which is implemented by counting the number of predicates in the query * used to define or identify each object. @@ -206,17 +206,17 @@ namespace mobject { II p,i,e; P next, ptr; - Iter (II from, II to) ///< just ennumerates the given range + Iter (II from, II to) ///< just enumerates the given range : p(from), i(from), e(to) { if (i!=e) ++i; // p is next to be tested, i always one ahead operator++ (); } - Iter (II match, II from, II to) ///< returns direct match first, then ennumerates + Iter (II match, II from, II to) ///< returns direct match first, then enumerates : p(match), i(from), e(to) { - operator++ (); // init to first element (or to null if emty) + operator++ (); // init to first element (or to null if empty) } P findNext () throw() @@ -233,7 +233,7 @@ namespace mobject { public: P operator* () { return ptr; } - bool hasNext () { return next || findNext(); } + bool hasNext () { return next || findNext(); } Iter operator++ (int) { Iter tmp=*this; operator++(); return tmp; } Iter& operator++ () { @@ -243,12 +243,12 @@ namespace mobject { } }; - /** find a sequence of "default" objects possibliy matching the query. + /** find a sequence of "default" objects possibly matching the query. * If there was a registration for some object of the given kind with * the \em same query, this one will be first in the sequence. Besides, * the sequence will yield all still existing registered "default" objects * of this kind, ordered ascending by "degree of constriction", i.e. starting - * with the object registered togehter with the shortest query. + * with the object registered together with the shortest query. * @return a forward input iterator yielding this sequence * @note none of the queries will be evaluated (we're just counting predicates) */ @@ -265,7 +265,7 @@ namespace mobject { typename Registry::iterator end = registry.end(); if (pos==end) - return Iter (registry.begin(), end); // just ennumerate contents + return Iter (registry.begin(), end); // just enumerate contents else return Iter (pos, registry.begin(), end); // start with direct match } From 7a2bbefb1d95209a0e446ba118678334af22c091 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 28 Dec 2008 05:36:37 +0100 Subject: [PATCH 05/35] typos --- src/proc/asset/struct.cpp | 4 +-- src/proc/mobject/session/defsmanager.hpp | 8 +++--- tests/40components.tests | 36 ++++++++++++------------ tests/42query.tests | 2 +- tests/lib/exceptionerrortest.cpp | 12 ++++---- tests/lib/query/queryutilstest.cpp | 26 ++++++++--------- tests/lib/testtargetobj.hpp | 4 +-- 7 files changed, 45 insertions(+), 47 deletions(-) diff --git a/src/proc/asset/struct.cpp b/src/proc/asset/struct.cpp index 1aecc48d1..71ffa995f 100644 --- a/src/proc/asset/struct.cpp +++ b/src/proc/asset/struct.cpp @@ -83,7 +83,7 @@ namespace asset /** Factory method for Structural Asset instances. * First tries to relove the asset by issuing an capability query. - * If unsuccessfull, use some internally specialized ctor call. + * If unsuccessful, use some internally specialised ctor call. * @todo work out the struct asset naming scheme! * @return an Struct smart ptr linked to the internally registered smart ptr * created as a side effect of calling the concrete Struct subclass ctor. @@ -109,7 +109,7 @@ namespace asset /** Factory method for creating Pipes explicitly. - * Normalizes pipe- and streamID, then retrieves the + * Normalises pipe- and streamID, then retrieves the * default processing pattern (ProcPatt) for this streamID. * The Pipe ctor will fill out the shortDesc and longDesc * automatically, based on pipeID and streamID (and they diff --git a/src/proc/mobject/session/defsmanager.hpp b/src/proc/mobject/session/defsmanager.hpp index 0a0a25aa8..a223a17e8 100644 --- a/src/proc/mobject/session/defsmanager.hpp +++ b/src/proc/mobject/session/defsmanager.hpp @@ -44,8 +44,8 @@ namespace mobject { /** - * Organize a collection of preconfigured default objects. - * For various kinds of objects we can tweek the default parametrisation + * Organise a collection of preconfigured default objects. + * For various kinds of objects we can tweak the default parametrisation * as part of the general session configuration. A ref to an instance of * this class is accessible through the current session and can be used * to fill in parts of the configuration of new objects, if the user @@ -88,10 +88,10 @@ namespace mobject { template P create (const lumiera::Query&); - /** register the given object as default, after ensuring it fulfills the + /** register the given object as default, after ensuring it fulfils the * query. The latter may cause some properties of the object to be set, * trigger creation of additional objects, and may fail altogether. - * @return true if query was successfull and object is registered as default + * @return true if query was successful and object is registered as default * @note only a weak ref to the object is stored */ template diff --git a/tests/40components.tests b/tests/40components.tests index ca079d7ef..a9bcad005 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -180,38 +180,38 @@ END TEST "Factory_test" Factory_test 5 <(i); - cout << format("ctor TargetObj(%i) successfull\n") % cnt_; + cout << format("ctor TargetObj(%i) successful\n") % cnt_; } @@ -82,7 +82,7 @@ namespace lumiera { delete heapData_; delete[] heapArray_; - cout << format("dtor ~TargetObj(%i) successfull\n") % cnt_; + cout << format("dtor ~TargetObj(%i) successful\n") % cnt_; } From 4b3d567ca00792890b67a8de35bf1b3398928cae Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 29 Dec 2008 05:18:22 +0100 Subject: [PATCH 06/35] Switch Singleton template to use the threadsafe version (Fix) --- src/lib/singleton.hpp | 2 +- src/lib/singletonfactory.hpp | 51 ++++++++++++++++++------------- src/lib/singletonpolicies.hpp | 35 +++++---------------- src/lib/singletonpreconfigure.hpp | 4 +-- src/lib/singletonsubclass.hpp | 6 ++-- src/lib/test/mockinjector.hpp | 9 +++--- 6 files changed, 45 insertions(+), 62 deletions(-) diff --git a/src/lib/singleton.hpp b/src/lib/singleton.hpp index fc5a99de4..20fa5332c 100644 --- a/src/lib/singleton.hpp +++ b/src/lib/singleton.hpp @@ -25,7 +25,7 @@ ** This configuration header just pulls in some other implementation headers in ** the right order. The basic class template for creating singletons resides in ** singletonfactory.hpp, besides we need policy classes defining how to create - ** the singleton objects, how to manage lifecycle and multithreading. Finally, + ** the singleton objects and how to manage singleton lifecycle. Finally, ** we want to preconfigure singleton factories for some important facilities; ** e.g. sometimes we want to include a hook for injecting Test Mock instances. ** diff --git a/src/lib/singletonfactory.hpp b/src/lib/singletonfactory.hpp index 853d18fcd..abd8a5bbf 100644 --- a/src/lib/singletonfactory.hpp +++ b/src/lib/singletonfactory.hpp @@ -37,31 +37,40 @@ This code is heavily inspired by #include "lib/singletonpolicies.hpp" // several Policies usable together with SingletonFactory -#include "lib/util.hpp" #include "include/nobugcfg.h" +#include "lib/util.hpp" +#include "lib/sync-classlock.hpp" -namespace lumiera - { +namespace lumiera { /** * A configurable Template for implementing Singletons. - * Actually this is a Functor object, which could be placed into a static field + * Actually this is a Factory object, which could be placed into a static field * of the Singleton (target) class or used directly. - * @note internally uses static fields, so all functor instances share pInstance_ + * @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 + * @param SI the class of the Singleton instance + * @param Create policy defining how to create/destroy the instance + * @oaram Life policy defining how to manage Singleton Lifecycle */ template - < class SI // the class of the Singleton instance - , template class Create = singleton::StaticCreate // how to create/destroy the instance - , template class Life = singleton::AutoDestroy // how to manage Singleton Lifecycle - , template class Threading = singleton::IgnoreThreadsafety //TODO use Multithreaded!!! + < class SI + , template class Create = singleton::StaticCreate + , template class Life = singleton::AutoDestroy > class SingletonFactory { - typedef typename Threading::VolatileType SType; - typedef typename Threading::Lock ThreadLock; - static SType* pInstance_; + typedef SI* volatile PType; + typedef lib::ClassLock ThreadLock; + + static PType pInstance_; static bool isDead_; public: @@ -110,21 +119,19 @@ namespace lumiera template < class SI, template class C, - template class L, - template class T + template class L > - typename SingletonFactory::SType* - SingletonFactory::pInstance_; + typename SingletonFactory::PType + SingletonFactory::pInstance_; template < class SI, template class C, - template class L, - template class T + template class L > - bool SingletonFactory::isDead_; - - + bool SingletonFactory::isDead_; + + ///// TODO: get rid of the static fields? ///// is tricky because of invoking the destructors. If we rely on instance vars, @@ -132,6 +139,6 @@ namespace lumiera ///// 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. - + } // namespace lumiera #endif diff --git a/src/lib/singletonpolicies.hpp b/src/lib/singletonpolicies.hpp index ef2342c17..cfc21c67a 100644 --- a/src/lib/singletonpolicies.hpp +++ b/src/lib/singletonpolicies.hpp @@ -35,7 +35,6 @@ This code is heavily inspired by #define LUMIERA_SINGLETONPOLICIES_H #include "lib/error.hpp" -#include "lib/sync-classlock.hpp" #include @@ -84,7 +83,7 @@ namespace lumiera { typedef void (*DelFunc)(void); using std::vector; - + /** * Policy relying on the compiler/runtime system for Singleton Lifecycle */ @@ -98,7 +97,8 @@ namespace lumiera { * several Singletons, we need to memorise all registered * deleter functions for calling them at shutdown. */ - static void scheduleDelete (DelFunc kill_the_singleton) + static void + scheduleDelete (DelFunc kill_the_singleton) { class DeleteTrigger { @@ -122,36 +122,15 @@ namespace lumiera { finally.schedule (kill_the_singleton); } - static void onDeadReference () + static void + onDeadReference () { throw error::Logic ("Trying to access the a Singleton instance that has " "already been released or finished its lifecycle."); } }; - - - - /** - * Policy for handling multithreaded access to the singleton instance - * @todo we could consider using a single shared lock for all singleton types... - */ - template - struct Multithreaded - { - typedef volatile S VolatileType; - typedef lib::ClassLock Lock; - }; - - - /** - * Policy just ignoring thread safety - */ - template - struct IgnoreThreadsafety - { - typedef S VolatileType; - struct Lock {}; - }; + + } // namespace singleton diff --git a/src/lib/singletonpreconfigure.hpp b/src/lib/singletonpreconfigure.hpp index 4884509a0..a95295a7b 100644 --- a/src/lib/singletonpreconfigure.hpp +++ b/src/lib/singletonpreconfigure.hpp @@ -64,8 +64,8 @@ namespace lumiera /* Forward declarations of all Classes we want to specialise the template */ /* ********************************************************************** */ - namespace test - { + namespace test { + class TestSingletonO; using lumiera::Singleton; diff --git a/src/lib/singletonsubclass.hpp b/src/lib/singletonsubclass.hpp index 2cf9ce32f..b5ce47184 100644 --- a/src/lib/singletonsubclass.hpp +++ b/src/lib/singletonsubclass.hpp @@ -50,8 +50,8 @@ namespace lumiera { using boost::scoped_ptr; - namespace singleton - { + namespace singleton { + /** * Helper template to use the general policy classes of the lumiera::Singleton, * but change the way they are parametrised on-the-fly. @@ -123,13 +123,11 @@ namespace lumiera { < class SI // the class to use as Interface for the Singleton , template class Create = singleton::StaticCreate // how to create/destroy the instance , template class Life = singleton::AutoDestroy // how to manage Singleton Lifecycle - , template class Threading = singleton::IgnoreThreadsafety //TODO use Multithreaded!!! > class SingletonSubclassFactory : public SingletonFactory< SI , singleton::Adapter::template Adapted , Life - , Threading > { public: diff --git a/src/lib/test/mockinjector.hpp b/src/lib/test/mockinjector.hpp index 0941e271b..b778f4b0c 100644 --- a/src/lib/test/mockinjector.hpp +++ b/src/lib/test/mockinjector.hpp @@ -31,15 +31,14 @@ #include -namespace lumiera - { - namespace test - { +namespace lumiera { + namespace test { + using boost::scoped_ptr; /** * Special SingletonFactory allowing to inject some instance of the Singleton - * class, thus shaddowing "the" (default) Singleton instance temporarily. + * class, thus shadowing "the" (default) Singleton instance temporarily. * This allows installing a Mock Subclass of the Singleton for running tests, * while the Singleton can be used as usual in production code. * @note we use the default policies or SingletonFactory From 71aa88df62fe652c81afba49a46e4d97e347a127 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 29 Dec 2008 06:07:28 +0100 Subject: [PATCH 07/35] add some error checking makes the dummy Gui plugin "work" again, but now with enabled locking. --- src/common/guifacade.cpp | 3 ++- src/common/instancehandle.hpp | 16 ++++++++++++++-- src/gui/guistart.cpp | 2 +- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/common/guifacade.cpp b/src/common/guifacade.cpp index 6efdfb9f3..c95e069a1 100644 --- a/src/common/guifacade.cpp +++ b/src/common/guifacade.cpp @@ -44,6 +44,7 @@ namespace gui { using lumiera::InstanceHandle; using util::dispatchSequenced; using lib::Sync; + using lib::RecursiveLock_NoWait; @@ -82,7 +83,7 @@ namespace gui { class GuiSubsysDescriptor : public lumiera::Subsys, - public Sync<> + public Sync { operator string () const { return "Lumiera GTK GUI"; } diff --git a/src/common/instancehandle.hpp b/src/common/instancehandle.hpp index 26dd084be..78a46cbce 100644 --- a/src/common/instancehandle.hpp +++ b/src/common/instancehandle.hpp @@ -58,6 +58,13 @@ namespace lumiera { // using boost::scoped_ptr; namespace { // implementation details + + void + throwIfError() + { + if (lumiera_error_peek()) + throw lumiera::error::Config("failed to open interface or plugin.",lumiera_error()); + } /** takes a bunch of instance definitions, as typically created * when defining interfaces for external use, and registers them @@ -69,6 +76,7 @@ namespace lumiera { { if (!descriptors) return NULL; lumiera_interfaceregistry_bulkregister_interfaces (descriptors, NULL); + throwIfError(); LumieraInterface masterI = descriptors[0]; return lumiera_interface_open (masterI->interface, masterI->version, @@ -122,7 +130,9 @@ namespace lumiera { : desc_(0), instance_(reinterpret_cast (lumiera_interface_open (iName.c_str(), version, minminor, impName.c_str()))) - { } + { + throwIfError(); + } /** Set up an InstanceHandle managing the * registration and deregistration of interface(s). @@ -133,7 +143,9 @@ namespace lumiera { InstanceHandle (LumieraInterface* descriptors) : desc_(descriptors), instance_(reinterpret_cast (register_and_open (desc_))) - { } + { + throwIfError(); + } ~InstanceHandle () { diff --git a/src/gui/guistart.cpp b/src/gui/guistart.cpp index 6060073ac..360cba90f 100644 --- a/src/gui/guistart.cpp +++ b/src/gui/guistart.cpp @@ -83,7 +83,7 @@ namespace gui { << " but actually nothing happens!!!!!!!!!!!!!!\n\n"; terminationHandle(0); // signal immediate shutdown without error - return true; + return false; } }; From 5114d09156135297bfc29c8c84e56174c0554a13 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 30 Dec 2008 08:35:26 +0100 Subject: [PATCH 08/35] fix after merge/rebase --- src/common/subsystemrunner.hpp | 2 +- tests/lib/sync-timedwait-test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/subsystemrunner.hpp b/src/common/subsystemrunner.hpp index 7c6762694..c883ed9b9 100644 --- a/src/common/subsystemrunner.hpp +++ b/src/common/subsystemrunner.hpp @@ -182,7 +182,7 @@ namespace lumiera { sync.notify(); } - volatile bool + bool allDead () { if (isEmergencyExit()) diff --git a/tests/lib/sync-timedwait-test.cpp b/tests/lib/sync-timedwait-test.cpp index 21dc41b0c..cd0f279cf 100644 --- a/tests/lib/sync-timedwait-test.cpp +++ b/tests/lib/sync-timedwait-test.cpp @@ -81,7 +81,7 @@ namespace lib { } - volatile bool + bool neverHappens() ///< the "condition test" used for waiting.... { Lock currentLock(this); // get the Lock recursively From 8c892846e1e33092f30537f912ca3c4ec1a6cd56 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 31 Dec 2008 05:05:34 +0100 Subject: [PATCH 09/35] renaming etc... --- src/common/appstate.cpp | 2 +- ...subsystemrunner.hpp => subsystem-runner.hpp} | 2 +- src/include/symbol.hpp | 7 +++++-- src/lib/query.cpp | 17 +++++++---------- tests/lib/sync-classlock-test.cpp | 2 +- tests/lib/sync-locking-test.cpp | 2 +- tests/lib/sync-timedwait-test.cpp | 2 +- tests/lib/sync-waiting-test.cpp | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) rename src/common/{subsystemrunner.hpp => subsystem-runner.hpp} (99%) diff --git a/src/common/appstate.cpp b/src/common/appstate.cpp index ce1e8f2a3..6d5d009f0 100644 --- a/src/common/appstate.cpp +++ b/src/common/appstate.cpp @@ -25,7 +25,7 @@ #include "include/lifecycle.h" #include "common/appstate.hpp" #include "lib/lifecycleregistry.hpp" -#include "common/subsystemrunner.hpp" +#include "common/subsystem-runner.hpp" extern "C" { #include "common/config_interface.h" diff --git a/src/common/subsystemrunner.hpp b/src/common/subsystem-runner.hpp similarity index 99% rename from src/common/subsystemrunner.hpp rename to src/common/subsystem-runner.hpp index c883ed9b9..5ebdc1f0d 100644 --- a/src/common/subsystemrunner.hpp +++ b/src/common/subsystem-runner.hpp @@ -1,5 +1,5 @@ /* - SUBSYSTEMRUNNER.hpp - helper for controlling execution of several dependant subsystems + SUBSYSTEMRUNNER.hpp - helper for controlling execution of several dependent subsystems Copyright (C) Lumiera.org 2008, Hermann Vosseler diff --git a/src/include/symbol.hpp b/src/include/symbol.hpp index b2b526e6a..5de94a2cd 100644 --- a/src/include/symbol.hpp +++ b/src/include/symbol.hpp @@ -23,7 +23,7 @@ /** @file symbol.hpp ** WIP placeholder definition for a planned Symbol datatype. ** - ** @todo the (currently just planned as of 11/08) rules based configuration + ** @todo for the (currently just planned as of 11/08) rules based configuration ** in the Proc-Layer a explicit Symbol datatype will probably very helpful. ** For now we just a typedef is sufficient. A real Symbol datatype should ** - be definable by string constant @@ -41,11 +41,14 @@ #define LUMIERA_SYMBOL_H +#include namespace lumiera { - typedef const char * const Symbol; //TODO define a real Symbol class, i.e. same literal string==same pointer, + typedef const char * const Symbol; ///< Token or Atom with distinct identity @todo define a real Symbol class, i.e. same literal string==same pointer, + + typedef const std::string Literal; ///< inline string literal @todo improve interaction with Symbol diff --git a/src/lib/query.cpp b/src/lib/query.cpp index 522ece750..5dcc8e4ab 100644 --- a/src/lib/query.cpp +++ b/src/lib/query.cpp @@ -39,14 +39,11 @@ using util::contains; using util::isnil; -namespace lumiera - { - - namespace query - { - - namespace // local definitions - { +namespace lumiera { + namespace query { + + namespace { // local definitions + typedef boost::function ChPredicate; ChPredicate is_alpha = boost::algorithm::is_alpha(); @@ -92,8 +89,8 @@ namespace lumiera /** (preliminary) helper: instead of really parsing and evaluating the terms, * just do a regular expression match to extract the literal argument * behind the given predicate symbol. e.g calling - * queryID ("stream", "id(abc), stream(mpeg)") - * yields "mpeg" + * \code extractID ("stream", "id(abc), stream(mpeg)") \endcode + * yields \c "mpeg" */ const string extractID (Symbol sym, const string& termString) diff --git a/tests/lib/sync-classlock-test.cpp b/tests/lib/sync-classlock-test.cpp index 74e074451..81ad457d1 100644 --- a/tests/lib/sync-classlock-test.cpp +++ b/tests/lib/sync-classlock-test.cpp @@ -95,4 +95,4 @@ namespace lib { } // namespace test -} // namespace lumiera +} // namespace lib diff --git a/tests/lib/sync-locking-test.cpp b/tests/lib/sync-locking-test.cpp index 2afc03592..33651ebc9 100644 --- a/tests/lib/sync-locking-test.cpp +++ b/tests/lib/sync-locking-test.cpp @@ -206,4 +206,4 @@ namespace lib { } // namespace test -} // namespace lumiera +} // namespace lib diff --git a/tests/lib/sync-timedwait-test.cpp b/tests/lib/sync-timedwait-test.cpp index cd0f279cf..a9dcea3b1 100644 --- a/tests/lib/sync-timedwait-test.cpp +++ b/tests/lib/sync-timedwait-test.cpp @@ -137,4 +137,4 @@ namespace lib { } // namespace test -} // namespace lumiera +} // namespace lib diff --git a/tests/lib/sync-waiting-test.cpp b/tests/lib/sync-waiting-test.cpp index 2c6a280fb..5e54262e4 100644 --- a/tests/lib/sync-waiting-test.cpp +++ b/tests/lib/sync-waiting-test.cpp @@ -185,4 +185,4 @@ namespace lib { } // namespace test -} // namespace lumiera +} // namespace lib From 41d5ee097300cfb8778d7274913f286ff84596c3 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 31 Dec 2008 05:06:17 +0100 Subject: [PATCH 10/35] a "mock subsystem" for testing the subsystemrunner --- tests/lib/subsystem-runner-test.cpp | 228 ++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 tests/lib/subsystem-runner-test.cpp diff --git a/tests/lib/subsystem-runner-test.cpp b/tests/lib/subsystem-runner-test.cpp new file mode 100644 index 000000000..fb9564eaa --- /dev/null +++ b/tests/lib/subsystem-runner-test.cpp @@ -0,0 +1,228 @@ +/* + SubsystemRunner(Test) - validate starting and stopping of dependent subsystems + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + 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. + +* *****************************************************/ + + +#include "lib/test/run.hpp" +#include "common/subsys.hpp" +#include "common/subsystem-runner.hpp" + +#include "include/symbol.hpp" +#include "lib/error.hpp" +#include "lib/query.hpp" +#include "lib/util.hpp" + +#include +#include + +using std::cout; +using std::tr1::bind; +using std::tr1::placeholders::_1; +using util::isnil; +using test::Test; + + +namespace lumiera { + namespace test { + + namespace { // private test classes and data... + + using query::extractID; + + /** limit for the randomly selected duration of + * subsystem's running phase (milliseconds) */ + const uint MAX_RUNNING_TIME_ms = 50; + + /** the "running" subsystem checks for a + * shutdown request every XX milliseconds */ + const uint TICK_DURATION_ms = 5; + + + /** + * A simulated "Lumiera Subsystem". + * It is capable of starting a separate thread, + * which may terminate regularly after a random + * time, or may fail in various ways. + * The behaviour is controlled by a number of + * definitions, given at construction in + * logic predicate notation. + */ + class MockSys + : public lumiera::Subsys, + public Sync + { + bool isUp_; + Literal id_; + Literal spec_; + + volatile bool termRequest_; + int running_duration_; + + + operator string () const { return "MockSys(\""+id_+"\")"; } + + bool + shouldStart (lumiera::Option&) + { + Literal startSpec (extractID ("start",spec_)); + return "true" ==startSpec + || "fail" ==startSpec + || "throw"==startSpec; + } + + bool + start (lumiera::Option&, Subsys::SigTerm termination) + { + Lock guard (this); + if (isUp_) return false; // already started + + Literal startSpec (extractID ("start",spec_)); + ASSERT ("false"!=startSpec); + ASSERT (!isnil (startSpec)); + + if ("true"==startSpec) //----simulate successful subsystem start + { + Thread (bind (&MockSys::run, this, termination)); + isUp_ = true; + } + else + if ("throw"==startSpec) //---starting flounders + throw error::Fatal("simulated failure to start the subsystem"); + + return isUp_; + } + + void + triggerShutdown () throw() + { + termRequest_ = true; + cout << *this << ": triggerShutdown()\n"; + } + + bool + checkRunningState () throw() + { + Lock guard (this); + return isUp_; + } + + + void + run (Subsys::SigTerm termination) ///< simulates a "running" subsystem + { + cout << *this << ": start running...\n"; + + Literal runSpec (extractID ("run",spec_)); + ASSERT (!isnil (startSpec)); + + if ("false"!=runSpec) //----actually hold running state for some time + { + running_duration_ = (rand() % MAX_RUNNING_TIME_ms); + Lock wait(this, &MockSys::tick); + } + + Error problemIndicator("simulated Problem killing a subsystem"); + lumiera_error(); // reset error state.... + // Note: in real life this actually + // would be an catched exception! + + Lock guard (this); + isUp_ = false; + + termination ("true"==runSpec? 0 : &problemIndicator); + } + + + bool + tick () ///< simulates async termination, either on request or by timing + { + Lock sync(this); + if (!sync.isTimedWait()) + { + sync.setTimeout(TICK_DURATION_ms); + running_duration_ += TICK_DURATION_ms; + } + + running_duration_ -= TICK_DURATION_ms; + return termRequest_ || running_duration_ <= 0; + } + + + + public: + MockSys(Literal id, Literal spec) + : id_(id), + spec_(spec), + isUp_(false), + termRequest_(false), + running_duration_(0) + { } + + ~MockSys() { cout << *this << " dead.\n"; } + }; + + + inline ostream& operator<< (ostream& os, MockSys const& mosi) { return os << string(mosi); } + + + + } // (End) test classes and data.... + + + + + + + + + + + /************************************************************************** + * @test managing start and stop of several dependent "subsystems" + * under various conditions. Using mock-subsystems, which actually + * spawn a thread and finish by themselves and generally behave sane. + * + * @see lumiera::Subsys + * @see lumiera::SubsystemRunner + * @see lumiera::AppState + * @see main.cpp + */ + class SubsystemRunner_test : public Test + { + + virtual void + run (Arg) + { + + } + + }; + + + + /** Register this test class... */ + LAUNCHER (SubsystemRunner_test, "function common"); + + + + } // namespace test + +} // namespace lumiera From 2f346370883978f7ab20e896f74ba645965da0e0 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 31 Dec 2008 06:56:31 +0100 Subject: [PATCH 11/35] wire in the new threads implementation from backend... --- src/lib/thread-wrapper.hpp | 90 +++++++++++++++++++++++++++++ tests/lib/Makefile.am | 1 + tests/lib/subsystem-runner-test.cpp | 26 +++++---- 3 files changed, 107 insertions(+), 10 deletions(-) create mode 100644 src/lib/thread-wrapper.hpp diff --git a/src/lib/thread-wrapper.hpp b/src/lib/thread-wrapper.hpp new file mode 100644 index 000000000..8c90295b4 --- /dev/null +++ b/src/lib/thread-wrapper.hpp @@ -0,0 +1,90 @@ +/* + THREADWRAPPER.hpp - thin convenience wrapper for starting lumiera threads + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + 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. + +*/ + + +#ifndef LUMIERA_THREADWRAPPER_H +#define LUMIERA_THREADWRAPPER_H + + +#include "backend/threads.h" +#include "include/nobugcfg.h" + +#include +#include + + +namespace lumiera { + + using std::tr1::bind; + using std::tr1::function; + using std::tr1::placeholders::_1; + + + /** + * A thin convenience wrapper for dealing with threads, + * as implemented by the backend (on top of pthread). + * Using this wrapper... + * - helps with passing data to the function executed in the new thread + * - allows to bind to various kinds of functions + * - supports integrating with an existing object monitor based lock (planned) + * + * @note this class is \em not a thread handle. Within Lumiera, we do all of + * our thread management such as to avoid using global thread handles. + * If some cooperation between threads is needed, this should be done + * in a implementation private way, e.g. by sharing a condition var. + * + * @todo Ichthyo started this wrapper 12/08 while our own thread handling + * was just being shaped. It may well be possible that such a wrapper + * is superfluous in the final application. Re-evaluate this! + */ + class Thread : boost::noncopyable + { + typedef function Operation; + + static void + run (void* arg) + { + ASSERT (arg); + Operation doIt_ = *reinterpret_cast(arg); + + doIt_(); + } + + + public: + Thread (Literal& purpose, Operation operation, struct nobug_flag *logging_flag = &NOBUG_FLAG(operate)) + { + lumiera_thread_run ( LUMIERA_THREAD_INTERACTIVE + , &run // invoking the run helper and.. + , &operation // passing the actual operation as parameter + , 0 // no condition variable provided (for now...) + , purpose.c_str() + , logging_flag + ); + } + }; + + + + +} // namespace lumiera +#endif diff --git a/tests/lib/Makefile.am b/tests/lib/Makefile.am index 5be9d86fc..0e9efe563 100644 --- a/tests/lib/Makefile.am +++ b/tests/lib/Makefile.am @@ -59,6 +59,7 @@ test_lib_SOURCES = \ $(testlib_srcdir)/singletontestmocktest.cpp \ $(testlib_srcdir)/streamtypebasicstest.cpp \ $(testlib_srcdir)/streamtypelifecycletest.cpp \ + $(testlib_srcdir)/subsystem-runner-test.cpp \ $(testlib_srcdir)/sync-classlock-test.cpp \ $(testlib_srcdir)/sync-locking-test.cpp \ $(testlib_srcdir)/sync-waiting-test.cpp \ diff --git a/tests/lib/subsystem-runner-test.cpp b/tests/lib/subsystem-runner-test.cpp index fb9564eaa..d53ba9865 100644 --- a/tests/lib/subsystem-runner-test.cpp +++ b/tests/lib/subsystem-runner-test.cpp @@ -26,9 +26,11 @@ #include "common/subsystem-runner.hpp" #include "include/symbol.hpp" +#include "lib/thread-wrapper.hpp" #include "lib/error.hpp" #include "lib/query.hpp" #include "lib/util.hpp" +#include "lib/sync.hpp" #include #include @@ -38,6 +40,8 @@ using std::tr1::bind; using std::tr1::placeholders::_1; using util::isnil; using test::Test; +using lib::Sync; +using lib::RecursiveLock_Waitable; namespace lumiera { @@ -67,18 +71,16 @@ namespace lumiera { */ class MockSys : public lumiera::Subsys, - public Sync + public Sync { - bool isUp_; Literal id_; Literal spec_; + bool isUp_; volatile bool termRequest_; int running_duration_; - operator string () const { return "MockSys(\""+id_+"\")"; } - bool shouldStart (lumiera::Option&) { @@ -100,7 +102,7 @@ namespace lumiera { if ("true"==startSpec) //----simulate successful subsystem start { - Thread (bind (&MockSys::run, this, termination)); + Thread (id_, bind (&MockSys::run, this, termination)); /////TODO: the thread description should be rather "Test: "+string(*this), but this requires to implement the class Literal as planned isUp_ = true; } else @@ -131,12 +133,13 @@ namespace lumiera { cout << *this << ": start running...\n"; Literal runSpec (extractID ("run",spec_)); - ASSERT (!isnil (startSpec)); + ASSERT (!isnil (runSpec)); if ("false"!=runSpec) //----actually hold running state for some time { running_duration_ = (rand() % MAX_RUNNING_TIME_ms); - Lock wait(this, &MockSys::tick); + + Lock wait_blocking (this, &MockSys::tick); } Error problemIndicator("simulated Problem killing a subsystem"); @@ -177,11 +180,14 @@ namespace lumiera { { } ~MockSys() { cout << *this << " dead.\n"; } + + operator string () const { return "MockSys(\""+id_+"\")"; } + + friend inline ostream& + operator<< (ostream& os, MockSys const& mosi) { return os << string(mosi); } + }; - - inline ostream& operator<< (ostream& os, MockSys const& mosi) { return os << string(mosi); } - } // (End) test classes and data.... From 120fbf8f01feb31d97d5eae4684fc3d502551813 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 2 Jan 2009 08:01:51 +0100 Subject: [PATCH 12/35] temporary addition: signalling successful thread creation (I take it the final implementation will provide something equivalent, without such a check, failure to create the thread results in deadlock) --- src/backend/threads.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/backend/threads.c b/src/backend/threads.c index 77f5bb45f..11f70ac7a 100644 --- a/src/backend/threads.c +++ b/src/backend/threads.c @@ -98,10 +98,11 @@ lumiera_thread_run (enum lumiera_thread_class kind, pthread_mutex_lock (&threads_mutex); pthread_t dummy; - pthread_create (&dummy, &attrs, pthread_runner, &thread); + int error = pthread_create (&dummy, &attrs, pthread_runner, &thread); pthread_mutex_unlock (&threads_mutex); + if (error) return 0; /////TODO temporary addition by Ichthyo; probably we'll set lumiera_error? return (LumieraThread) 1; } From 2aab2491aacafe4804a8a71970d9b4bd81680c59 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 2 Jan 2009 08:02:27 +0100 Subject: [PATCH 13/35] deal with a race regarding argument passing --- src/lib/thread-wrapper.hpp | 54 +++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/src/lib/thread-wrapper.hpp b/src/lib/thread-wrapper.hpp index 8c90295b4..b927f3d51 100644 --- a/src/lib/thread-wrapper.hpp +++ b/src/lib/thread-wrapper.hpp @@ -25,27 +25,36 @@ #define LUMIERA_THREADWRAPPER_H -#include "backend/threads.h" #include "include/nobugcfg.h" +#include "lib/sync.hpp" + +extern "C" { +#include "backend/threads.h" +} #include #include namespace lumiera { - + using std::tr1::bind; using std::tr1::function; using std::tr1::placeholders::_1; + using lib::Sync; + using lib::NonrecursiveLock_Waitable; + /** * A thin convenience wrapper for dealing with threads, * as implemented by the backend (on top of pthread). * Using this wrapper... * - helps with passing data to the function executed in the new thread - * - allows to bind to various kinds of functions + * - allows to bind to various kinds of functions including member functions * - supports integrating with an existing object monitor based lock (planned) + * The new thread starts immediately within the ctor; after returning, the new + * thread has already copied the arguments and indeed actively started to run. * * @note this class is \em not a thread handle. Within Lumiera, we do all of * our thread management such as to avoid using global thread handles. @@ -56,35 +65,56 @@ namespace lumiera { * was just being shaped. It may well be possible that such a wrapper * is superfluous in the final application. Re-evaluate this! */ - class Thread : boost::noncopyable + class Thread + : public Sync, + boost::noncopyable { + volatile bool started_; + typedef function Operation; + Operation const& operation_; static void run (void* arg) { ASSERT (arg); - Operation doIt_ = *reinterpret_cast(arg); + Thread* startingWrapper = reinterpret_cast(arg); + Operation _doIt_(startingWrapper->operation_); + { + Lock sync(startingWrapper); + startingWrapper->started_ = true; + sync.notify(); // handshake signalling we've gotten the parameter + } - doIt_(); + _doIt_(); // execute the actual operation in the new thread } public: - Thread (Literal& purpose, Operation operation, struct nobug_flag *logging_flag = &NOBUG_FLAG(operate)) + Thread (Literal& purpose, Operation const& operation, struct nobug_flag *logging_flag = &NOBUG_FLAG(operate)) + : started_(false), + operation_(operation) { + Lock sync(this); + LumieraThread res = lumiera_thread_run ( LUMIERA_THREAD_INTERACTIVE , &run // invoking the run helper and.. - , &operation // passing the actual operation as parameter + , this // passing this start context as parameter , 0 // no condition variable provided (for now...) , purpose.c_str() , logging_flag ); + + if (!res) + throw error::State("failed to create new thread."); + + // make sure the new thread had the opportunity to take the Operation + // prior to leaving and thereby possibly destroying this local context + sync.wait (started_); } }; - - - -} // namespace lumiera + + + } // namespace lumiera #endif From 5e579b5abce70fc1ead45161e1b9ad7ac44a7102 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 2 Jan 2009 08:07:55 +0100 Subject: [PATCH 14/35] simple test creating 20 threads... --- tests/40components.tests | 5 ++ tests/lib/Makefile.am | 1 + tests/lib/thread-wrapper-test.cpp | 117 ++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 tests/lib/thread-wrapper-test.cpp diff --git a/tests/40components.tests b/tests/40components.tests index a9bcad005..c9666cb21 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -332,6 +332,11 @@ return: 0 END +TEST "Create 20 Threads passing context" ThreadWrapper_test < Testgroup=ALL diff --git a/tests/lib/Makefile.am b/tests/lib/Makefile.am index 0e9efe563..52dff04b0 100644 --- a/tests/lib/Makefile.am +++ b/tests/lib/Makefile.am @@ -63,6 +63,7 @@ test_lib_SOURCES = \ $(testlib_srcdir)/sync-classlock-test.cpp \ $(testlib_srcdir)/sync-locking-test.cpp \ $(testlib_srcdir)/sync-waiting-test.cpp \ + $(testlib_srcdir)/thread-wrapper-test.cpp \ $(testlib_srcdir)/test/cmdlinewrappertest.cpp \ $(testlib_srcdir)/test/testoptiontest.cpp \ $(testlib_srcdir)/vectortransfertest.cpp \ diff --git a/tests/lib/thread-wrapper-test.cpp b/tests/lib/thread-wrapper-test.cpp new file mode 100644 index 000000000..30bd1e24c --- /dev/null +++ b/tests/lib/thread-wrapper-test.cpp @@ -0,0 +1,117 @@ +/* + ThreadWrapper(Test) - starting threads and passing context + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + 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. + +* *****************************************************/ + + +#include "lib/test/run.hpp" + +#include "include/symbol.hpp" +#include "lib/thread-wrapper.hpp" +#include "lib/sync.hpp" + +#include + +using std::tr1::bind; +using test::Test; + + + +namespace lumiera { + namespace test { + + namespace { // private test classes and data... + + ulong sum; + ulong checksum; + + const uint NUM_THREADS = 20; + const uint MAX_RAND_SUMMAND = 100; + + uint + createVal() ///< generating test values, remembering the sum + { + uint val(rand() % MAX_RAND_SUMMAND); + checksum += val; + return val; + } + + + struct TestThread : Thread + { + TestThread() + : Thread("test Thread creation", + bind (&TestThread::theOperation, this, createVal(), createVal())) + { } // note the binding (functor object) is passed as anonymous temporary + + + void + theOperation (uint a, uint b) ///< the actual operation running in a separate thread + { + Lock sync(this); // *not* a recursive lock, because parent unlocks prior to invoking the operation + sum += (a+b); + } + }; + + } // (End) test classes and data.... + + + + + + + + + + + /************************************************************************** + * @test use the Lumiera backend to create some new threads, utilising the + * lumiera::Thread wrapper for binding to an arbitrary operation + * and passing the appropriate context. + * + * @see lumiera::Thread + * @see threads.h + */ + class ThreadWrapper_test : public Test + { + + virtual void + run (Arg) + { + sum = checksum = 0; + TestThread instances[NUM_THREADS] SIDEEFFECT; + + ASSERT (0 < sum); + ASSERT (sum==checksum); + } + + + }; + + + + /** Register this test class... */ + LAUNCHER (ThreadWrapper_test, "function common"); + + + + } // namespace test + +} // namespace lumiera From eac43b80d65691f8d1bb56ac31c018df1c465d0a Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 2 Jan 2009 10:57:13 +0100 Subject: [PATCH 15/35] cover simple testcase of starting just one subsystem --- tests/40components.tests | 5 +++++ tests/lib/subsystem-runner-test.cpp | 30 +++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/tests/40components.tests b/tests/40components.tests index c9666cb21..2a1c8be8c 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -337,6 +337,11 @@ return: 0 END +TEST "Starting and stopping subsystems" SubsystemRunner_test < Testgroup=ALL diff --git a/tests/lib/subsystem-runner-test.cpp b/tests/lib/subsystem-runner-test.cpp index d53ba9865..50d000316 100644 --- a/tests/lib/subsystem-runner-test.cpp +++ b/tests/lib/subsystem-runner-test.cpp @@ -24,6 +24,7 @@ #include "lib/test/run.hpp" #include "common/subsys.hpp" #include "common/subsystem-runner.hpp" +#include "common/option.hpp" #include "include/symbol.hpp" #include "lib/thread-wrapper.hpp" @@ -59,6 +60,11 @@ namespace lumiera { * shutdown request every XX milliseconds */ const uint TICK_DURATION_ms = 5; + /** dummy options just to be ignored */ + util::Cmdline dummyArgs (""); + lumiera::Option dummyOpt (dummyArgs); + + /** * A simulated "Lumiera Subsystem". @@ -77,6 +83,7 @@ namespace lumiera { Literal spec_; bool isUp_; + bool didRun_; volatile bool termRequest_; int running_duration_; @@ -137,6 +144,7 @@ namespace lumiera { if ("false"!=runSpec) //----actually hold running state for some time { + didRun_ = true; running_duration_ = (rand() % MAX_RUNNING_TIME_ms); Lock wait_blocking (this, &MockSys::tick); @@ -175,6 +183,7 @@ namespace lumiera { : id_(id), spec_(spec), isUp_(false), + didRun_(false), termRequest_(false), running_duration_(0) { } @@ -185,7 +194,8 @@ namespace lumiera { friend inline ostream& operator<< (ostream& os, MockSys const& mosi) { return os << string(mosi); } - + + bool didRun () const { return didRun_; } }; @@ -217,9 +227,25 @@ namespace lumiera { virtual void run (Arg) { - + singleSubsys_complete_cycle(); } + + void + singleSubsys_complete_cycle() + { + MockSys unit ("one", "start(true), run(true)."); + SubsystemRunner runner(dummyOpt); + REQUIRE (!unit.isRunning()); + REQUIRE (!unit.didRun()); + + runner.maybeRun (unit); + bool emergency = runner.wait(); + + ASSERT (!emergency); + ASSERT (!unit.isRunning()); + ASSERT (unit.didRun()); + } }; From 762a108dff1352fce0df24962ab83c97acd628c1 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 3 Jan 2009 01:11:21 +0100 Subject: [PATCH 16/35] cover more testcases (starting several subsystems) --- tests/lib/exceptionerrortest.cpp | 42 +++++----- tests/lib/subsystem-runner-test.cpp | 124 +++++++++++++++++++++++++--- 2 files changed, 134 insertions(+), 32 deletions(-) diff --git a/tests/lib/exceptionerrortest.cpp b/tests/lib/exceptionerrortest.cpp index b5d4c348c..4407a39f8 100644 --- a/tests/lib/exceptionerrortest.cpp +++ b/tests/lib/exceptionerrortest.cpp @@ -1,5 +1,5 @@ /* - Exceptionhandlin(Test) - throwing and catching our exception type + ExceptionError(Test) - throwing and catching our exception type Copyright (C) Lumiera.org 2008, Hermann Vosseler @@ -41,13 +41,11 @@ using std::cout; -namespace lumiera - { - namespace test - { - +namespace lumiera { + namespace test { + /** local specific error-constant for use in the - * construcor of the nested SpecificError class. + * constructor of the nested SpecificError class. */ LUMIERA_ERROR_DEFINE(LIFE_AND_UNIVERSE, "and everything?"); LUMIERA_ERROR_DEFINE(DERIVED, "convoluted exception"); @@ -98,7 +96,7 @@ namespace lumiera void throwExternal(string _) { throw error::External(_); } void throwRuntime (string _) { throw std::runtime_error(_); } void throwExceptn (string ) { throw std::exception(); } - + /** @test catching, repackaging and rethrowing of errors. * This feature is important for passing exceptions transparently @@ -126,7 +124,7 @@ namespace lumiera try { nestedThrower (msg); } catch (Error& e) { - cout << "2nd intermediate handler caught: " << e.what() + cout << "2nd intermediate handler caught: " << e.what() << "....will rethrow as error::Config\n"; throw error::Config (e); } @@ -172,7 +170,7 @@ namespace lumiera ASSERT (err2.rootCause() == err1.what()); ASSERT (err3.rootCause() == err1.what()); ASSERT (err4.rootCause() == err1.what()); - + ASSERT (err5.rootCause() == rerr.what()); ASSERT (err6.rootCause() == rerr.what()); } @@ -214,22 +212,22 @@ namespace lumiera (this->*funky) (context); } - catch (SpecificError& e) { cout << "caught: " << e.what() << "..the answer is: " << e.revealIt() << "\n"; } - catch (error::Logic& e) { cout << "caught error::Logic: " << e.what() << "\n"; } - catch (error::Invalid&e) { cout << "caught error::Invalid: " << e.what() << "\n"; } - catch (Error& e) { cout << "caught lumiera::Error: " << e.what() << "\n"; } - catch (runtime_error& e) { cout << "caught std::runtime_error: " << e.what() << "\n"; } + catch (SpecificError& e) { cout << "caught: " << e.what() << "..the answer is: " << e.revealIt() << "\n"; } + catch (error::Logic& e) { cout << "caught error::Logic: " << e.what() << "\n"; } + catch (error::Invalid&e) { cout << "caught error::Invalid: " << e.what() << "\n"; } + catch (Error& e) { cout << "caught lumiera::Error: " << e.what() << "\n"; } + catch (runtime_error& e) { cout << "caught std::runtime_error: " << e.what() << "\n"; } catch (exception& e) { cout << "caught std::exception. (unspecific)" << "\n"; } catch (...) { cout << "caught an unknown exception\n"; } } }; - - - - /** register this test class... */ - LAUNCHER (ExceptionError_test, "function common"); - - + + + + /** register this test class... */ + LAUNCHER (ExceptionError_test, "function common"); + + } // namespace test } // namespace util diff --git a/tests/lib/subsystem-runner-test.cpp b/tests/lib/subsystem-runner-test.cpp index 50d000316..1d810fcd0 100644 --- a/tests/lib/subsystem-runner-test.cpp +++ b/tests/lib/subsystem-runner-test.cpp @@ -38,7 +38,6 @@ using std::cout; using std::tr1::bind; -using std::tr1::placeholders::_1; using util::isnil; using test::Test; using lib::Sync; @@ -64,6 +63,10 @@ namespace lumiera { util::Cmdline dummyArgs (""); lumiera::Option dummyOpt (dummyArgs); + /** marker for simulated failure exceptions */ + LUMIERA_ERROR_DEFINE( TEST, "simulated failure."); + + /** @@ -82,8 +85,8 @@ namespace lumiera { Literal id_; Literal spec_; - bool isUp_; - bool didRun_; + volatile bool isUp_; + volatile bool didRun_; volatile bool termRequest_; int running_duration_; @@ -113,8 +116,11 @@ namespace lumiera { isUp_ = true; } else + if ("fail"==startSpec) //----starting incorrectly reports success + return true; + else if ("throw"==startSpec) //---starting flounders - throw error::Fatal("simulated failure to start the subsystem"); + throw error::Fatal("simulated failure to start the subsystem", LUMIERA_ERROR_TEST); return isUp_; } @@ -150,16 +156,17 @@ namespace lumiera { Lock wait_blocking (this, &MockSys::tick); } - Error problemIndicator("simulated Problem killing a subsystem"); + Error problemIndicator("simulated Problem killing a subsystem",LUMIERA_ERROR_TEST); lumiera_error(); // reset error state.... // Note: in real life this actually // would be an catched exception! - Lock guard (this); - isUp_ = false; - - termination ("true"==runSpec? 0 : &problemIndicator); - } + { + Lock guard (this); + isUp_ = false; + + termination ("true"==runSpec? 0 : &problemIndicator); + } } bool @@ -228,6 +235,10 @@ namespace lumiera { run (Arg) { singleSubsys_complete_cycle(); + singleSubsys_start_failure(); + singleSubsys_emegency_exit(); + + dependentSubsys_complete_cycle(); } @@ -246,6 +257,99 @@ namespace lumiera { ASSERT (!unit.isRunning()); ASSERT (unit.didRun()); } + + + void + singleSubsys_start_failure() + { + MockSys unit1 ("U1", "start(false), run(false)."); + MockSys unit2 ("U2", "start(throw), run(false)."); + MockSys unit3 ("U3", "start(fail), run(false)."); // simulates incorrect behaviour + MockSys unit4 ("U4", "start(true), run(false)."); + SubsystemRunner runner(dummyOpt); + + runner.maybeRun (unit1); + runner.maybeRun (unit4); + try + { + runner.maybeRun (unit2); + NOTREACHED; + } + catch (lumiera::Error&) + { + ASSERT (lumiera_error() == LUMIERA_ERROR_TEST); + } + try + { + runner.maybeRun (unit3); + NOTREACHED; + } + catch (lumiera::Error&) + { + ASSERT (lumiera_error() == error::LUMIERA_ERROR_LOGIC); // incorrect behaviour trapped + } + + + bool emergency = runner.wait(); + + ASSERT (emergency); // emergency state from unit4 got propagated + ASSERT (!unit1.isRunning()); + ASSERT (!unit2.isRunning()); + ASSERT (!unit3.isRunning()); + ASSERT (!unit4.isRunning()); + ASSERT (!unit1.didRun()); + ASSERT (!unit2.didRun()); + ASSERT (!unit3.didRun()); + ASSERT (!unit4.didRun()); + } + + + void + singleSubsys_emegency_exit() + { + MockSys unit ("one", "start(true), run(fail)."); + SubsystemRunner runner(dummyOpt); + + runner.maybeRun (unit); + bool emergency = runner.wait(); + + ASSERT (emergency); // emergency state got propagated + ASSERT (!unit.isRunning()); + ASSERT (unit.didRun()); + } + + + void + dependentSubsys_complete_cycle() + { + MockSys unit1 ("U1", "start(true), run(true)."); + MockSys unit2 ("U2", "start(true), run(true)."); + MockSys unit3 ("U3", "start(true), run(true)."); + MockSys unit4 ("U4", "start(true), run(true)."); + unit2.depends (unit1); + unit4.depends (unit3); + unit4.depends (unit1); + unit3.depends (unit2); + SubsystemRunner runner(dummyOpt); + + runner.maybeRun (unit4); + ASSERT (unit1.isRunning()); + ASSERT (unit2.isRunning()); + ASSERT (unit3.isRunning()); + ASSERT (unit4.isRunning()); + + bool emergency = runner.wait(); + + ASSERT (!emergency); + ASSERT (!unit1.isRunning()); + ASSERT (!unit2.isRunning()); + ASSERT (!unit3.isRunning()); + ASSERT (!unit4.isRunning()); + ASSERT (unit1.didRun()); + ASSERT (unit2.didRun()); + ASSERT (unit3.didRun()); + ASSERT (unit4.didRun()); + } }; From f90238dba47664abc2867dcc92c995e01a33d660 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 3 Jan 2009 04:29:59 +0100 Subject: [PATCH 17/35] chased two bugs... --- src/common/subsys.hpp | 3 ++- src/common/subsystem-runner.hpp | 14 +++++----- tests/lib/subsystem-runner-test.cpp | 41 +++++++++++++++++++++++++---- 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/common/subsys.hpp b/src/common/subsys.hpp index e59d2db28..598919bb7 100644 --- a/src/common/subsys.hpp +++ b/src/common/subsys.hpp @@ -83,7 +83,8 @@ namespace lumiera { * required for running this subsystem */ Subsys& depends (Subsys& prereq); - /** @return true if Up */ + /** @return true if Up + * @warning must not block nor throw. */ bool isRunning(); diff --git a/src/common/subsystem-runner.hpp b/src/common/subsystem-runner.hpp index 5ebdc1f0d..60fbd9e56 100644 --- a/src/common/subsystem-runner.hpp +++ b/src/common/subsystem-runner.hpp @@ -120,8 +120,6 @@ namespace lumiera { if (!susy.isRunning() && susy.shouldStart (opts_)) triggerStartup (&susy); - if (susy.isRunning()) - running_.push_back (&susy); } void @@ -154,15 +152,19 @@ namespace lumiera { triggerStartup (Subsys* susy) { ASSERT (susy); - INFO (operate, "Starting subsystem \"%s\"", cStr(*susy)); + if (susy->isRunning()) return; + + INFO (operate, "Triggering startup of subsystem \"%s\"", cStr(*susy)); for_each (susy->getPrerequisites(), start_); bool started = susy->start (opts_, bind (&SubsystemRunner::sigTerm, this, susy, _1)); - if (started && !susy->isRunning()) - { + if (started) + if (susy->isRunning()) + running_.push_back (susy); // now responsible for managing the started subsystem + else throw error::Logic("Subsystem "+string(*susy)+" failed to start"); - } + if (!and_all (susy->getPrerequisites(), isRunning() )) { susy->triggerShutdown(); diff --git a/tests/lib/subsystem-runner-test.cpp b/tests/lib/subsystem-runner-test.cpp index 1d810fcd0..3bcb89d08 100644 --- a/tests/lib/subsystem-runner-test.cpp +++ b/tests/lib/subsystem-runner-test.cpp @@ -39,6 +39,7 @@ using std::cout; using std::tr1::bind; using util::isnil; +using util::cStr; using test::Test; using lib::Sync; using lib::RecursiveLock_Waitable; @@ -53,7 +54,8 @@ namespace lumiera { /** limit for the randomly selected duration of * subsystem's running phase (milliseconds) */ - const uint MAX_RUNNING_TIME_ms = 50; + const uint MAX_RUNNING_TIME_ms = 60; + const uint MIN_RUNNING_TIME_ms = 10; /** the "running" subsystem checks for a * shutdown request every XX milliseconds */ @@ -103,9 +105,9 @@ namespace lumiera { bool start (lumiera::Option&, Subsys::SigTerm termination) { - Lock guard (this); - if (isUp_) return false; // already started + REQUIRE (!isUp_, "attempt to start %s twice!", cStr(*this)); + Lock guard (this); Literal startSpec (extractID ("start",spec_)); ASSERT ("false"!=startSpec); ASSERT (!isnil (startSpec)); @@ -128,6 +130,7 @@ namespace lumiera { void triggerShutdown () throw() { + // note: *not* locking here... termRequest_ = true; cout << *this << ": triggerShutdown()\n"; } @@ -135,7 +138,7 @@ namespace lumiera { bool checkRunningState () throw() { - Lock guard (this); + // note: *not* locking here... return isUp_; } @@ -151,7 +154,8 @@ namespace lumiera { if ("false"!=runSpec) //----actually hold running state for some time { didRun_ = true; - running_duration_ = (rand() % MAX_RUNNING_TIME_ms); + running_duration_ = MIN_RUNNING_TIME_ms; + running_duration_ += (rand() % (MAX_RUNNING_TIME_ms - MIN_RUNNING_TIME_ms)); Lock wait_blocking (this, &MockSys::tick); } @@ -165,6 +169,7 @@ namespace lumiera { Lock guard (this); isUp_ = false; + cout << *this << ": terminates.\n"; termination ("true"==runSpec? 0 : &problemIndicator); } } @@ -245,6 +250,8 @@ namespace lumiera { void singleSubsys_complete_cycle() { + cout << "-----singleSubsys_complete_cycle-----\n"; + MockSys unit ("one", "start(true), run(true)."); SubsystemRunner runner(dummyOpt); REQUIRE (!unit.isRunning()); @@ -262,6 +269,8 @@ namespace lumiera { void singleSubsys_start_failure() { + cout << "-----singleSubsys_start_failure-----\n"; + MockSys unit1 ("U1", "start(false), run(false)."); MockSys unit2 ("U2", "start(throw), run(false)."); MockSys unit3 ("U3", "start(fail), run(false)."); // simulates incorrect behaviour @@ -307,6 +316,8 @@ namespace lumiera { void singleSubsys_emegency_exit() { + cout << "-----singleSubsys_emegency_exit-----\n"; + MockSys unit ("one", "start(true), run(fail)."); SubsystemRunner runner(dummyOpt); @@ -319,9 +330,23 @@ namespace lumiera { } + void zoing(string zoz) + { + cout << "zoing! "< Date: Sat, 3 Jan 2009 13:32:24 +0100 Subject: [PATCH 18/35] cleanup, add further testcase (starting prerequisite subsystems) SubsystemRunner considered finished. --- src/common/subsystem-runner.hpp | 2 +- tests/40components.tests | 5 ++ tests/lib/subsystem-runner-test.cpp | 104 ++++++++++++++++++---------- 3 files changed, 72 insertions(+), 39 deletions(-) diff --git a/src/common/subsystem-runner.hpp b/src/common/subsystem-runner.hpp index 60fbd9e56..1e7deb32f 100644 --- a/src/common/subsystem-runner.hpp +++ b/src/common/subsystem-runner.hpp @@ -133,7 +133,7 @@ namespace lumiera { triggerEmergency (bool cond) { Lock guard (this); - emergency_ |= cond; + if (cond) emergency_= true; } bool diff --git a/tests/40components.tests b/tests/40components.tests index 2a1c8be8c..6ed448349 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -338,6 +338,11 @@ END TEST "Starting and stopping subsystems" SubsystemRunner_test < %s....", cStr(*this)); } bool @@ -146,36 +146,36 @@ namespace lumiera { void run (Subsys::SigTerm termination) ///< simulates a "running" subsystem { - cout << *this << ": start running...\n"; - Literal runSpec (extractID ("run",spec_)); ASSERT (!isnil (runSpec)); - if ("false"!=runSpec) //----actually hold running state for some time + if ("false"!=runSpec) //----actually enter running state for some time { didRun_ = true; running_duration_ = MIN_RUNNING_TIME_ms; running_duration_ += (rand() % (MAX_RUNNING_TIME_ms - MIN_RUNNING_TIME_ms)); + INFO (test, "thread %s now running....", cStr(*this)); + Lock wait_blocking (this, &MockSys::tick); } Error problemIndicator("simulated Problem killing a subsystem",LUMIERA_ERROR_TEST); lumiera_error(); // reset error state.... // Note: in real life this actually - // would be an catched exception! + // would be an catched exception! { Lock guard (this); isUp_ = false; - cout << *this << ": terminates.\n"; + INFO (test, "thread %s terminates.", cStr(*this)); termination ("true"==runSpec? 0 : &problemIndicator); } } bool - tick () ///< simulates async termination, either on request or by timing + tick () ///< simulates async termination, either on request or by timing { Lock sync(this); if (!sync.isTimedWait()) @@ -200,7 +200,7 @@ namespace lumiera { running_duration_(0) { } - ~MockSys() { cout << *this << " dead.\n"; } + ~MockSys() { } operator string () const { return "MockSys(\""+id_+"\")"; } @@ -209,8 +209,8 @@ namespace lumiera { bool didRun () const { return didRun_; } }; - - + + } // (End) test classes and data.... @@ -227,6 +227,8 @@ namespace lumiera { * @test managing start and stop of several dependent "subsystems" * under various conditions. Using mock-subsystems, which actually * spawn a thread and finish by themselves and generally behave sane. + * For each such MockSys, we can define a behaviour pattern, e.g. + * weather the start succeeds and if the run terminates with error. * * @see lumiera::Subsys * @see lumiera::SubsystemRunner @@ -237,13 +239,14 @@ namespace lumiera { { virtual void - run (Arg) + run (Arg) { singleSubsys_complete_cycle(); singleSubsys_start_failure(); singleSubsys_emegency_exit(); dependentSubsys_complete_cycle(); + dependentSubsys_start_failure(); } @@ -330,18 +333,6 @@ namespace lumiera { } - void zoing(string zoz) - { - cout << "zoing! "< Date: Sat, 3 Jan 2009 16:05:04 +0100 Subject: [PATCH 19/35] Integration: Thread/sync, GUI-Plugin invoked in separate thread --- src/common/guifacade.cpp | 14 +++++++++----- src/common/subsystem-runner.hpp | 1 + src/gui/guifacade.hpp | 4 ++-- src/gui/guistart.cpp | 7 +++---- src/lib/thread-wrapper.hpp | 15 ++++++--------- tests/lib/subsystem-runner-test.cpp | 1 + tests/lib/thread-wrapper-test.cpp | 8 ++++---- 7 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/common/guifacade.cpp b/src/common/guifacade.cpp index c95e069a1..d803cecc3 100644 --- a/src/common/guifacade.cpp +++ b/src/common/guifacade.cpp @@ -27,6 +27,7 @@ #include "lib/error.hpp" #include "lib/singleton.hpp" #include "lib/functorutil.hpp" +#include "lib/thread-wrapper.hpp" #include "common/instancehandle.hpp" #include @@ -45,6 +46,7 @@ namespace gui { using util::dispatchSequenced; using lib::Sync; using lib::RecursiveLock_NoWait; + using lib::Thread; @@ -60,17 +62,18 @@ namespace gui { : theGUI_("lumieraorg_Gui", 1, 1, "lumieraorg_GuiStarterPlugin") // load GuiStarterPlugin { ASSERT (theGUI_); - if (!kickOff (terminationHandle)) + Thread ("GUI-Main", bind (&GuiRunner::kickOff, this, terminationHandle)); + + if (lumiera_error_peek()) throw lumiera::error::Fatal("failed to bring up GUI",lumiera_error()); } ~GuiRunner () { } - bool kickOff (Subsys::SigTerm& terminationHandle) + void kickOff (Subsys::SigTerm& terminationHandle) { - return theGUI_->kickOff (reinterpret_cast (&terminationHandle)) - && !lumiera_error_peek(); + theGUI_->kickOff (reinterpret_cast (&terminationHandle)); } }; @@ -81,6 +84,7 @@ namespace gui { scoped_ptr facade (0); + class GuiSubsysDescriptor : public lumiera::Subsys, public Sync @@ -123,10 +127,10 @@ namespace gui { bool checkRunningState () throw() { - Lock guard (this); return (facade); } + void closeGuiModule (lumiera::Error *) { diff --git a/src/common/subsystem-runner.hpp b/src/common/subsystem-runner.hpp index 1e7deb32f..f46168cd7 100644 --- a/src/common/subsystem-runner.hpp +++ b/src/common/subsystem-runner.hpp @@ -177,6 +177,7 @@ namespace lumiera { ASSERT (susy); Lock sync (this); triggerEmergency(problem); + INFO (operate, "Subsystem '%s' terminated.", cStr(*susy)); ERROR_IF (susy->isRunning(), lumiera, "Subsystem '%s' signals termination, " "without resetting running state", cStr(*susy)); removeall (running_, susy); diff --git a/src/gui/guifacade.hpp b/src/gui/guifacade.hpp index 677ef4711..5afa230f0 100644 --- a/src/gui/guifacade.hpp +++ b/src/gui/guifacade.hpp @@ -91,7 +91,7 @@ namespace gui { * @internal this function is invoked automatically during the GUI * loading and startup process. Don't call it manually. */ - virtual bool kickOff (lumiera::Subsys::SigTerm&) =0; + virtual void kickOff (lumiera::Subsys::SigTerm&) =0; protected: @@ -100,7 +100,7 @@ namespace gui { /** interface of the GuiStarterPlugin */ LUMIERA_INTERFACE_DECLARE (lumieraorg_Gui, 1, - LUMIERA_INTERFACE_SLOT (bool, kickOff, (void*)) + LUMIERA_INTERFACE_SLOT (void, kickOff, (void*)) ); diff --git a/src/gui/guistart.cpp b/src/gui/guistart.cpp index 360cba90f..cca023ac9 100644 --- a/src/gui/guistart.cpp +++ b/src/gui/guistart.cpp @@ -75,7 +75,7 @@ namespace gui { : public GuiFacade { - bool kickOff (Subsys::SigTerm& terminationHandle) + void kickOff (Subsys::SigTerm& terminationHandle) { cout << " *** Ha Ha Ha\n" << " this is the GuiStarterPlugin speaking!\n" @@ -83,7 +83,6 @@ namespace gui { << " but actually nothing happens!!!!!!!!!!!!!!\n\n"; terminationHandle(0); // signal immediate shutdown without error - return false; } }; @@ -179,9 +178,9 @@ extern "C" { /* ================== define an lumieraorg_Gui instance =========== , NULL /* on open */ , NULL /* on close */ , LUMIERA_INTERFACE_INLINE (kickOff, "\255\142\006\244\057\170\152\312\301\372\220\323\230\026\200\065", - bool, (void* termSig), + void, (void* termSig), { - return gui::facade_().kickOff ( + gui::facade_().kickOff ( *reinterpret_cast (termSig)); } ) diff --git a/src/lib/thread-wrapper.hpp b/src/lib/thread-wrapper.hpp index b927f3d51..3c60cda09 100644 --- a/src/lib/thread-wrapper.hpp +++ b/src/lib/thread-wrapper.hpp @@ -21,8 +21,8 @@ */ -#ifndef LUMIERA_THREADWRAPPER_H -#define LUMIERA_THREADWRAPPER_H +#ifndef LIB_THREADWRAPPER_H +#define LIB_THREADWRAPPER_H #include "include/nobugcfg.h" @@ -36,14 +36,11 @@ extern "C" { #include -namespace lumiera { +namespace lib { using std::tr1::bind; using std::tr1::function; - using std::tr1::placeholders::_1; - - using lib::Sync; - using lib::NonrecursiveLock_Waitable; + using lumiera::Literal; /** @@ -106,7 +103,7 @@ namespace lumiera { ); if (!res) - throw error::State("failed to create new thread."); + throw lumiera::error::State("failed to create new thread."); // make sure the new thread had the opportunity to take the Operation // prior to leaving and thereby possibly destroying this local context @@ -116,5 +113,5 @@ namespace lumiera { - } // namespace lumiera + } // namespace lib #endif diff --git a/tests/lib/subsystem-runner-test.cpp b/tests/lib/subsystem-runner-test.cpp index c1391a26c..2f6d65454 100644 --- a/tests/lib/subsystem-runner-test.cpp +++ b/tests/lib/subsystem-runner-test.cpp @@ -43,6 +43,7 @@ using util::cStr; using test::Test; using lib::Sync; using lib::RecursiveLock_Waitable; +using lib::Thread; namespace lumiera { diff --git a/tests/lib/thread-wrapper-test.cpp b/tests/lib/thread-wrapper-test.cpp index 30bd1e24c..52ec2bb14 100644 --- a/tests/lib/thread-wrapper-test.cpp +++ b/tests/lib/thread-wrapper-test.cpp @@ -34,8 +34,8 @@ using test::Test; -namespace lumiera { - namespace test { +namespace lib { + namespace test { namespace { // private test classes and data... @@ -86,7 +86,7 @@ namespace lumiera { * lumiera::Thread wrapper for binding to an arbitrary operation * and passing the appropriate context. * - * @see lumiera::Thread + * @see lib::Thread * @see threads.h */ class ThreadWrapper_test : public Test @@ -114,4 +114,4 @@ namespace lumiera { } // namespace test -} // namespace lumiera +} // namespace lib From e8229623bcadeaebcbbe7a7de0eb4708fa7e5470 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 3 Jan 2009 16:57:51 +0100 Subject: [PATCH 20/35] Integration: complete GTK-GUI loaded from main Lumiera App. !Yay! --- src/gui/gtk-lumiera.cpp | 19 +++++++++------ src/gui/gtk-lumiera.hpp | 2 +- src/gui/guistart.cpp | 51 +++++++++++++++++++++++++++-------------- 3 files changed, 47 insertions(+), 25 deletions(-) diff --git a/src/gui/gtk-lumiera.cpp b/src/gui/gtk-lumiera.cpp index 64dd4668c..e9c7b0088 100644 --- a/src/gui/gtk-lumiera.cpp +++ b/src/gui/gtk-lumiera.cpp @@ -46,20 +46,14 @@ using namespace gui::model; GtkLumiera the_application; -int -main (int argc, char *argv[]) -{ - return the_application.main(argc, argv); -} namespace gui { -int +void GtkLumiera::main(int argc, char *argv[]) { - NOBUG_INIT; Main kit(argc, argv); @@ -92,3 +86,14 @@ application() } // namespace gui + +/** + * Run the Lumiera GTK GUI as standalone application without backend. + */ +int +main (int argc, char *argv[]) +{ + NOBUG_INIT; + gui::application().main(argc, argv); + return 0; +} diff --git a/src/gui/gtk-lumiera.hpp b/src/gui/gtk-lumiera.hpp index 4f3021b76..ce3d4c2e4 100644 --- a/src/gui/gtk-lumiera.hpp +++ b/src/gui/gtk-lumiera.hpp @@ -98,7 +98,7 @@ static const gchar* AppAuthors[] = { class GtkLumiera : private boost::noncopyable { public: - int main(int argc, char *argv[]); + void main(int argc, char *argv[]); static Glib::ustring get_home_data_path(); diff --git a/src/gui/guistart.cpp b/src/gui/guistart.cpp index cca023ac9..4b9d28262 100644 --- a/src/gui/guistart.cpp +++ b/src/gui/guistart.cpp @@ -31,18 +31,24 @@ ** ** After successfully loading this module, a call to #kickOff is expected to be ** issued, passing a termination signal (callback) to be executed when the GUI - ** terminates. This call returns immediately, after spawning off the main thread - ** and setting up the termination callback accordingly. Additionally, it cares - ** for opening the primary "business" interface of the GUI, i.e. the interface - ** gui::GuiNotification. + ** terminates. This call remains blocked within the main GTK event loop; thus + ** typically this should already run within a separate dedicated GUI thread. + ** Especially, the gui::GuiRunner will ensure this to happen. + ** + ** Prior to entering the GTK event loop, all primary "business" interface of the GUI + ** will be opened (currently as of 1/09 this is the interface gui::GuiNotification.) + ** @todo implement this! ** ** @see lumiera::AppState ** @see gui::GuiFacade ** @see guifacade.cpp - ** @see ///////////////////////////////////TODO: add link to the gui main routine here! + ** @see gui::GtkLumiera#main the GTK GUI main */ +#include "gui/gtk-lumiera.hpp" +#include "include/nobugcfg.h" +#include "lib/error.hpp" #include "gui/guifacade.hpp" #include "common/subsys.hpp" #include "lib/singleton.hpp" @@ -52,12 +58,7 @@ extern "C" { #include "common/interfacedescriptor.h" } -#include -using std::string; - -#include /////////////TODO -using std::cout; //////////////TODO using lumiera::Subsys; @@ -75,14 +76,30 @@ namespace gui { : public GuiFacade { - void kickOff (Subsys::SigTerm& terminationHandle) + void kickOff (Subsys::SigTerm& reportTermination) { - cout << " *** Ha Ha Ha\n" - << " this is the GuiStarterPlugin speaking!\n" - << " now, the Lumiera GUI should be spawned....\n" - << " but actually nothing happens!!!!!!!!!!!!!!\n\n"; - - terminationHandle(0); // signal immediate shutdown without error + try + { + int argc =0; /////////////////////////////////////////////////////////////////////////////TODO pass arguments from core + char *argv[] = {}; + + gui::application().main(argc, argv); // execute the GTK Event Loop + + if (!lumiera_error_peek()) + { + reportTermination(0); // report GUI shutdown without error + return; + } + } + catch (lumiera::Error& problem) + { + reportTermination(&problem); // signal shutdown reporting the error + return; + } + catch (...){ } + lumiera::error::Fatal problemIndicator("unexpected error terminated the GUI.", lumiera_error()); + reportTermination (&problemIndicator); + return; } }; From 8d4bc62fbe91dddfb25a1e520614aa907c0424eb Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 4 Jan 2009 15:21:04 +0100 Subject: [PATCH 21/35] WIP start drafting a better InterfaceProxy handling --- src/common/instancehandle.hpp | 2 +- src/common/interfaceproxy.cpp | 3 +- src/gui/guistart.cpp | 7 +- src/include/guinotificationfacade.h | 2 +- src/include/interfaceproxy.hpp | 107 ++++++++++++++++++++++++++++ src/lib/singletonsubclass.hpp | 8 +-- 6 files changed, 119 insertions(+), 10 deletions(-) create mode 100644 src/include/interfaceproxy.hpp diff --git a/src/common/instancehandle.hpp b/src/common/instancehandle.hpp index 78a46cbce..13a85bf97 100644 --- a/src/common/instancehandle.hpp +++ b/src/common/instancehandle.hpp @@ -161,7 +161,7 @@ namespace lumiera { * @note we don't provide operator* */ FA * operator-> () const { return accessFacade(); } - /** directly access the instance via the CLI interface */ + /** directly access the instance via the CL interface */ I& get () const { ENSURE(instance_); return *instance_; } diff --git a/src/common/interfaceproxy.cpp b/src/common/interfaceproxy.cpp index 6eb4b6c58..e486e3f60 100644 --- a/src/common/interfaceproxy.cpp +++ b/src/common/interfaceproxy.cpp @@ -21,7 +21,8 @@ * *****************************************************/ -#include "lib/singletonsubclass.hpp" +#include "include/interfaceproxy.hpp" +#include "lib/singletonsubclass.hpp" ////////////////////TODO #include "include/guinotificationfacade.h" #include "lib/util.hpp" #include "lib/error.hpp" diff --git a/src/gui/guistart.cpp b/src/gui/guistart.cpp index 4b9d28262..dbff558a4 100644 --- a/src/gui/guistart.cpp +++ b/src/gui/guistart.cpp @@ -70,7 +70,8 @@ namespace gui { namespace { // implementation details /** - * Implement the necessary steps for starting up the GUI main thread + * Implement the necessary steps for actually making the Lumiera Gui available. + * Open the business interface(s) and start up the GTK GUI main event loop. */ struct GuiFacadeImpl : public GuiFacade @@ -104,7 +105,7 @@ namespace gui { }; - lumiera::Singleton facade_; + lumiera::Singleton guiImplProvider_; } // (End) impl details @@ -197,7 +198,7 @@ extern "C" { /* ================== define an lumieraorg_Gui instance =========== , LUMIERA_INTERFACE_INLINE (kickOff, "\255\142\006\244\057\170\152\312\301\372\220\323\230\026\200\065", void, (void* termSig), { - gui::facade_().kickOff ( + gui::guiImplProvider_().kickOff ( *reinterpret_cast (termSig)); } ) diff --git a/src/include/guinotificationfacade.h b/src/include/guinotificationfacade.h index 1f176470a..916f0ddc4 100644 --- a/src/include/guinotificationfacade.h +++ b/src/include/guinotificationfacade.h @@ -83,7 +83,7 @@ namespace gui { extern "C" { -#endif /* =========================== CLI Interface ================= */ +#endif /* =========================== CL Interface ===================== */ #include "common/interface.h" diff --git a/src/include/interfaceproxy.hpp b/src/include/interfaceproxy.hpp new file mode 100644 index 000000000..46c61af73 --- /dev/null +++ b/src/include/interfaceproxy.hpp @@ -0,0 +1,107 @@ +/* + INTERFACEPROXY - definition of forwarding proxies for the facade interfaces + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + 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 interfaceproxy.hpp + ** Facade Interfaces Lifecycle. Communication between the Layers within Lumiera + ** usually is routed through Layer Separation Interfaces. These are comprised + ** of a Facade interface and a equivalent rendering as C Language interface defined + ** with the help of the Interface/Plugin system. But in order to be able to actually + ** access a service via this Facade, you need an instance of the interface. + ** + ** InterfaceProxy and InstanceHandle together are used to create such an concrete + ** instance of the Facade interface. It is implemented such as to route each call + ** through the corresponding C Language function defined in the Interface/Plugin system. + ** Typically there is another subclass of the Facade interfaces sitting "on the other side" + ** of the interface barrier and actually implementing the functionality. The template + ** InterfaceProxy can be thought of as a factory creating such a proxy instance of the + ** facade interface for the client code to use. Typically, in instance of the \em factory + ** is embedded (as a static functor member object) right within the otherwise abstract + ** facade interface, this way allowing the client code to write e.g. \c XYZInterface::facade() + ** to yield a reference to a proxy object implementing \c XYZInterface. + ** + ** Interface Lifecycle + ** + ** Instances of an Interface are either directly provided by some facility within the core, + ** or they are loaded from a shared module (plugin). In either case this means the interface + ** isn't accessible all the time, rather it comes up at a defined point in the application + ** lifecycle and similarly will be shut down deliberately at some point. Beyond this time + ** window of availability, any access through the proxy factory throws an lumiera::error::State. + ** Any sort of dependency management is outside the scope of the InterfaceProxy (for the core + ** services, it is handled by the dependency of subsystems, while the plugin loader cares + ** for dependency issues regarding loadable modules, thereby building on the deployment + ** descriptors. + ** + ** For the Layer separation interfaces, the process of loading and opening is abstracted as + ** an InstanceHandle object. When creating such an InstanceHandle using the appropriate + ** template and ctor parameters, in addition to the registration with the Interface/Plugin + ** system, the corresponding InterfaceProxy factory is addressed and "opened" by creating + ** the right proxy object instance. Similarly, when the InstanceHandle object goes out + ** of scope, prior to detaching from the Interface/Proxy system, the corresponding + ** InterfaceProxy factory is "closed", which means destroying the proxy object instance + ** and switching any further access to throwing and exception. + ** + ** While client code just includes the interface header (including interfaceproxy.hpp + ** in turn), there needs to be an actual implementation of each proxy object located in + ** some translation unit. The usual place is interfaceproxy.cpp, which gets linked into + ** \c liblumieracommon.so and contains actual specialisations and literal forwarding + ** code for each individual facade. + ** + ** @see interface.h + ** @see plugin.h + ** @see lumiera::Subsys + ** @see guinotification.h usage example (facade interface) + ** @see guinotificationfacade.cpp corresponding implementation within the GUI + */ + + +#ifndef LUMIERA_INTERFACE_PROXY_H +#define LUMIERA_INTERFACE_PROXY_H + + + +#include + + +namespace lumiera { + + using std::string; + + + /********************************************************************* + * + */ + template + class InterfaceProxy + { + + friend class lumiera::InstanceHandle;/////////////TODO use an abstraction here! + + public: + + + + }; + + + +} // namespace lumiera +#endif diff --git a/src/lib/singletonsubclass.hpp b/src/lib/singletonsubclass.hpp index b5ce47184..bfac1c734 100644 --- a/src/lib/singletonsubclass.hpp +++ b/src/lib/singletonsubclass.hpp @@ -21,14 +21,14 @@ */ /** @file singletonsubclass.hpp - ** Spezialized SingletonFactory creating sublcasses of the nominal type. + ** Specialised SingletonFactory creating subclasses of the nominal type. ** The rationale is to be able to defer the decision what type to create - ** down to the point where the singleton factory is actualy created. + ** down to the point where the singleton factory is actually created. ** Thus the code using the singleton need not know the implementation ** class, but nevertheless gets an non-virtual access function to the ** singleton instance (which can be inlined), and the compiler is ** still able to spot type errors. Maybe someone knows a less - ** contrieved solution fulfilling the same criteria....? + ** contrived solution fulfilling the same criteria....? ** ** @see configrules.cpp usage example ** @see SingletonSubclass_test @@ -63,7 +63,7 @@ namespace lumiera { struct Link { virtual ~Link() {} - virtual I* create () = 0; ///< @note compiler will check the actual type is assignable... + virtual I* create () = 0; ///< @note compiler will check if the actual type is assignable... virtual void destroy (I* pSi) = 0; }; From 31a112acaa32a1aeb6c1a77e36e510c396945174 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 5 Jan 2009 16:17:17 +0100 Subject: [PATCH 22/35] some typos --- src/proc/asset/proc.hpp | 6 +++--- src/proc/asset/struct.cpp | 5 ++--- src/proc/asset/struct.hpp | 6 +++--- src/proc/asset/structfactoryimpl.hpp | 2 +- src/proc/assetmanager.cpp | 23 +++++++++++++---------- src/proc/mobject/session/defsmanager.cpp | 14 +++++++------- 6 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/proc/asset/proc.hpp b/src/proc/asset/proc.hpp index 5ab69dfc9..9b744f2e1 100644 --- a/src/proc/asset/proc.hpp +++ b/src/proc/asset/proc.hpp @@ -42,8 +42,8 @@ -namespace asset - { +namespace asset { + class Proc; class ProcFactory; @@ -92,7 +92,7 @@ namespace asset /** - * Factory specialized for createing Processor Asset objects. + * Factory specialised for creating Processor Asset objects. */ class ProcFactory : public lumiera::Factory { diff --git a/src/proc/asset/struct.cpp b/src/proc/asset/struct.cpp index 71ffa995f..e92fa0bb9 100644 --- a/src/proc/asset/struct.cpp +++ b/src/proc/asset/struct.cpp @@ -82,7 +82,7 @@ namespace asset /** Factory method for Structural Asset instances. - * First tries to relove the asset by issuing an capability query. + * First tries to resolve the asset by issuing an capability query. * If unsuccessful, use some internally specialised ctor call. * @todo work out the struct asset naming scheme! * @return an Struct smart ptr linked to the internally registered smart ptr @@ -144,8 +144,7 @@ namespace asset #include "proc/asset/pipe.hpp" -namespace asset - { +namespace asset { template P StructFactory::operator() (const Query& query); template P StructFactory::operator() (const Query& query); diff --git a/src/proc/asset/struct.hpp b/src/proc/asset/struct.hpp index a7a1df437..07efca7e0 100644 --- a/src/proc/asset/struct.hpp +++ b/src/proc/asset/struct.hpp @@ -49,8 +49,8 @@ -namespace asset - { +namespace asset { + using std::string; using std::wstring; using boost::scoped_ptr; @@ -108,7 +108,7 @@ namespace asset /** - * Factory specialized for createing Structural Asset objects. + * Factory specialised for creating Structural Asset objects. */ class StructFactory : public lumiera::Factory { diff --git a/src/proc/asset/structfactoryimpl.hpp b/src/proc/asset/structfactoryimpl.hpp index 497f84791..f39d41b05 100644 --- a/src/proc/asset/structfactoryimpl.hpp +++ b/src/proc/asset/structfactoryimpl.hpp @@ -79,7 +79,7 @@ namespace asset /** - * Implementation deatils, esp. concerning how configuration + * Implementation details, especially concerning how configuration * queries are resolved and when to create new objects automatically. * @todo better use a general struct traits class, esp.for creating the Ident */ diff --git a/src/proc/assetmanager.cpp b/src/proc/assetmanager.cpp index 0aaa26c0e..6c46e9b6a 100644 --- a/src/proc/assetmanager.cpp +++ b/src/proc/assetmanager.cpp @@ -183,16 +183,19 @@ namespace asset { } - void - recursive_call (AssetManager* instance, PAsset& pA) - { - instance->remove (pA->getID()); - } - - function - detach_child_recursively () ///< @return a functor recursively invoking remove(child) - { - return bind( &recursive_call, &AssetManager::instance(), _1 ); + namespace { // details implementing AssetManager::remove + + void + recursive_call (AssetManager* instance, PAsset& pA) + { + instance->remove (pA->getID()); + } + + function + detach_child_recursively () ///< @return a functor recursively invoking remove(child) + { + return bind( &recursive_call, &AssetManager::instance(), _1 ); + } } /** diff --git a/src/proc/mobject/session/defsmanager.cpp b/src/proc/mobject/session/defsmanager.cpp index f7a40de13..38509c981 100644 --- a/src/proc/mobject/session/defsmanager.cpp +++ b/src/proc/mobject/session/defsmanager.cpp @@ -42,7 +42,7 @@ namespace mobject { - /** initialize the most basic internal defaults. */ + /** initialise the most basic internal defaults. */ DefsManager::DefsManager () throw() : defsRegistry(new DefsRegistry) { @@ -142,11 +142,10 @@ namespace mobject { #include "proc/asset/track.hpp" #include "proc/mobject/session/track.hpp" -namespace mobject - { - namespace session - { - +namespace mobject { + namespace session { + + using asset::Pipe; using asset::PPipe; using asset::ProcPatt; @@ -164,7 +163,8 @@ namespace mobject template bool DefsManager::define (const PPipe&, const Query&); template bool DefsManager::forget (const PPipe&); - + + } // namespace mobject::session } // namespace mobject From 57ca80c2fc49b10edd582e1821444ce09f7b1ddc Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 5 Jan 2009 16:17:53 +0100 Subject: [PATCH 23/35] WIP continued drafting... --- src/include/interfaceproxy.hpp | 63 ++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/src/include/interfaceproxy.hpp b/src/include/interfaceproxy.hpp index 46c61af73..14b5e51ad 100644 --- a/src/include/interfaceproxy.hpp +++ b/src/include/interfaceproxy.hpp @@ -90,18 +90,77 @@ namespace lumiera { * */ template - class InterfaceProxy + class FacadeAccessor { + FA* insta_; - friend class lumiera::InstanceHandle;/////////////TODO use an abstraction here! public: + FA& + operator() () + { + if (insta_) + return *insta_; + else + throw error::State("Facade interface currently closed."); + } + }; + + template + class Holder + { + static IMP& open() + { + static char buff[sizeof(IMP)]; + IMP* p = new(buff) IMP(); + insta_ = p; + return *p; + } + template + static void close() + { + IMP* p = static_cast (insta_); + insta_ = 0; + p->~IMP(); + } }; + template + class Proxy; + template + class Mixi; + + template + class Mixi > + : Holder >, + public FA + { + I* _i_; + public: + void setupInterface(I& interface) { _i_ = &interface; } + + }; + + class XYZ; + + template<> + class Proxy + : public Mixi + { + + }; + + template + void + pullUp (InstanceHandle& iha) + { + Proxy >::open().setupInterface(iha.get()); + + } } // namespace lumiera #endif From 8a40075ee8fa701bb0bf3cf223141e5ae121555f Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 6 Jan 2009 06:09:46 +0100 Subject: [PATCH 24/35] WIP expand on this draft to build a prospective solution --- src/common/instancehandle.hpp | 2 +- src/include/interfaceproxy.hpp | 109 ++++++++++++++++++++++++--------- 2 files changed, 80 insertions(+), 31 deletions(-) diff --git a/src/common/instancehandle.hpp b/src/common/instancehandle.hpp index 13a85bf97..b2a6e9ffd 100644 --- a/src/common/instancehandle.hpp +++ b/src/common/instancehandle.hpp @@ -40,6 +40,7 @@ #include "include/nobugcfg.h" +#include "lib/error.hpp" extern "C" { #include "common/interface.h" @@ -55,7 +56,6 @@ extern "C" { namespace lumiera { using std::string; -// using boost::scoped_ptr; namespace { // implementation details diff --git a/src/include/interfaceproxy.hpp b/src/include/interfaceproxy.hpp index 14b5e51ad..2b2396fe9 100644 --- a/src/include/interfaceproxy.hpp +++ b/src/include/interfaceproxy.hpp @@ -77,6 +77,7 @@ #define LUMIERA_INTERFACE_PROXY_H +#include "lib/error.hpp" #include @@ -92,74 +93,122 @@ namespace lumiera { template class FacadeAccessor { - FA* insta_; + protected: + static FA* implProxy_; public: FA& operator() () { - if (insta_) - return *insta_; + if (implProxy_) + return *implProxy_; else throw error::State("Facade interface currently closed."); } }; - template - class Holder + template + void openProxy (IHA& iha); + + template + void closeProxy (IHA& iha); + + template + class Proxy; + +} + +#include "common/instancehandle.hpp" + +namespace lumiera { + + template + class Holder; + + template + class Holder > + : FacadeAccessor, + protected FA { - static IMP& open() + protected: + typedef InstanceHandle IHandle; + typedef FacadeAccessor Access; + typedef Holder THolder; + typedef Proxy Proxy; + + static Proxy& open(IHandle& iha) { - static char buff[sizeof(IMP)]; - IMP* p = new(buff) IMP(); - insta_ = p; + static char buff[sizeof(Proxy)]; + Proxy* p = new(buff) Proxy(iha); + Access::implProxy_ = p; return *p; } - template static void close() { - IMP* p = static_cast (insta_); - insta_ = 0; - p->~IMP(); + if (!Access::implProxy_) return; + Proxy* p = static_cast (Access::implProxy_); + Access::implProxy_ = 0; + p->~Proxy(); } + I& _i_; + + Holder (IHandle& iha) + : _i_(iha.get()) + { } + }; + template - class Proxy; + FA* FacadeAccessor::implProxy_; - template - class Mixi; - template - class Mixi > - : Holder >, - public FA + struct XYZ { - I* _i_; - public: - void setupInterface(I& interface) { _i_ = &interface; } + virtual ~XYZ(){} + virtual int zoing(int i) =0; }; - class XYZ; + struct II {}; + typedef InstanceHandle IIXYZ; + + template<> - class Proxy - : public Mixi + class Proxy + : public Holder { + //----Proxy-Implementation-of-XYZ-------- + virtual int + zoing (int i) + { + return (rand() % i); + } + + + public: + Proxy (IHandle iha) : THolder(iha) {} }; - template + + template void - pullUp (InstanceHandle& iha) + openProxy (IHA& iha) { - Proxy >::open().setupInterface(iha.get()); - + Proxy::open(iha); + } + + template + void + closeProxy (IHA& iha) + { + Proxy::close(); } } // namespace lumiera From afcea26399dc68eb76ee61b6747d12caa7a07251 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 6 Jan 2009 06:15:36 +0100 Subject: [PATCH 25/35] wrap into additional namespace lumiera::facade --- src/include/interfaceproxy.hpp | 242 +++++++++++++++++---------------- 1 file changed, 124 insertions(+), 118 deletions(-) diff --git a/src/include/interfaceproxy.hpp b/src/include/interfaceproxy.hpp index 2b2396fe9..065fb1163 100644 --- a/src/include/interfaceproxy.hpp +++ b/src/include/interfaceproxy.hpp @@ -79,137 +79,143 @@ #include "lib/error.hpp" -#include namespace lumiera { - - using std::string; + namespace facade { - /********************************************************************* - * - */ - template - class FacadeAccessor - { - protected: - static FA* implProxy_; - - - public: - FA& - operator() () - { - if (implProxy_) - return *implProxy_; - else - throw error::State("Facade interface currently closed."); - } - }; + /********************************************************************* + * + */ + template + class Accessor + { + protected: + static FA* implProxy_; + + + public: + FA& + operator() () + { + if (implProxy_) + return *implProxy_; + else + throw error::State("Facade interface currently closed."); + } + }; + + template + void openProxy (IHA& iha); + + template + void closeProxy (IHA& iha); + + template + class Proxy; + + + } // namespace facade - template - void openProxy (IHA& iha); - - template - void closeProxy (IHA& iha); - - template - class Proxy; - -} +} // namespace lumiera #include "common/instancehandle.hpp" namespace lumiera { - - template - class Holder; - - template - class Holder > - : FacadeAccessor, - protected FA - { - protected: - typedef InstanceHandle IHandle; - typedef FacadeAccessor Access; - typedef Holder THolder; - typedef Proxy Proxy; - - static Proxy& open(IHandle& iha) - { - static char buff[sizeof(Proxy)]; - Proxy* p = new(buff) Proxy(iha); - Access::implProxy_ = p; - return *p; - } - - static void close() - { - if (!Access::implProxy_) return; - Proxy* p = static_cast (Access::implProxy_); - Access::implProxy_ = 0; - p->~Proxy(); - } - - - I& _i_; - - Holder (IHandle& iha) - : _i_(iha.get()) - { } - - }; + namespace facade { - template - FA* FacadeAccessor::implProxy_; + template + class Holder; + + template + class Holder > + : Accessor, + protected FA + { + protected: + typedef InstanceHandle IHandle; + typedef Holder THolder; + typedef Proxy Proxy; + typedef Accessor Access; + + static Proxy& open(IHandle& iha) + { + static char buff[sizeof(Proxy)]; + Proxy* p = new(buff) Proxy(iha); + Access::implProxy_ = p; + return *p; + } + + static void close() + { + if (!Access::implProxy_) return; + Proxy* p = static_cast (Access::implProxy_); + Access::implProxy_ = 0; + p->~Proxy(); + } + + + I& _i_; + + Holder (IHandle& iha) + : _i_(iha.get()) + { } + + }; + + + template + FA* Accessor::implProxy_; + + + struct XYZ + { + virtual ~XYZ(){} + + virtual int zoing(int i) =0; + }; + + struct II {}; - - struct XYZ - { - virtual ~XYZ(){} - - virtual int zoing(int i) =0; - }; - - struct II {}; - - typedef InstanceHandle IIXYZ; - - - template<> - class Proxy - : public Holder - { - //----Proxy-Implementation-of-XYZ-------- - - virtual int - zoing (int i) - { - return (rand() % i); - } - - - public: - Proxy (IHandle iha) : THolder(iha) {} - }; - - - template - void - openProxy (IHA& iha) - { - Proxy::open(iha); - } - - template - void - closeProxy (IHA& iha) - { - Proxy::close(); - } + typedef InstanceHandle IIXYZ; + + + template<> + class Proxy + : public Holder + { + //----Proxy-Implementation-of-XYZ-------- + + virtual int + zoing (int i) + { + return (rand() % i); + } + + + public: + Proxy (IHandle iha) : THolder(iha) {} + }; + + + template + void + openProxy (IHA& iha) + { + Proxy::open(iha); + } + + template + void + closeProxy (IHA& iha) + { + Proxy::close(); + } + + + } // namespace facade } // namespace lumiera #endif From 24fe4bcb703c1d12af0f99931ac35347d076c8c0 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 6 Jan 2009 06:18:13 +0100 Subject: [PATCH 26/35] separate and hide away implementation part into common/interfaceproxy.cpp --- src/common/interfaceproxy.cpp | 99 ++++++++++++++++++++++++++++++++++ src/include/interfaceproxy.hpp | 98 --------------------------------- 2 files changed, 99 insertions(+), 98 deletions(-) diff --git a/src/common/interfaceproxy.cpp b/src/common/interfaceproxy.cpp index e486e3f60..0aff8f5cd 100644 --- a/src/common/interfaceproxy.cpp +++ b/src/common/interfaceproxy.cpp @@ -84,3 +84,102 @@ namespace gui { } // namespace gui + +#include "common/instancehandle.hpp" + +namespace lumiera { + namespace facade { + + + template + class Holder; + + template + class Holder > + : Accessor, + protected FA + { + protected: + typedef InstanceHandle IHandle; + typedef Holder THolder; + typedef Proxy Proxy; + typedef Accessor Access; + + static Proxy& open(IHandle& iha) + { + static char buff[sizeof(Proxy)]; + Proxy* p = new(buff) Proxy(iha); + Access::implProxy_ = p; + return *p; + } + + static void close() + { + if (!Access::implProxy_) return; + Proxy* p = static_cast (Access::implProxy_); + Access::implProxy_ = 0; + p->~Proxy(); + } + + + I& _i_; + + Holder (IHandle& iha) + : _i_(iha.get()) + { } + + }; + + + template + FA* Accessor::implProxy_; + + + struct XYZ + { + virtual ~XYZ(){} + + virtual int zoing(int i) =0; + }; + + struct II {}; + + typedef InstanceHandle IIXYZ; + + + template<> + class Proxy + : public Holder + { + //----Proxy-Implementation-of-XYZ-------- + + virtual int + zoing (int i) + { + return (rand() % i); + } + + + public: + Proxy (IHandle iha) : THolder(iha) {} + }; + + + template + void + openProxy (IHA& iha) + { + Proxy::open(iha); + } + + template + void + closeProxy (IHA& iha) + { + Proxy::close(); + } + + + } // namespace facade + +} // namespace lumiera diff --git a/src/include/interfaceproxy.hpp b/src/include/interfaceproxy.hpp index 065fb1163..03c3b071a 100644 --- a/src/include/interfaceproxy.hpp +++ b/src/include/interfaceproxy.hpp @@ -120,102 +120,4 @@ namespace lumiera { } // namespace lumiera -#include "common/instancehandle.hpp" - -namespace lumiera { - namespace facade { - - - template - class Holder; - - template - class Holder > - : Accessor, - protected FA - { - protected: - typedef InstanceHandle IHandle; - typedef Holder THolder; - typedef Proxy Proxy; - typedef Accessor Access; - - static Proxy& open(IHandle& iha) - { - static char buff[sizeof(Proxy)]; - Proxy* p = new(buff) Proxy(iha); - Access::implProxy_ = p; - return *p; - } - - static void close() - { - if (!Access::implProxy_) return; - Proxy* p = static_cast (Access::implProxy_); - Access::implProxy_ = 0; - p->~Proxy(); - } - - - I& _i_; - - Holder (IHandle& iha) - : _i_(iha.get()) - { } - - }; - - - template - FA* Accessor::implProxy_; - - - struct XYZ - { - virtual ~XYZ(){} - - virtual int zoing(int i) =0; - }; - - struct II {}; - - typedef InstanceHandle IIXYZ; - - - template<> - class Proxy - : public Holder - { - //----Proxy-Implementation-of-XYZ-------- - - virtual int - zoing (int i) - { - return (rand() % i); - } - - - public: - Proxy (IHandle iha) : THolder(iha) {} - }; - - - template - void - openProxy (IHA& iha) - { - Proxy::open(iha); - } - - template - void - closeProxy (IHA& iha) - { - Proxy::close(); - } - - - } // namespace facade - -} // namespace lumiera #endif From 635b9441f458492f88364201525b5c73e04d45aa Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 6 Jan 2009 06:40:44 +0100 Subject: [PATCH 27/35] WIP rewrite the existing solution for the GuiNotification facade using this new approach (not functional yet, because laci of automatic integration with InstanceHandle. --- src/common/interfaceproxy.cpp | 132 +++++++++------------------- src/include/guinotificationfacade.h | 4 +- 2 files changed, 43 insertions(+), 93 deletions(-) diff --git a/src/common/interfaceproxy.cpp b/src/common/interfaceproxy.cpp index 0aff8f5cd..dd4674dcd 100644 --- a/src/common/interfaceproxy.cpp +++ b/src/common/interfaceproxy.cpp @@ -22,70 +22,24 @@ #include "include/interfaceproxy.hpp" -#include "lib/singletonsubclass.hpp" ////////////////////TODO -#include "include/guinotificationfacade.h" -#include "lib/util.hpp" +#include "common/instancehandle.hpp" #include "lib/error.hpp" - -extern "C" { -#include "common/interface.h" -} +#include "lib/util.hpp" using util::cStr; -namespace singleton = lumiera::singleton; +#include "include/guinotificationfacade.h" namespace gui { - - class GuiNotificationInterfaceProxy - : public GuiNotification - { - LUMIERA_INTERFACE_INAME(lumieraorg_GuiNotification, 1) * interface_; - - GuiNotificationInterfaceProxy () - { - interface_ = LUMIERA_INTERFACE_OPEN (lumieraorg_GuiNotification, 1, 2, lumieraorg_GuiNotificationFacade); - if (!interface_) - throw lumiera::error::State ("unable to access GuiNotificationFacade"); - } - - friend class singleton::StaticCreate; - - - - /* ======== forwarding through interface ========== */ - - void - displayInfo (string const& text) - { - interface_->displayInfo (cStr(text)); - } - - void - triggerGuiShutdown (string const& cause) - { - interface_->triggerGuiShutdown (cStr(cause)); - } - - - }; - - namespace { - - singleton::UseSubclass typeinfo_proxyInstance_to_create; - } /** storage for the facade proxy factory used by client code to invoke through the interface */ - lumiera::SingletonSub GuiNotification::facade (typeinfo_proxyInstance_to_create); - - ///////////////////////////////////////TODO: this solution is not correct, because it doesn't detect when the interface is shut down! - - + lumiera::facade::Accessor GuiNotification::facade; } // namespace gui -#include "common/instancehandle.hpp" + + namespace lumiera { namespace facade { @@ -105,6 +59,13 @@ namespace lumiera { typedef Proxy Proxy; typedef Accessor Access; + I& _i_; + + Holder (IHandle& iha) + : _i_(iha.get()) + { } + + public: static Proxy& open(IHandle& iha) { static char buff[sizeof(Proxy)]; @@ -120,14 +81,6 @@ namespace lumiera { Access::implProxy_ = 0; p->~Proxy(); } - - - I& _i_; - - Holder (IHandle& iha) - : _i_(iha.get()) - { } - }; @@ -135,36 +88,6 @@ namespace lumiera { FA* Accessor::implProxy_; - struct XYZ - { - virtual ~XYZ(){} - - virtual int zoing(int i) =0; - }; - - struct II {}; - - typedef InstanceHandle IIXYZ; - - - template<> - class Proxy - : public Holder - { - //----Proxy-Implementation-of-XYZ-------- - - virtual int - zoing (int i) - { - return (rand() % i); - } - - - public: - Proxy (IHandle iha) : THolder(iha) {} - }; - - template void openProxy (IHA& iha) @@ -174,12 +97,39 @@ namespace lumiera { template void - closeProxy (IHA& iha) + closeProxy (IHA&) { Proxy::close(); } + + typedef InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_GuiNotification, 1) + , gui::GuiNotification + > Handle_GuiNotification; + + + template<> + class Proxy + : public Holder + { + //----Proxy-Implementation-of-GuiNotification-------- + + void displayInfo (string const& text) { _i_.displayInfo (cStr(text)); } + void triggerGuiShutdown (string const& cause) { _i_.triggerGuiShutdown (cStr(cause)); } + + + public: + Proxy (IHandle& iha) : THolder(iha) {} + }; + + + + + template void openProxy (Handle_GuiNotification&); + template void closeProxy (Handle_GuiNotification&); + + } // namespace facade } // namespace lumiera diff --git a/src/include/guinotificationfacade.h b/src/include/guinotificationfacade.h index 916f0ddc4..648839f50 100644 --- a/src/include/guinotificationfacade.h +++ b/src/include/guinotificationfacade.h @@ -40,7 +40,7 @@ #ifdef __cplusplus /* ============== C++ Interface ================= */ -#include "lib/singletonsubclass.hpp" +#include "include/interfaceproxy.hpp" #include @@ -63,7 +63,7 @@ namespace gui { class GuiNotification { public: - static lumiera::SingletonSub facade; + static lumiera::facade::Accessor facade; /** push a user visible notification text */ virtual void displayInfo (string const& text) =0; From 4ffa60161ba69eac7c24d63a1c8d31df0fd87fd8 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 7 Jan 2009 12:26:44 +0100 Subject: [PATCH 28/35] Integration with InstanceHandle --- src/common/instancehandle.hpp | 88 +++++++++++++++++++++++++++------- src/common/interfaceproxy.cpp | 14 +++--- src/include/interfaceproxy.hpp | 16 +++---- 3 files changed, 86 insertions(+), 32 deletions(-) diff --git a/src/common/instancehandle.hpp b/src/common/instancehandle.hpp index b2a6e9ffd..467870609 100644 --- a/src/common/instancehandle.hpp +++ b/src/common/instancehandle.hpp @@ -31,7 +31,9 @@ ** ** @see gui::GuiFacade usage example ** @see interface.h - ** @see interfaceproxy.cpp + ** @see interfaceproxy.hpp (more explanations) + ** @see interfaceproxy.cpp (Implementation of the proxies) + ** */ @@ -41,6 +43,7 @@ #include "include/nobugcfg.h" #include "lib/error.hpp" +#include "include/interfaceproxy.hpp" extern "C" { #include "common/interface.h" @@ -48,7 +51,6 @@ extern "C" { } #include -//#include #include @@ -57,6 +59,10 @@ namespace lumiera { using std::string; + template + class InstanceHandle; + + namespace { // implementation details void @@ -96,16 +102,69 @@ namespace lumiera { ifa->name)); } + + /** + * @internal Helper/Adapter for establishing a link + * between an InstanceHandle and a facade interface, + * which is going to be implemented through the given + * interface/plugin. This way, creating the InstanceHandle + * automatically creates a lumiera::facade::Proxy, to route + * any facade calls through the interface/plugin. Similarly, + * when destroying the InstanceHandle, the proxy will be closed. + */ + template + struct FacadeLink + : boost::noncopyable + { + typedef InstanceHandle IH; + + FacadeLink (IH const& iha) { facade::openProxy(iha); } + ~FacadeLink() { facade::closeProxy(); } + + FA& + operator() (IH const&) const + { + return facade::Accessor()(); + } + }; + + + /** + * @internal when the InstanceHandle isn't associated with a + * facade interface, then this specialisation switches + * the FacadeLink into "NOP" mode. + */ + template + struct FacadeLink + : boost::noncopyable + { + typedef InstanceHandle IH; + + FacadeLink (IH const&) { /* NOP */ } + ~FacadeLink() { /* NOP */ } + + I& + operator() (IH const& handle) const + { + return handle.get(); + } + }; + } // (End) impl details + + /** * Handle tracking the registration of an interface, deregistering it on deletion. * Depending on which flavour of the ctor is used, either (bulk) registration of interfaces * or plugin loading is triggered. The interface type is defined by type parameter. - * @todo when provided with the type of an facade interface class, care for enabling/disabling - * access through the facade proxy singleton when opening/closing the registration. + * Additionally, choosing a facade interface as second type parameter causes installation + * of a proxy, which implements the facade by routing calls through the basic interface + * represented by this handle. This proxy will be "closed" automatically when this + * InstanceHandle goes out of scope. Of course, the proxy needs to be implemented + * somewhere, typically in interfaceproxy.cpp */ template< class I ///< fully mangled name of the interface type , class FA = I ///< facade interface type to be used by clients @@ -115,6 +174,7 @@ namespace lumiera { { LumieraInterface* desc_; I* instance_; + FacadeLink facadeLink_; typedef InstanceHandle _ThisType; @@ -127,9 +187,10 @@ namespace lumiera { * @param impName unmangled name of the instance (implementation) */ InstanceHandle (string const& iName, uint version, size_t minminor, string const& impName) - : desc_(0), - instance_(reinterpret_cast + : desc_(0) + , instance_(reinterpret_cast (lumiera_interface_open (iName.c_str(), version, minminor, impName.c_str()))) + , facadeLink_(*this) { throwIfError(); } @@ -141,8 +202,9 @@ namespace lumiera { * usually available through lumiera_plugin_interfaces() */ InstanceHandle (LumieraInterface* descriptors) - : desc_(descriptors), - instance_(reinterpret_cast (register_and_open (desc_))) + : desc_(descriptors) + , instance_(reinterpret_cast (register_and_open (desc_))) + , facadeLink_(*this) { throwIfError(); } @@ -157,9 +219,8 @@ namespace lumiera { /** act as smart pointer providing access through the facade. - * @todo implement the case where the Facade differs from I * @note we don't provide operator* */ - FA * operator-> () const { return accessFacade(); } + FA * operator-> () const { return &(facadeLink_(*this)); } /** directly access the instance via the CL interface */ I& get () const { ENSURE(instance_); return *instance_; } @@ -176,13 +237,6 @@ namespace lumiera { private: - FA * - accessFacade() const - { - ENSURE (instance_); - return static_cast (instance_); /////////////////TODO: actually handle the case when the facade differs from the interface by using the proxy - } - bool isValid() const { diff --git a/src/common/interfaceproxy.cpp b/src/common/interfaceproxy.cpp index dd4674dcd..121c50929 100644 --- a/src/common/interfaceproxy.cpp +++ b/src/common/interfaceproxy.cpp @@ -61,12 +61,12 @@ namespace lumiera { I& _i_; - Holder (IHandle& iha) + Holder (IHandle const& iha) : _i_(iha.get()) { } public: - static Proxy& open(IHandle& iha) + static Proxy& open(IHandle const& iha) { static char buff[sizeof(Proxy)]; Proxy* p = new(buff) Proxy(iha); @@ -90,14 +90,14 @@ namespace lumiera { template void - openProxy (IHA& iha) + openProxy (IHA const& iha) { Proxy::open(iha); } template void - closeProxy (IHA&) + closeProxy () { Proxy::close(); } @@ -120,14 +120,14 @@ namespace lumiera { public: - Proxy (IHandle& iha) : THolder(iha) {} + Proxy (IHandle const& iha) : THolder(iha) {} }; - template void openProxy (Handle_GuiNotification&); - template void closeProxy (Handle_GuiNotification&); + template void openProxy (Handle_GuiNotification const&); + template void closeProxy (void); } // namespace facade diff --git a/src/include/interfaceproxy.hpp b/src/include/interfaceproxy.hpp index 03c3b071a..cb8da0d92 100644 --- a/src/include/interfaceproxy.hpp +++ b/src/include/interfaceproxy.hpp @@ -27,12 +27,12 @@ ** with the help of the Interface/Plugin system. But in order to be able to actually ** access a service via this Facade, you need an instance of the interface. ** - ** InterfaceProxy and InstanceHandle together are used to create such an concrete + ** lumiera::facade::Proxy and InstanceHandle together are used to create such an concrete ** instance of the Facade interface. It is implemented such as to route each call ** through the corresponding C Language function defined in the Interface/Plugin system. ** Typically there is another subclass of the Facade interfaces sitting "on the other side" ** of the interface barrier and actually implementing the functionality. The template - ** InterfaceProxy can be thought of as a factory creating such a proxy instance of the + ** facade::Accessor can be thought of as a factory creating such a proxy instance of the ** facade interface for the client code to use. Typically, in instance of the \em factory ** is embedded (as a static functor member object) right within the otherwise abstract ** facade interface, this way allowing the client code to write e.g. \c XYZInterface::facade() @@ -45,7 +45,7 @@ ** isn't accessible all the time, rather it comes up at a defined point in the application ** lifecycle and similarly will be shut down deliberately at some point. Beyond this time ** window of availability, any access through the proxy factory throws an lumiera::error::State. - ** Any sort of dependency management is outside the scope of the InterfaceProxy (for the core + ** Any sort of dependency management is outside the scope of the InstanceHandle (for the core ** services, it is handled by the dependency of subsystems, while the plugin loader cares ** for dependency issues regarding loadable modules, thereby building on the deployment ** descriptors. @@ -53,11 +53,11 @@ ** For the Layer separation interfaces, the process of loading and opening is abstracted as ** an InstanceHandle object. When creating such an InstanceHandle using the appropriate ** template and ctor parameters, in addition to the registration with the Interface/Plugin - ** system, the corresponding InterfaceProxy factory is addressed and "opened" by creating + ** system, the corresponding facade::Proxy factory is addressed and "opened" by creating ** the right proxy object instance. Similarly, when the InstanceHandle object goes out ** of scope, prior to detaching from the Interface/Proxy system, the corresponding - ** InterfaceProxy factory is "closed", which means destroying the proxy object instance - ** and switching any further access to throwing and exception. + ** lumiera::facade::Accessor factory is "closed", which additionally means destroying + ** the proxy object instance and switching any further access to throwing and exception. ** ** While client code just includes the interface header (including interfaceproxy.hpp ** in turn), there needs to be an actual implementation of each proxy object located in @@ -107,10 +107,10 @@ namespace lumiera { }; template - void openProxy (IHA& iha); + void openProxy (IHA const&); template - void closeProxy (IHA& iha); + void closeProxy (); template class Proxy; From 3da958682405e3470253d2bb94dc9fe6306d917e Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 10 Jan 2009 15:29:11 +0100 Subject: [PATCH 29/35] Rewrite the GuiNotification service to operate in sync with bringing up the GUI --- src/common/guifacade.cpp | 4 + src/common/instancehandle.hpp | 34 ++--- src/common/interfaceproxy.cpp | 3 + src/gui/guistart.cpp | 57 +++++--- ...ionfacade.cpp => notification-service.cpp} | 84 +++++++---- src/gui/notification-service.hpp | 91 ++++++++++++ src/include/guinotificationfacade.h | 15 +- src/include/interfaceproxy.hpp | 3 + src/lib/singleton-ref.hpp | 131 ++++++++++++++++++ src/proc/facade.hpp | 15 +- 10 files changed, 354 insertions(+), 83 deletions(-) rename src/gui/{guinotificationfacade.cpp => notification-service.cpp} (81%) create mode 100644 src/gui/notification-service.hpp create mode 100644 src/lib/singleton-ref.hpp diff --git a/src/common/guifacade.cpp b/src/common/guifacade.cpp index d803cecc3..2fb76dcc1 100644 --- a/src/common/guifacade.cpp +++ b/src/common/guifacade.cpp @@ -66,6 +66,10 @@ namespace gui { if (lumiera_error_peek()) throw lumiera::error::Fatal("failed to bring up GUI",lumiera_error()); + + ///////////////////////////////////////////////////////TODO: just a test to verify the GuiNotification facade is properly opened + GuiNotification::facade().displayInfo("Test-Notification message pushed to GUI!!!!"); + ///////////////////////////////////////////////////////TODO: just a test to verify the GuiNotification facade is properly opened } ~GuiRunner () { } diff --git a/src/common/instancehandle.hpp b/src/common/instancehandle.hpp index 467870609..513a7607e 100644 --- a/src/common/instancehandle.hpp +++ b/src/common/instancehandle.hpp @@ -72,22 +72,22 @@ namespace lumiera { throw lumiera::error::Config("failed to open interface or plugin.",lumiera_error()); } - /** takes a bunch of instance definitions, as typically created - * when defining interfaces for external use, and registers them + /** takes a (single) instance definitions, as typically created + * when defining interfaces for external use, and registers it * with the InterfaceSystem. Then uses the data found in the - * \em first descriptor to open an instance handle. + * \em given instance descriptor to open an instance handle. + * @throws error::Config when the registration process fails */ LumieraInterface - register_and_open (LumieraInterface* descriptors) + register_and_open (LumieraInterface descriptor) { - if (!descriptors) return NULL; - lumiera_interfaceregistry_bulkregister_interfaces (descriptors, NULL); + if (!descriptor) return NULL; + lumiera_interfaceregistry_register_interface (descriptor, NULL); throwIfError(); - LumieraInterface masterI = descriptors[0]; - return lumiera_interface_open (masterI->interface, - masterI->version, - masterI->size, - masterI->name); + return lumiera_interface_open (descriptor->interface, + descriptor->version, + descriptor->size, + descriptor->name); } /** do a lookup within the interfaceregistry @@ -172,7 +172,7 @@ namespace lumiera { class InstanceHandle : private boost::noncopyable { - LumieraInterface* desc_; + LumieraInterface desc_; I* instance_; FacadeLink facadeLink_; @@ -198,11 +198,11 @@ namespace lumiera { /** Set up an InstanceHandle managing the * registration and deregistration of interface(s). * Should be placed at the service providing side. - * @param descriptors zero terminated array of interface descriptors, - * usually available through lumiera_plugin_interfaces() + * @param a (single) interface descriptor, which can be created with + * LUMIERA_INTERFACE_INSTANCE and referred to by LUMIERA_INTERFACE_REF */ - InstanceHandle (LumieraInterface* descriptors) - : desc_(descriptors) + InstanceHandle (LumieraInterface descriptor) + : desc_(descriptor) , instance_(reinterpret_cast (register_and_open (desc_))) , facadeLink_(*this) { @@ -213,7 +213,7 @@ namespace lumiera { { lumiera_interface_close (&instance_->interface_header_); if (desc_) - lumiera_interfaceregistry_bulkremove_interfaces (desc_); + lumiera_interfaceregistry_remove_interface (desc_); } diff --git a/src/common/interfaceproxy.cpp b/src/common/interfaceproxy.cpp index 121c50929..52bd9d3f7 100644 --- a/src/common/interfaceproxy.cpp +++ b/src/common/interfaceproxy.cpp @@ -45,6 +45,9 @@ namespace lumiera { namespace facade { + LUMIERA_ERROR_DEFINE (FACADE_LIFECYCLE, "facade interface currently not accessible"); + + template class Holder; diff --git a/src/gui/guistart.cpp b/src/gui/guistart.cpp index dbff558a4..43efe6004 100644 --- a/src/gui/guistart.cpp +++ b/src/gui/guistart.cpp @@ -22,22 +22,22 @@ * *****************************************************/ + /** @file guistart.cpp ** Start up the Lumiera GTK GUI when loading it as dynamic module. ** This plugin is linked together with the Lumiera GUI code; when loaded as - ** Lumiera plugin, it allows to kick off the main GUI thread and thus to bring up - ** the GUI. The loading and shutdown process is carried out by gui::GuiFacade and + ** Lumiera plugin, it allows to kick off the GTK main event loop and thus to bring + ** up the GUI. The loading and shutdown process is carried out by gui::GuiFacade and ** controlled by lumiera::AppState, which in turn is activated by Lumiera main(). ** ** After successfully loading this module, a call to #kickOff is expected to be ** issued, passing a termination signal (callback) to be executed when the GUI - ** terminates. This call remains blocked within the main GTK event loop; thus - ** typically this should already run within a separate dedicated GUI thread. + ** terminates. The \c kickOff() call remains blocked within the main GTK event loop; + ** thus typically this call should be issued within a separate dedicated GUI thread. ** Especially, the gui::GuiRunner will ensure this to happen. ** ** Prior to entering the GTK event loop, all primary "business" interface of the GUI ** will be opened (currently as of 1/09 this is the interface gui::GuiNotification.) - ** @todo implement this! ** ** @see lumiera::AppState ** @see gui::GuiFacade @@ -50,6 +50,7 @@ #include "include/nobugcfg.h" #include "lib/error.hpp" #include "gui/guifacade.hpp" +#include "gui/notification-service.hpp" #include "common/subsys.hpp" #include "lib/singleton.hpp" @@ -58,9 +59,11 @@ extern "C" { #include "common/interfacedescriptor.h" } +#include +using std::string; using lumiera::Subsys; using gui::LUMIERA_INTERFACE_INAME(lumieraorg_Gui, 1); @@ -73,41 +76,58 @@ namespace gui { * Implement the necessary steps for actually making the Lumiera Gui available. * Open the business interface(s) and start up the GTK GUI main event loop. */ - struct GuiFacadeImpl - : public GuiFacade + struct GuiLifecycle { + string error_; + Subsys::SigTerm& reportOnTermination_; + NotificationService activateNotificationService_; - void kickOff (Subsys::SigTerm& reportTermination) + GuiLifecycle (Subsys::SigTerm& terminationHandler) + : reportOnTermination_(terminationHandler) + , activateNotificationService_() // opens the GuiNotification facade interface + { } + + ~GuiLifecycle () + { + reportOnTermination_(0); /////////TODO: pass on error information + } + + + void + run () { try { - int argc =0; /////////////////////////////////////////////////////////////////////////////TODO pass arguments from core - char *argv[] = {}; + int argc =0; + char *argv[] = {}; // dummy command line for GTK gui::application().main(argc, argv); // execute the GTK Event Loop if (!lumiera_error_peek()) - { - reportTermination(0); // report GUI shutdown without error return; - } } catch (lumiera::Error& problem) { - reportTermination(&problem); // signal shutdown reporting the error + error_ = problem.what(); + lumiera_error(); // clear error flag return; } catch (...){ } - lumiera::error::Fatal problemIndicator("unexpected error terminated the GUI.", lumiera_error()); - reportTermination (&problemIndicator); + error_ = "unexpected error terminated the GUI."; return; } }; - lumiera::Singleton guiImplProvider_; } // (End) impl details + + + void + kickOff (Subsys::SigTerm& reportTermination) + { + GuiLifecycle(reportTermination).run(); + } } // namespace gui @@ -198,8 +218,7 @@ extern "C" { /* ================== define an lumieraorg_Gui instance =========== , LUMIERA_INTERFACE_INLINE (kickOff, "\255\142\006\244\057\170\152\312\301\372\220\323\230\026\200\065", void, (void* termSig), { - gui::guiImplProvider_().kickOff ( - *reinterpret_cast (termSig)); + gui::kickOff (*reinterpret_cast (termSig)); } ) ) diff --git a/src/gui/guinotificationfacade.cpp b/src/gui/notification-service.cpp similarity index 81% rename from src/gui/guinotificationfacade.cpp rename to src/gui/notification-service.cpp index 67ae31162..c09e1bbd5 100644 --- a/src/gui/guinotificationfacade.cpp +++ b/src/gui/notification-service.cpp @@ -1,5 +1,5 @@ /* - GuiNotificationFacade - access point for pushing informations into the GUI + NotificationService - public service allowing to push informations into the GUI Copyright (C) Lumiera.org 2008, Hermann Vosseler @@ -21,7 +21,7 @@ * *****************************************************/ -#include "include/guinotificationfacade.h" +#include "gui/notification-service.hpp" #include "lib/singleton.hpp" #include "include/nobugcfg.h" #include "lib/util.hpp" @@ -33,35 +33,33 @@ extern "C" { #include + + namespace gui { using std::string; using util::cStr; + + + void + NotificationService::displayInfo (string const& text) + { + INFO (operate, "@GUI: display '%s' as notification message.", cStr(text)); + ////////////////////////TODO actually push the information to the GUI + } + + + void + NotificationService::triggerGuiShutdown (string const& cause) + { + NOTICE (operate, "@GUI: shutdown triggered with explanation '%s'....", cStr(cause)); + TODO ("actually request a shutdown from the GUI"); + } + namespace { // facade implementation details - struct GuiNotificationFacade - : public GuiNotification - { - void - displayInfo (string const& text) - { - INFO (operate, "@GUI: display '%s' as notification message.", cStr(text)); - } - - void - triggerGuiShutdown (string const& cause) - { - NOTICE (operate, "@GUI: shutdown triggered with explanation '%s'....", cStr(cause)); - } - }; - - lumiera::Singleton _facade; - - - - /* ================== define an lumieraorg_GuiNotification instance ======================= */ LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0 @@ -131,6 +129,16 @@ namespace gui { ); + + + + using lumiera::facade::LUMIERA_ERROR_FACADE_LIFECYCLE; + typedef lib::SingletonRef::Accessor InstanceRef; + + InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual GuiNotification implementation... + + + LUMIERA_INTERFACE_INSTANCE (lumieraorg_GuiNotification, 1 ,lumieraorg_GuiNotificationFacade , LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_GuiNotificationFacade_descriptor) @@ -138,15 +146,37 @@ namespace gui { , NULL /* on close */ , LUMIERA_INTERFACE_INLINE (displayInfo, "\366\075\213\163\207\040\221\233\010\366\174\374\317\126\331\205", void, (const char* text), - { return _facade().displayInfo(text); } + { + if (!_instance) lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE); + else + _instance->displayInfo(text); + } ) , LUMIERA_INTERFACE_INLINE (triggerGuiShutdown, "\267\043\244\065\107\314\370\175\063\330\264\257\302\146\326\303", void, (const char* cause), - { return _facade().triggerGuiShutdown(cause); } + { + if (!_instance) lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE); + else + _instance->triggerGuiShutdown(cause); + } ) ); - - + + + } // (END) facade implementation details + + + + + NotificationService::NotificationService () + : implInstance_(this,_instance), + serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_GuiNotification, 1,lumieraorg_GuiNotificationFacade)) + { + INFO (operate, "GuiNotification Facade opened."); + } + + + } // namespace gui diff --git a/src/gui/notification-service.hpp b/src/gui/notification-service.hpp new file mode 100644 index 000000000..41e404e46 --- /dev/null +++ b/src/gui/notification-service.hpp @@ -0,0 +1,91 @@ +/* + NOTIFICATION-SERVICE.hpp - public service allowing to push informations into the GUI + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + 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 notification-service.hpp + ** A public service provided by the GUI, implementing the gui::GuiNotification facade interface. + ** The purpose of this service is to push state update and notification of events from the lower + ** layers into the Lumiera GUI. Typically, this happens asynchronously and triggered by events + ** within the lower layers. + ** + ** This service is the implementation of a layer separation facade interface. Clients should use + ** gui::GuiNotification#facade to access this service. This header defines the interface used + ** to \em provide this service, not to access it. + ** + ** @see gui::GuiFacade + ** @see guifacade.cpp starting this service + */ + + +#ifndef GUI_NOTIFICATION_SERVICE_H +#define GUI_NOTIFICATION_SERVICE_H + + +#include "include/guinotificationfacade.h" +#include "common/instancehandle.hpp" +#include "lib/singleton-ref.hpp" + + + +namespace gui { + + + + /****************************************************** + * Actual implementation of the GuiNotification service + * within the Lumiera GTK GUI. Creating an instance of + * this class automatically registers the interface + * with the Lumiera Interface/Plugin system and creates + * a forwarding proxy within the application core to + * route calls through this interface. + * + * @todo the ctor of this class should take references + * to any internal service providers within the + * GUI which are needed to implement the service. + */ + class NotificationService + : public GuiNotification + { + + /* === Implementation of the Facade Interface === */ + + void displayInfo (string const& text); + void triggerGuiShutdown (string const& cause); + + + /* === Interface Lifecycle === */ + + typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_GuiNotification, 1) + , GuiNotification + > ServiceInstanceHandle; + + lib::SingletonRef implInstance_; + ServiceInstanceHandle serviceInstance_; + + public: + NotificationService(); + + }; + + + +} // namespace gui +#endif diff --git a/src/include/guinotificationfacade.h b/src/include/guinotificationfacade.h index 648839f50..9f4f91474 100644 --- a/src/include/guinotificationfacade.h +++ b/src/include/guinotificationfacade.h @@ -20,16 +20,13 @@ */ -/** @file guifacade.hpp - ** Interface for the GUI loader and for accessing the GUI interface from the - ** lower layers of Lumiera. While part of the public interface of the Lumiera GUI, - ** the implementation of this facility is part of the core application (and not - ** contained within the GUI dynamic module), because it's job is to load and - ** activate this module and to startup the GUI. +/** @file guinotificationfacade.hpp + ** Main public Interface of the Lumiera GUI. While generally speaking, the GUI + ** controls the application and thus acts on its own, it exposes some services + ** usable by scripts or the two lower layers. The main purpose of these services + ** is to push informations and status updates into the GUI. ** - ** @see lumiera::AppState - ** @see lumiera::Option - ** @see guifacade.cpp + ** @see gui::GuiFacade ** @see main.cpp */ diff --git a/src/include/interfaceproxy.hpp b/src/include/interfaceproxy.hpp index cb8da0d92..32248d762 100644 --- a/src/include/interfaceproxy.hpp +++ b/src/include/interfaceproxy.hpp @@ -84,6 +84,9 @@ namespace lumiera { namespace facade { + /** error-ID for accessing a (currently) closed facade */ + LUMIERA_ERROR_DECLARE(FACADE_LIFECYCLE); + /********************************************************************* * diff --git a/src/lib/singleton-ref.hpp b/src/lib/singleton-ref.hpp new file mode 100644 index 000000000..f3fad3921 --- /dev/null +++ b/src/lib/singleton-ref.hpp @@ -0,0 +1,131 @@ +/* + SINGLETON-REF.hpp - helper template providing singleton-like access for implementation code + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + 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 singleton-ref.hpp + ** Helper for singleton-kind access without managing object creation and lifecycle. + ** A typical usage scenario is when implementing C Language Interfaces without any + ** canonical access to some "this" pointer. + ** + ** @see gui::NotificationService usage example + */ + + +#ifndef LIB_SINGLETON_REF_H +#define LIB_SINGLETON_REF_H + + +#include "lib/error.hpp" + +#include + + +namespace lib { + + namespace singleton { + + /*************************************** + * Detail/Policy class specifying + * how the SingletonRef can be accessed + */ + template + class AccessAsReference + : boost::noncopyable + { + TY* obj_; + + typedef AccessAsReference _ThisType; + + public: + void + open (TY* instance) + { + ASSERT (!obj_, "Lifecycle error"); + obj_ = instance; + } + + void + close () + { + ASSERT (obj_, "Lifecycle error"); + obj_ = 0; + } + + TY* + operator-> () const + { + if (!obj_) + throw lumiera::error::State("Target currently not available."); + return obj_; + } + + + typedef void* _ThisType::*unspecified_bool_type; + + /** implicit conversion to "bool" */ + operator unspecified_bool_type() const // never throws + { + return obj_? &_ThisType::obj_ : 0; + } + + bool operator! () const { return !obj_; } + + }; + + } // namespace Singleton + + + + + /************************************************************* + * Helper template providing singleton access without managing + * object creation and lifecycle. + * @param TY the actual type to be made accessible + * @param B a base class to inherit from; defaults to noncopyable + * @param Accessor how to implement the static instance access + */ + template< class TY + , class B = boost::noncopyable + , template class Access = singleton::AccessAsReference + > + struct SingletonRef + : public B + { + + typedef Access Accessor; + Accessor& accessor_; + + SingletonRef(TY * instance, Accessor& acc) + : accessor_(acc) + { + accessor_.open (instance); + } + + ~SingletonRef() + { + accessor_.close (); + } + }; + + + +} // namespace lib +#endif diff --git a/src/proc/facade.hpp b/src/proc/facade.hpp index 1a30c7c27..5f4531617 100644 --- a/src/proc/facade.hpp +++ b/src/proc/facade.hpp @@ -33,18 +33,11 @@ namespace proc { /********************************************************************* - * Global access point for loading and starting up the Lumiera GTK GUI - * and for defining the public interface(s) for addressing the GUI - * from Backend or Proc-Layer. + * Global access point for the services implemented by the Proc-Layer. * - * If running Lumiera with a GUI is required (the default case), - * it is loaded as dynamic module, thus defining the interface(s) - * for any further access. After successfully loading and starting - * the GUI, this gui::Facade is wired internally with this interface - * such as to allow transparent access from within the core. This - * startup sequence includes providing the GUI with similar facade - * access via interface handles for communication with Backend and - * Proc-Layer. + * @todo this is a dummy placeholder as of 1/2009. Currently, there + * is only implementation-level code within the Proc-Layer and + * the interfaces need to be worked out. * */ struct Facade From b6fb135398d81c169f6539ad1b486b4f9e5c99f1 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 10 Jan 2009 16:15:17 +0100 Subject: [PATCH 30/35] change error notification at subsystem shutdown to use just a string* (this allows to memoize the error message and call the termination handler outside the catch block) --- src/common/guifacade.cpp | 2 +- src/common/subsys.hpp | 2 +- src/common/subsystem-runner.hpp | 7 +++++-- src/gui/guistart.cpp | 2 +- src/lib/util.hpp | 7 +++++++ tests/lib/subsystem-runner-test.cpp | 3 ++- 6 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/common/guifacade.cpp b/src/common/guifacade.cpp index 2fb76dcc1..8b2bf0dee 100644 --- a/src/common/guifacade.cpp +++ b/src/common/guifacade.cpp @@ -136,7 +136,7 @@ namespace gui { void - closeGuiModule (lumiera::Error *) + closeGuiModule (std::string *) { Lock guard (this); if (!facade) diff --git a/src/common/subsys.hpp b/src/common/subsys.hpp index 598919bb7..ee0e229ad 100644 --- a/src/common/subsys.hpp +++ b/src/common/subsys.hpp @@ -71,7 +71,7 @@ namespace lumiera { : private noncopyable { public: - typedef function SigTerm; + typedef function SigTerm; virtual ~Subsys(); diff --git a/src/common/subsystem-runner.hpp b/src/common/subsystem-runner.hpp index f46168cd7..a25bc3dc0 100644 --- a/src/common/subsystem-runner.hpp +++ b/src/common/subsystem-runner.hpp @@ -31,6 +31,7 @@ #include #include +#include namespace lumiera { @@ -39,6 +40,7 @@ namespace lumiera { using std::tr1::function; using std::tr1::placeholders::_1; using std::vector; + using std::string; using util::cStr; using util::isnil; using util::and_all; @@ -172,12 +174,13 @@ namespace lumiera { } } void - sigTerm (Subsys* susy, Error* problem) ///< called from subsystem on termination + sigTerm (Subsys* susy, string* problem) ///< called from subsystem on termination { ASSERT (susy); Lock sync (this); - triggerEmergency(problem); + triggerEmergency(!isnil (problem)); INFO (operate, "Subsystem '%s' terminated.", cStr(*susy)); + WARN_IF (!isnil(problem), operate, "Irregular shutdown caused by: %s", cStr(*problem)); ERROR_IF (susy->isRunning(), lumiera, "Subsystem '%s' signals termination, " "without resetting running state", cStr(*susy)); removeall (running_, susy); diff --git a/src/gui/guistart.cpp b/src/gui/guistart.cpp index 43efe6004..529ea37de 100644 --- a/src/gui/guistart.cpp +++ b/src/gui/guistart.cpp @@ -89,7 +89,7 @@ namespace gui { ~GuiLifecycle () { - reportOnTermination_(0); /////////TODO: pass on error information + reportOnTermination_(&error_); // inform main thread that the GUI has been shut down. } diff --git a/src/lib/util.hpp b/src/lib/util.hpp index 402cbb435..1fba41ca1 100644 --- a/src/lib/util.hpp +++ b/src/lib/util.hpp @@ -60,6 +60,13 @@ namespace util { return !pContainer || pContainer->empty(); } + template + inline bool + isnil (CONT* pContainer) + { + return !pContainer || pContainer->empty(); + } + inline bool isnil (const char* pCStr) { diff --git a/tests/lib/subsystem-runner-test.cpp b/tests/lib/subsystem-runner-test.cpp index 2f6d65454..513b132d6 100644 --- a/tests/lib/subsystem-runner-test.cpp +++ b/tests/lib/subsystem-runner-test.cpp @@ -165,13 +165,14 @@ namespace lumiera { lumiera_error(); // reset error state.... // Note: in real life this actually // would be an catched exception! + string problemReport (problemIndicator.what()); { Lock guard (this); isUp_ = false; INFO (test, "thread %s terminates.", cStr(*this)); - termination ("true"==runSpec? 0 : &problemIndicator); + termination ("true"==runSpec? 0 : &problemReport); } } From f75bb233ba7ff33ac1d4494d17900fd69375e68a Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 10 Jan 2009 17:01:09 +0000 Subject: [PATCH 31/35] fix warnings and problems detected by gcc 4.3 / Lenny --- src/common/instancehandle.hpp | 22 +++++++++++++--------- src/common/interfaceproxy.cpp | 12 ++++++------ src/common/subsystem-runner.hpp | 10 ++++++---- src/gui/gtk-lumiera.hpp | 2 +- src/gui/guistart.cpp | 3 ++- tests/lib/subsystem-runner-test.cpp | 14 ++++++++++++-- 6 files changed, 40 insertions(+), 23 deletions(-) diff --git a/src/common/instancehandle.hpp b/src/common/instancehandle.hpp index 513a7607e..e12b8ec2d 100644 --- a/src/common/instancehandle.hpp +++ b/src/common/instancehandle.hpp @@ -101,7 +101,11 @@ namespace lumiera { ifa->version, ifa->name)); } + + } // (End) impl details + + namespace facade { /** * @internal Helper/Adapter for establishing a link @@ -113,13 +117,13 @@ namespace lumiera { * when destroying the InstanceHandle, the proxy will be closed. */ template - struct FacadeLink + struct Link : boost::noncopyable { typedef InstanceHandle IH; - FacadeLink (IH const& iha) { facade::openProxy(iha); } - ~FacadeLink() { facade::closeProxy(); } + Link (IH const& iha) { facade::openProxy(iha); } + ~Link() { facade::closeProxy(); } FA& operator() (IH const&) const @@ -132,16 +136,16 @@ namespace lumiera { /** * @internal when the InstanceHandle isn't associated with a * facade interface, then this specialisation switches - * the FacadeLink into "NOP" mode. + * the facade::Link into "NOP" mode. */ template - struct FacadeLink + struct Link : boost::noncopyable { typedef InstanceHandle IH; - FacadeLink (IH const&) { /* NOP */ } - ~FacadeLink() { /* NOP */ } + Link (IH const&) { /* NOP */ } + ~Link() { /* NOP */ } I& operator() (IH const& handle) const @@ -150,7 +154,7 @@ namespace lumiera { } }; - } // (End) impl details + } // namespace facade (impl details) @@ -174,7 +178,7 @@ namespace lumiera { { LumieraInterface desc_; I* instance_; - FacadeLink facadeLink_; + facade::Link facadeLink_; typedef InstanceHandle _ThisType; diff --git a/src/common/interfaceproxy.cpp b/src/common/interfaceproxy.cpp index 52bd9d3f7..6cbc8b4cb 100644 --- a/src/common/interfaceproxy.cpp +++ b/src/common/interfaceproxy.cpp @@ -59,7 +59,7 @@ namespace lumiera { protected: typedef InstanceHandle IHandle; typedef Holder THolder; - typedef Proxy Proxy; + typedef Proxy TProxy; typedef Accessor Access; I& _i_; @@ -69,10 +69,10 @@ namespace lumiera { { } public: - static Proxy& open(IHandle const& iha) + static TProxy& open(IHandle const& iha) { - static char buff[sizeof(Proxy)]; - Proxy* p = new(buff) Proxy(iha); + static char buff[sizeof(TProxy)]; + TProxy* p = new(buff) TProxy(iha); Access::implProxy_ = p; return *p; } @@ -80,9 +80,9 @@ namespace lumiera { static void close() { if (!Access::implProxy_) return; - Proxy* p = static_cast (Access::implProxy_); + TProxy* p = static_cast (Access::implProxy_); Access::implProxy_ = 0; - p->~Proxy(); + p->~TProxy(); } }; diff --git a/src/common/subsystem-runner.hpp b/src/common/subsystem-runner.hpp index a25bc3dc0..d2476a77e 100644 --- a/src/common/subsystem-runner.hpp +++ b/src/common/subsystem-runner.hpp @@ -162,10 +162,12 @@ namespace lumiera { bool started = susy->start (opts_, bind (&SubsystemRunner::sigTerm, this, susy, _1)); if (started) - if (susy->isRunning()) - running_.push_back (susy); // now responsible for managing the started subsystem - else - throw error::Logic("Subsystem "+string(*susy)+" failed to start"); + { + if (susy->isRunning()) + running_.push_back (susy); // now responsible for managing the started subsystem + else + throw error::Logic("Subsystem "+string(*susy)+" failed to start"); + } if (!and_all (susy->getPrerequisites(), isRunning() )) { diff --git a/src/gui/gtk-lumiera.hpp b/src/gui/gtk-lumiera.hpp index ce3d4c2e4..f2e228851 100644 --- a/src/gui/gtk-lumiera.hpp +++ b/src/gui/gtk-lumiera.hpp @@ -29,7 +29,7 @@ #define GTK_LUMIERA_HPP #include -#include +#include // need to include this after gtkmm.h, because types.h from GTK tries to shaddow the ERROR macro from windows, which kills NoBug's ERROR macro #include #include #include diff --git a/src/gui/guistart.cpp b/src/gui/guistart.cpp index 529ea37de..455dafabb 100644 --- a/src/gui/guistart.cpp +++ b/src/gui/guistart.cpp @@ -45,8 +45,9 @@ ** @see gui::GtkLumiera#main the GTK GUI main */ +#include // need to include this to prevent errors when libintl.h defines textdomain (because gtk-lumiera removes the def when ENABLE_NLS isn't defined) -#include "gui/gtk-lumiera.hpp" +#include "gui/gtk-lumiera.hpp" // need to include this before nobugcfg.h, because types.h from GTK tries to shaddow the ERROR macro from windows, which kills nobug's ERROR macro #include "include/nobugcfg.h" #include "lib/error.hpp" #include "gui/guifacade.hpp" diff --git a/tests/lib/subsystem-runner-test.cpp b/tests/lib/subsystem-runner-test.cpp index 513b132d6..dd2fc7b1f 100644 --- a/tests/lib/subsystem-runner-test.cpp +++ b/tests/lib/subsystem-runner-test.cpp @@ -103,6 +103,7 @@ namespace lumiera { || "throw"==startSpec; } + bool start (lumiera::Option&, Subsys::SigTerm termination) { @@ -282,8 +283,8 @@ namespace lumiera { MockSys unit4 ("U4", "start(true), run(false)."); SubsystemRunner runner(dummyOpt); - runner.maybeRun (unit1); - runner.maybeRun (unit4); + runner.maybeRun (unit1); // this one doesn't start at all, which isn't considered an error + try { runner.maybeRun (unit2); @@ -302,6 +303,15 @@ namespace lumiera { { ASSERT (lumiera_error() == error::LUMIERA_ERROR_LOGIC); // incorrect behaviour trapped } + try + { + runner.maybeRun (unit4); + NOTREACHED; + } + catch (lumiera::Error&) + { + ASSERT (lumiera_error() == error::LUMIERA_ERROR_LOGIC); // detected that the subsystem didn't come up + } bool emergency = runner.wait(); From 5df4aee966e431c4cce89996158ad97108eb481e Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 10 Jan 2009 18:20:04 +0100 Subject: [PATCH 32/35] circumvent false alarm in SubsystemRunner_test due to timing problems --- tests/lib/subsystem-runner-test.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/lib/subsystem-runner-test.cpp b/tests/lib/subsystem-runner-test.cpp index dd2fc7b1f..766005357 100644 --- a/tests/lib/subsystem-runner-test.cpp +++ b/tests/lib/subsystem-runner-test.cpp @@ -306,12 +306,13 @@ namespace lumiera { try { runner.maybeRun (unit4); - NOTREACHED; } catch (lumiera::Error&) { ASSERT (lumiera_error() == error::LUMIERA_ERROR_LOGIC); // detected that the subsystem didn't come up - } + } // (due to the way the test subsystem is written, + // this may not always be detected, because there + // is a short time window where isUp_==true ) bool emergency = runner.wait(); From a9667310191df00f6ba299eabee04a44d08e497b Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 10 Jan 2009 19:03:28 +0100 Subject: [PATCH 33/35] fix some more warnings --- tests/lib/customsharedptrtest.cpp | 9 ++++----- tests/lib/lifecycletest.cpp | 2 +- tests/lib/meta/typelisttest.cpp | 3 ++- tests/lib/removefromsettest.cpp | 2 +- tests/lib/scopedholdertest.cpp | 2 +- tests/lib/scopedholdertransfertest.cpp | 2 +- tests/lib/test/cmdlinewrappertest.cpp | 3 ++- tests/lib/test/testoptiontest.cpp | 4 +++- tests/lib/vectortransfertest.cpp | 14 +++++++------- tests/lib/visitingtoolconcept.cpp | 2 +- 10 files changed, 23 insertions(+), 20 deletions(-) diff --git a/tests/lib/customsharedptrtest.cpp b/tests/lib/customsharedptrtest.cpp index 15ceb26e4..1c15f25e5 100644 --- a/tests/lib/customsharedptrtest.cpp +++ b/tests/lib/customsharedptrtest.cpp @@ -31,10 +31,9 @@ using std::string; -namespace asset - { - namespace test - { +namespace asset { + namespace test{ + using lumiera::P; using std::tr1::shared_ptr; using std::tr1::weak_ptr; @@ -71,7 +70,7 @@ namespace asset class CustomSharedPtr_test : public Test { virtual void - run (Arg arg) + run (Arg) { check_refcounting (); check_shared_ownership (); diff --git a/tests/lib/lifecycletest.cpp b/tests/lib/lifecycletest.cpp index 3749b25f8..e93d5e7d7 100644 --- a/tests/lib/lifecycletest.cpp +++ b/tests/lib/lifecycletest.cpp @@ -58,7 +58,7 @@ namespace lumiera class LifeCycle_test : public Test { virtual void - run (Arg arg) + run (Arg) { ASSERT (basicInit, "the basic-init callback hasn't been invoked automatically"); ASSERT (1 == basicInit, "the basic-init callback has been invoked more than once"); diff --git a/tests/lib/meta/typelisttest.cpp b/tests/lib/meta/typelisttest.cpp index b070feaa1..20a70cbfb 100644 --- a/tests/lib/meta/typelisttest.cpp +++ b/tests/lib/meta/typelisttest.cpp @@ -78,7 +78,8 @@ namespace lumiera */ class TypeList_test : public Test { - virtual void run(Arg arg) + void + run (Arg) { AssembledClass wow_me_has_numbers; diff --git a/tests/lib/removefromsettest.cpp b/tests/lib/removefromsettest.cpp index b86fc2389..dd512782f 100644 --- a/tests/lib/removefromsettest.cpp +++ b/tests/lib/removefromsettest.cpp @@ -67,7 +67,7 @@ namespace util class RemoveFromSet_test : public Test { virtual void - run (Arg arg) + run (Arg) { test_remove (" nothing "); test_remove ("0"); diff --git a/tests/lib/scopedholdertest.cpp b/tests/lib/scopedholdertest.cpp index 42ed7de7e..778cc2e4f 100644 --- a/tests/lib/scopedholdertest.cpp +++ b/tests/lib/scopedholdertest.cpp @@ -58,7 +58,7 @@ namespace lib { { virtual void - run (Arg arg) + run (Arg) { cout << "checking ScopedHolder...\n"; diff --git a/tests/lib/scopedholdertransfertest.cpp b/tests/lib/scopedholdertransfertest.cpp index 92be1118d..abbd3a959 100644 --- a/tests/lib/scopedholdertransfertest.cpp +++ b/tests/lib/scopedholdertransfertest.cpp @@ -101,7 +101,7 @@ namespace lib { { virtual void - run (Arg arg) + run (Arg) { cout << "checking ScopedHolder...\n"; diff --git a/tests/lib/test/cmdlinewrappertest.cpp b/tests/lib/test/cmdlinewrappertest.cpp index a5add31e2..7ef194c1d 100644 --- a/tests/lib/test/cmdlinewrappertest.cpp +++ b/tests/lib/test/cmdlinewrappertest.cpp @@ -46,7 +46,8 @@ namespace util /** @test for util::Cmdline, wrapping various example cmdlines */ class CmdlineWrapper_test : public Test { - virtual void run (Arg arg) + void + run (Arg) { testLine(""); testLine("\n\t "); diff --git a/tests/lib/test/testoptiontest.cpp b/tests/lib/test/testoptiontest.cpp index 52ed20038..31dde772d 100644 --- a/tests/lib/test/testoptiontest.cpp +++ b/tests/lib/test/testoptiontest.cpp @@ -41,7 +41,8 @@ namespace test */ class TestOption_test : public Test { - virtual void run(Arg arg) + void + run (Arg) { noOptions(); help(); @@ -53,6 +54,7 @@ namespace test additionalCmd2(); } + /** @test performs the actual test for the option parser test::TestOption */ void doIt (const string cmdline) { diff --git a/tests/lib/vectortransfertest.cpp b/tests/lib/vectortransfertest.cpp index ce82e6669..6254db7aa 100644 --- a/tests/lib/vectortransfertest.cpp +++ b/tests/lib/vectortransfertest.cpp @@ -62,6 +62,7 @@ namespace lib { */ TransDummy (const TransDummy& o) + : Dummy() { TRACE (test, "COPY-ctor TransDummy( ref=%x ) --> this=%x", &o,this); ASSERT (!o, "protocol violation: real copy operations inhibited"); @@ -113,18 +114,17 @@ namespace lib { /********************************************************************************** - * @test ScopedHolder and ScopedPtrHolder are initially empty and copyable. - * After taking ownership, they prohibit copy operations, manage the - * lifecycle of the contained object and provide smart-ptr like access. - * A series of identical tests is conducted both with the ScopedPtrHolder - * (the contained objects are heap allocated but managed by the holder) - * and with the ScopedHolder (objects placed inline) + * @test growing (re-allocating) a vector with noncopyable objects, with the + * help of a special Allocator and a custom \c transfer_control operation + * provided by the contained objects. The idea is to allow some special + * copy-operations for the purpose of re-allocations within the vector, + * without requiring the object to be really copyable. */ class VectorTransfer_test : public Test { virtual void - run (Arg arg) + run (Arg) { cout << "\n..setup table space for 2 elements\n"; TransDummyVector table; diff --git a/tests/lib/visitingtoolconcept.cpp b/tests/lib/visitingtoolconcept.cpp index 3d625c1c5..8508cdb0d 100644 --- a/tests/lib/visitingtoolconcept.cpp +++ b/tests/lib/visitingtoolconcept.cpp @@ -97,7 +97,7 @@ namespace lumiera template static Tag& - get (TOOLImpl* const concreteTool=0) + get (TOOLImpl* const =0) // param used to pass type info { // we have a race condition here... Tag& t = TagTypeRegistry::tag; From ba9b72bce438c257aeeb8bc06af57b5411b7102c Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 10 Jan 2009 21:35:43 +0100 Subject: [PATCH 34/35] Fixes after merge --- src/common/Makefile.am | 2 +- src/gui/Makefile.am | 25 +++++++++++++------------ src/gui/gtk-lumiera.cpp | 2 +- tests/lib/subsystem-runner-test.cpp | 3 +-- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 5833b9ba1..337bf1595 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -61,6 +61,6 @@ noinst_HEADERS += \ $(liblumieracommon_la_srcdir)/subsys.hpp \ $(liblumieracommon_la_srcdir)/appstate.hpp \ $(liblumieracommon_la_srcdir)/option.hpp \ - $(liblumieracommon_la_srcdir)/subsystemrunner.hpp \ + $(liblumieracommon_la_srcdir)/subsystem-runner.hpp \ $(liblumieracommon_la_srcdir)/instancehandle.hpp diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 70e8264fb..4d39b39a6 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -64,7 +64,7 @@ pkglib_LTLIBRARIES += gtk_gui.la gtk_gui_la_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wall -Wextra -Werror gtk_gui_la_CXXFLAGS = $(AM_CXXFLAGS) -Wall -Wextra -gtk_gui_la_CPPFLAGS = $(AM_CPPFLAGS) -DLUMIERA_PLUGIN -I$(top_srcdir)/src/ +gtk_gui_la_CPPFLAGS = $(AM_CPPFLAGS) $(LUMIERA_GUI_CFLAGS) -DLUMIERA_PLUGIN -I$(top_srcdir)/src/ gtk_gui_la_LDFLAGS = -module -avoid-version -no-undefined -rpath /dev/null -shrext .lum gtk_gui_la_LIBADD = \ @@ -72,10 +72,11 @@ gtk_gui_la_LIBADD = \ liblumierabackend.la \ liblumieraproc.la \ liblumiera.la \ + libgui.la \ $(LUMIERA_GUI_LIBS) \ $(NOBUGMT_LUMIERA_LIBS) -gtk_gui_la_SOURCES = \ +gtk_gui_la_SOURCES = \ $(lumigui_srcdir)/guistart.cpp @@ -94,18 +95,18 @@ libgui_la_CPPFLAGS = $(AM_CPPFLAGS) \ $(LUMIERA_GUI_CFLAGS) libgui_la_SOURCES = \ - $(lumigui_srcdir)/guinotificationfacade.cpp \ + $(lumigui_srcdir)/notification-service.cpp \ $(lumigui_srcdir)/window-manager.cpp \ $(lumigui_srcdir)/window-manager.hpp \ $(lumigui_srcdir)/workspace/actions.cpp \ $(lumigui_srcdir)/workspace/actions.hpp \ - $(lumigui_srcdir)/workspace/workspace-window.cpp \ - $(lumigui_srcdir)/workspace/workspace-window.hpp \ + $(lumigui_srcdir)/workspace/workspace-window.cpp \ + $(lumigui_srcdir)/workspace/workspace-window.hpp \ $(lumigui_srcdir)/dialogs/dialog.hpp \ $(lumigui_srcdir)/dialogs/render.cpp \ $(lumigui_srcdir)/dialogs/render.hpp \ - $(lumigui_srcdir)/dialogs/preferences-dialog.cpp \ - $(lumigui_srcdir)/dialogs/preferences-dialog.hpp \ + $(lumigui_srcdir)/dialogs/preferences-dialog.cpp \ + $(lumigui_srcdir)/dialogs/preferences-dialog.hpp \ $(lumigui_srcdir)/dialogs/name-chooser.cpp \ $(lumigui_srcdir)/dialogs/name-chooser.hpp \ $(lumigui_srcdir)/panels/panel.cpp \ @@ -152,19 +153,19 @@ libgui_la_SOURCES = \ $(lumigui_srcdir)/model/track.hpp \ $(lumigui_srcdir)/model/clip-track.cpp \ $(lumigui_srcdir)/model/clip-track.hpp \ - $(lumigui_srcdir)/model/parent-track.cpp \ - $(lumigui_srcdir)/model/parent-track.hpp \ + $(lumigui_srcdir)/model/parent-track.cpp \ + $(lumigui_srcdir)/model/parent-track.hpp \ $(lumigui_srcdir)/model/group-track.cpp \ $(lumigui_srcdir)/model/group-track.hpp \ $(lumigui_srcdir)/model/sequence.cpp \ $(lumigui_srcdir)/model/sequence.hpp \ - $(lumigui_srcdir)/model/clip.cpp \ - $(lumigui_srcdir)/model/clip.hpp \ + $(lumigui_srcdir)/model/clip.cpp \ + $(lumigui_srcdir)/model/clip.hpp \ $(lumigui_srcdir)/output/displayer.cpp \ $(lumigui_srcdir)/output/displayer.hpp \ $(lumigui_srcdir)/output/gdkdisplayer.cpp \ $(lumigui_srcdir)/output/gdkdisplayer.hpp \ - $(lumigui_srcdir)/output/xvdisplayer.cpp \ + $(lumigui_srcdir)/output/xvdisplayer.cpp \ $(lumigui_srcdir)/output/xvdisplayer.hpp libgui_la_LIBADD = \ diff --git a/src/gui/gtk-lumiera.cpp b/src/gui/gtk-lumiera.cpp index 34a49d4ad..9fd41b94e 100644 --- a/src/gui/gtk-lumiera.cpp +++ b/src/gui/gtk-lumiera.cpp @@ -69,9 +69,9 @@ GtkLumiera::main(int argc, char *argv[]) kit.run(main_window); - return 0; } + Glib::ustring GtkLumiera::get_home_data_path() { diff --git a/tests/lib/subsystem-runner-test.cpp b/tests/lib/subsystem-runner-test.cpp index 766005357..cca17b0a8 100644 --- a/tests/lib/subsystem-runner-test.cpp +++ b/tests/lib/subsystem-runner-test.cpp @@ -315,9 +315,8 @@ namespace lumiera { // is a short time window where isUp_==true ) - bool emergency = runner.wait(); + runner.wait(); - ASSERT (emergency); // emergency state from unit4 got propagated ASSERT (!unit1.isRunning()); ASSERT (!unit2.isRunning()); ASSERT (!unit3.isRunning()); From 5b68a39cc42d3fd04c75eb6c00925a1e15e84efb Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 10 Jan 2009 21:50:03 +0100 Subject: [PATCH 35/35] move threads from backend to liblumiera otherwise lib and common would depend on backend --- src/lib/Makefile.am | 2 ++ src/lib/thread-wrapper.hpp | 2 +- src/{backend => lib}/threads.c | 2 +- src/{backend => lib}/threads.h | 0 4 files changed, 4 insertions(+), 2 deletions(-) rename src/{backend => lib}/threads.c (99%) rename src/{backend => lib}/threads.h (100%) diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 54c210ce8..7f9d5fbf0 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -28,6 +28,7 @@ liblumiera_la_SOURCES = \ $(liblumiera_la_srcdir)/rwlock.c \ $(liblumiera_la_srcdir)/condition.c \ $(liblumiera_la_srcdir)/reccondition.c \ + $(liblumiera_la_srcdir)/threads.c \ $(liblumiera_la_srcdir)/luid.c \ $(liblumiera_la_srcdir)/safeclib.c \ $(liblumiera_la_srcdir)/psplay.c \ @@ -52,6 +53,7 @@ noinst_HEADERS += \ $(liblumiera_la_srcdir)/rwlock.h \ $(liblumiera_la_srcdir)/condition.h \ $(liblumiera_la_srcdir)/reccondition.h \ + $(liblumiera_la_srcdir)/threads.h \ $(liblumiera_la_srcdir)/luid.h \ $(liblumiera_la_srcdir)/safeclib.h \ $(liblumiera_la_srcdir)/psplay.h \ diff --git a/src/lib/thread-wrapper.hpp b/src/lib/thread-wrapper.hpp index 3c60cda09..1edc110ee 100644 --- a/src/lib/thread-wrapper.hpp +++ b/src/lib/thread-wrapper.hpp @@ -29,7 +29,7 @@ #include "lib/sync.hpp" extern "C" { -#include "backend/threads.h" +#include "lib/threads.h" } #include diff --git a/src/backend/threads.c b/src/lib/threads.c similarity index 99% rename from src/backend/threads.c rename to src/lib/threads.c index 11f70ac7a..128187095 100644 --- a/src/backend/threads.c +++ b/src/lib/threads.c @@ -23,7 +23,7 @@ //TODO: Lumiera header includes// -#include "backend/threads.h" +#include "lib/threads.h" //TODO: internal/static forward declarations// diff --git a/src/backend/threads.h b/src/lib/threads.h similarity index 100% rename from src/backend/threads.h rename to src/lib/threads.h