Merge branch 'master' of git.lumiera.org:/git/LUMIERA into join
Conflicts: src/gui/Makefile.am
This commit is contained in:
commit
fade287745
66 changed files with 1876 additions and 461 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -23,9 +23,11 @@
|
|||
|
||||
#include "gui/guifacade.hpp"
|
||||
#include "include/guinotificationfacade.h"
|
||||
#include "lib/sync.hpp"
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/singleton.hpp"
|
||||
#include "lib/functorutil.hpp"
|
||||
#include "lib/thread-wrapper.hpp"
|
||||
#include "common/instancehandle.hpp"
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
|
@ -42,6 +44,9 @@ namespace gui {
|
|||
using lumiera::Subsys;
|
||||
using lumiera::InstanceHandle;
|
||||
using util::dispatchSequenced;
|
||||
using lib::Sync;
|
||||
using lib::RecursiveLock_NoWait;
|
||||
using lib::Thread;
|
||||
|
||||
|
||||
|
||||
|
|
@ -57,17 +62,22 @@ 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());
|
||||
|
||||
///////////////////////////////////////////////////////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 () { }
|
||||
|
||||
|
||||
bool kickOff (Subsys::SigTerm& terminationHandle)
|
||||
void kickOff (Subsys::SigTerm& terminationHandle)
|
||||
{
|
||||
return theGUI_->kickOff (reinterpret_cast<void*> (&terminationHandle))
|
||||
&& !lumiera_error_peek();
|
||||
theGUI_->kickOff (reinterpret_cast<void*> (&terminationHandle));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -78,8 +88,10 @@ namespace gui {
|
|||
|
||||
scoped_ptr<GuiRunner> facade (0);
|
||||
|
||||
|
||||
class GuiSubsysDescriptor
|
||||
: public lumiera::Subsys
|
||||
: public lumiera::Subsys,
|
||||
public Sync<RecursiveLock_NoWait>
|
||||
{
|
||||
operator string () const { return "Lumiera GTK GUI"; }
|
||||
|
||||
|
|
@ -98,7 +110,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 +131,14 @@ namespace gui {
|
|||
bool
|
||||
checkRunningState () throw()
|
||||
{
|
||||
//Lock guard (*this);
|
||||
return (facade);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
closeGuiModule (lumiera::Error *)
|
||||
closeGuiModule (std::string *)
|
||||
{
|
||||
//Lock guard (*this);
|
||||
Lock guard (this);
|
||||
if (!facade)
|
||||
{
|
||||
WARN (operate, "Termination signal invoked, but GUI is currently closed. "
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
|
|
@ -40,6 +42,8 @@
|
|||
|
||||
|
||||
#include "include/nobugcfg.h"
|
||||
#include "lib/error.hpp"
|
||||
#include "include/interfaceproxy.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "common/interface.h"
|
||||
|
|
@ -47,7 +51,6 @@ extern "C" {
|
|||
}
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
//#include <boost/scoped_ptr.hpp>
|
||||
#include <string>
|
||||
|
||||
|
||||
|
|
@ -55,25 +58,36 @@ extern "C" {
|
|||
namespace lumiera {
|
||||
|
||||
using std::string;
|
||||
// using boost::scoped_ptr;
|
||||
|
||||
template<class I, class FA>
|
||||
class InstanceHandle;
|
||||
|
||||
|
||||
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
|
||||
/** 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);
|
||||
LumieraInterface masterI = descriptors[0];
|
||||
return lumiera_interface_open (masterI->interface,
|
||||
masterI->version,
|
||||
masterI->size,
|
||||
masterI->name);
|
||||
if (!descriptor) return NULL;
|
||||
lumiera_interfaceregistry_register_interface (descriptor, NULL);
|
||||
throwIfError();
|
||||
return lumiera_interface_open (descriptor->interface,
|
||||
descriptor->version,
|
||||
descriptor->size,
|
||||
descriptor->name);
|
||||
}
|
||||
|
||||
/** do a lookup within the interfaceregistry
|
||||
|
|
@ -87,8 +101,62 @@ namespace lumiera {
|
|||
ifa->version,
|
||||
ifa->name));
|
||||
}
|
||||
|
||||
|
||||
} // (End) impl details
|
||||
|
||||
|
||||
namespace facade {
|
||||
|
||||
/**
|
||||
* @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<class I, class FA>
|
||||
struct Link
|
||||
: boost::noncopyable
|
||||
{
|
||||
typedef InstanceHandle<I,FA> IH;
|
||||
|
||||
Link (IH const& iha) { facade::openProxy(iha); }
|
||||
~Link() { facade::closeProxy<IH>(); }
|
||||
|
||||
FA&
|
||||
operator() (IH const&) const
|
||||
{
|
||||
return facade::Accessor<FA>()();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @internal when the InstanceHandle isn't associated with a
|
||||
* facade interface, then this specialisation switches
|
||||
* the facade::Link into "NOP" mode.
|
||||
*/
|
||||
template<class I>
|
||||
struct Link<I,I>
|
||||
: boost::noncopyable
|
||||
{
|
||||
typedef InstanceHandle<I,I> IH;
|
||||
|
||||
Link (IH const&) { /* NOP */ }
|
||||
~Link() { /* NOP */ }
|
||||
|
||||
I&
|
||||
operator() (IH const& handle) const
|
||||
{
|
||||
return handle.get();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace facade (impl details)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -96,8 +164,11 @@ namespace lumiera {
|
|||
* 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
|
||||
|
|
@ -105,8 +176,9 @@ namespace lumiera {
|
|||
class InstanceHandle
|
||||
: private boost::noncopyable
|
||||
{
|
||||
LumieraInterface* desc_;
|
||||
LumieraInterface desc_;
|
||||
I* instance_;
|
||||
facade::Link<I,FA> facadeLink_;
|
||||
|
||||
typedef InstanceHandle<I,FA> _ThisType;
|
||||
|
||||
|
|
@ -119,37 +191,42 @@ 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<I*>
|
||||
: desc_(0)
|
||||
, instance_(reinterpret_cast<I*>
|
||||
(lumiera_interface_open (iName.c_str(), version, minminor, impName.c_str())))
|
||||
{ }
|
||||
, facadeLink_(*this)
|
||||
{
|
||||
throwIfError();
|
||||
}
|
||||
|
||||
/** 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),
|
||||
instance_(reinterpret_cast<I*> (register_and_open (desc_)))
|
||||
{ }
|
||||
InstanceHandle (LumieraInterface descriptor)
|
||||
: desc_(descriptor)
|
||||
, instance_(reinterpret_cast<I*> (register_and_open (desc_)))
|
||||
, facadeLink_(*this)
|
||||
{
|
||||
throwIfError();
|
||||
}
|
||||
|
||||
~InstanceHandle ()
|
||||
{
|
||||
lumiera_interface_close (&instance_->interface_header_);
|
||||
if (desc_)
|
||||
lumiera_interfaceregistry_bulkremove_interfaces (desc_);
|
||||
lumiera_interfaceregistry_remove_interface (desc_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 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 CLI interface */
|
||||
/** directly access the instance via the CL interface */
|
||||
I& get () const { ENSURE(instance_); return *instance_; }
|
||||
|
||||
|
||||
|
|
@ -164,13 +241,6 @@ namespace lumiera {
|
|||
|
||||
|
||||
private:
|
||||
FA *
|
||||
accessFacade() const
|
||||
{
|
||||
ENSURE (instance_);
|
||||
return static_cast<FA *> (instance_); /////////////////TODO: actually handle the case when the facade differs from the interface by using the proxy
|
||||
}
|
||||
|
||||
bool
|
||||
isValid() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -21,65 +21,118 @@
|
|||
* *****************************************************/
|
||||
|
||||
|
||||
#include "lib/singletonsubclass.hpp"
|
||||
#include "include/guinotificationfacade.h"
|
||||
#include "lib/util.hpp"
|
||||
#include "include/interfaceproxy.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<GuiNotificationInterfaceProxy>;
|
||||
|
||||
|
||||
|
||||
/* ======== forwarding through interface ========== */
|
||||
|
||||
void
|
||||
displayInfo (string const& text)
|
||||
{
|
||||
interface_->displayInfo (cStr(text));
|
||||
}
|
||||
|
||||
void
|
||||
triggerGuiShutdown (string const& cause)
|
||||
{
|
||||
interface_->triggerGuiShutdown (cStr(cause));
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
singleton::UseSubclass<GuiNotificationInterfaceProxy> typeinfo_proxyInstance_to_create;
|
||||
}
|
||||
|
||||
/** storage for the facade proxy factory used by client code to invoke through the interface */
|
||||
lumiera::SingletonSub<GuiNotification> 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> GuiNotification::facade;
|
||||
|
||||
} // namespace gui
|
||||
|
||||
|
||||
|
||||
|
||||
namespace lumiera {
|
||||
namespace facade {
|
||||
|
||||
|
||||
LUMIERA_ERROR_DEFINE (FACADE_LIFECYCLE, "facade interface currently not accessible");
|
||||
|
||||
|
||||
template<class IHA>
|
||||
class Holder;
|
||||
|
||||
template<class FA, class I>
|
||||
class Holder<InstanceHandle<I,FA> >
|
||||
: Accessor<FA>,
|
||||
protected FA
|
||||
{
|
||||
protected:
|
||||
typedef InstanceHandle<I,FA> IHandle;
|
||||
typedef Holder<IHandle> THolder;
|
||||
typedef Proxy<IHandle> TProxy;
|
||||
typedef Accessor<FA> Access;
|
||||
|
||||
I& _i_;
|
||||
|
||||
Holder (IHandle const& iha)
|
||||
: _i_(iha.get())
|
||||
{ }
|
||||
|
||||
public:
|
||||
static TProxy& open(IHandle const& iha)
|
||||
{
|
||||
static char buff[sizeof(TProxy)];
|
||||
TProxy* p = new(buff) TProxy(iha);
|
||||
Access::implProxy_ = p;
|
||||
return *p;
|
||||
}
|
||||
|
||||
static void close()
|
||||
{
|
||||
if (!Access::implProxy_) return;
|
||||
TProxy* p = static_cast<TProxy*> (Access::implProxy_);
|
||||
Access::implProxy_ = 0;
|
||||
p->~TProxy();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class FA>
|
||||
FA* Accessor<FA>::implProxy_;
|
||||
|
||||
|
||||
template<class IHA>
|
||||
void
|
||||
openProxy (IHA const& iha)
|
||||
{
|
||||
Proxy<IHA>::open(iha);
|
||||
}
|
||||
|
||||
template<class IHA>
|
||||
void
|
||||
closeProxy ()
|
||||
{
|
||||
Proxy<IHA>::close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_GuiNotification, 1)
|
||||
, gui::GuiNotification
|
||||
> Handle_GuiNotification;
|
||||
|
||||
|
||||
template<>
|
||||
class Proxy<Handle_GuiNotification>
|
||||
: public Holder<Handle_GuiNotification>
|
||||
{
|
||||
//----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 const& iha) : THolder(iha) {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template void openProxy<Handle_GuiNotification> (Handle_GuiNotification const&);
|
||||
template void closeProxy<Handle_GuiNotification> (void);
|
||||
|
||||
|
||||
} // namespace facade
|
||||
|
||||
} // namespace lumiera
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,12 +65,13 @@ 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
|
||||
{
|
||||
public:
|
||||
typedef function<void(Error*)> SigTerm;
|
||||
typedef function<void(string*)> SigTerm;
|
||||
|
||||
virtual ~Subsys();
|
||||
|
||||
|
|
@ -82,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();
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <Ichthyostega@web.de>
|
||||
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
#include <tr1/functional>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace lumiera {
|
||||
|
|
@ -39,13 +40,22 @@ 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;
|
||||
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<bool(Subsys*)>
|
||||
isRunning() {
|
||||
return bind (&Subsys::isRunning, _1);
|
||||
|
|
@ -76,10 +86,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 +96,7 @@ namespace lumiera {
|
|||
* @see main.cpp
|
||||
*/
|
||||
class SubsystemRunner
|
||||
// : Sync
|
||||
: public Sync<RecursiveLock_Waitable>
|
||||
{
|
||||
Option& opts_;
|
||||
volatile bool emergency_;
|
||||
|
|
@ -109,48 +118,57 @@ namespace lumiera {
|
|||
void
|
||||
maybeRun (Subsys& susy)
|
||||
{
|
||||
//Lock guard (this);
|
||||
Lock guard (this);
|
||||
|
||||
if (!susy.isRunning() && susy.shouldStart (opts_))
|
||||
triggerStartup (&susy);
|
||||
if (susy.isRunning())
|
||||
running_.push_back (&susy);
|
||||
}
|
||||
|
||||
void
|
||||
shutdownAll ()
|
||||
{
|
||||
//Lock guard (this);
|
||||
Lock guard (this);
|
||||
for_each (running_, killIt_);
|
||||
}
|
||||
|
||||
void
|
||||
triggerEmergency (bool cond)
|
||||
{
|
||||
Lock guard (this);
|
||||
if (cond) emergency_= true;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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() ))
|
||||
{
|
||||
susy->triggerShutdown();
|
||||
|
|
@ -158,23 +176,29 @@ 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 guard (this);
|
||||
triggerEmergency(problem);
|
||||
Lock sync (this);
|
||||
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);
|
||||
shutdownAll();
|
||||
//guard.notify();
|
||||
sync.notify();
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
@ -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,14 +153,14 @@ 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 \
|
||||
|
|
|
|||
|
|
@ -47,20 +47,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);
|
||||
|
||||
|
|
@ -75,9 +69,9 @@ GtkLumiera::main(int argc, char *argv[])
|
|||
|
||||
kit.run(main_window);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Glib::ustring
|
||||
GtkLumiera::get_home_data_path()
|
||||
{
|
||||
|
|
@ -109,3 +103,14 @@ const int GtkLumiera::AppAuthorCount = 4;
|
|||
} // 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
#define GTK_LUMIERA_HPP
|
||||
|
||||
#include <gtkmm.h>
|
||||
#include <nobug.h>
|
||||
#include <nobug.h> // 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 <vector>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
|
@ -69,7 +69,7 @@ namespace gui {
|
|||
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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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*))
|
||||
);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -22,28 +22,36 @@
|
|||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
/** @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 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. 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.)
|
||||
**
|
||||
** @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 <locale> // 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" // 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"
|
||||
#include "gui/notification-service.hpp"
|
||||
#include "common/subsys.hpp"
|
||||
#include "lib/singleton.hpp"
|
||||
|
||||
|
|
@ -54,12 +62,9 @@ extern "C" {
|
|||
|
||||
#include <string>
|
||||
|
||||
|
||||
|
||||
using std::string;
|
||||
|
||||
#include <iostream> /////////////TODO
|
||||
using std::cout; //////////////TODO
|
||||
|
||||
|
||||
using lumiera::Subsys;
|
||||
using gui::LUMIERA_INTERFACE_INAME(lumieraorg_Gui, 1);
|
||||
|
||||
|
|
@ -69,28 +74,61 @@ 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
|
||||
struct GuiLifecycle
|
||||
{
|
||||
string error_;
|
||||
Subsys::SigTerm& reportOnTermination_;
|
||||
NotificationService activateNotificationService_;
|
||||
|
||||
bool kickOff (Subsys::SigTerm& terminationHandle)
|
||||
GuiLifecycle (Subsys::SigTerm& terminationHandler)
|
||||
: reportOnTermination_(terminationHandler)
|
||||
, activateNotificationService_() // opens the GuiNotification facade interface
|
||||
{ }
|
||||
|
||||
~GuiLifecycle ()
|
||||
{
|
||||
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
|
||||
return true;
|
||||
reportOnTermination_(&error_); // inform main thread that the GUI has been shut down.
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
run ()
|
||||
{
|
||||
try
|
||||
{
|
||||
int argc =0;
|
||||
char *argv[] = {}; // dummy command line for GTK
|
||||
|
||||
gui::application().main(argc, argv); // execute the GTK Event Loop
|
||||
|
||||
if (!lumiera_error_peek())
|
||||
return;
|
||||
}
|
||||
catch (lumiera::Error& problem)
|
||||
{
|
||||
error_ = problem.what();
|
||||
lumiera_error(); // clear error flag
|
||||
return;
|
||||
}
|
||||
catch (...){ }
|
||||
error_ = "unexpected error terminated the GUI.";
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
lumiera::Singleton<GuiFacadeImpl> facade_;
|
||||
|
||||
} // (End) impl details
|
||||
|
||||
|
||||
void
|
||||
kickOff (Subsys::SigTerm& reportTermination)
|
||||
{
|
||||
GuiLifecycle(reportTermination).run();
|
||||
}
|
||||
|
||||
} // namespace gui
|
||||
|
||||
|
|
@ -179,10 +217,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 (
|
||||
*reinterpret_cast<Subsys::SigTerm *> (termSig));
|
||||
gui::kickOff (*reinterpret_cast<Subsys::SigTerm *> (termSig));
|
||||
}
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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 <Ichthyostega@web.de>
|
||||
|
|
@ -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 <string>
|
||||
|
||||
|
||||
|
||||
|
||||
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<GuiNotificationFacade> _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<GuiNotification>::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
|
||||
91
src/gui/notification-service.hpp
Normal file
91
src/gui/notification-service.hpp
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
NOTIFICATION-SERVICE.hpp - public service allowing to push informations into the GUI
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
/** @file 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<GuiNotification> implInstance_;
|
||||
ServiceInstanceHandle serviceInstance_;
|
||||
|
||||
public:
|
||||
NotificationService();
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace gui
|
||||
#endif
|
||||
|
|
@ -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
|
||||
*/
|
||||
|
||||
|
|
@ -40,7 +37,7 @@
|
|||
|
||||
#ifdef __cplusplus /* ============== C++ Interface ================= */
|
||||
|
||||
#include "lib/singletonsubclass.hpp"
|
||||
#include "include/interfaceproxy.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
|
@ -63,7 +60,7 @@ namespace gui {
|
|||
class GuiNotification
|
||||
{
|
||||
public:
|
||||
static lumiera::SingletonSub<GuiNotification> facade;
|
||||
static lumiera::facade::Accessor<GuiNotification> facade;
|
||||
|
||||
/** push a user visible notification text */
|
||||
virtual void displayInfo (string const& text) =0;
|
||||
|
|
@ -83,7 +80,7 @@ namespace gui {
|
|||
|
||||
|
||||
extern "C" {
|
||||
#endif /* =========================== CLI Interface ================= */
|
||||
#endif /* =========================== CL Interface ===================== */
|
||||
|
||||
|
||||
#include "common/interface.h"
|
||||
|
|
|
|||
126
src/include/interfaceproxy.hpp
Normal file
126
src/include/interfaceproxy.hpp
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
INTERFACEPROXY - definition of forwarding proxies for the facade interfaces
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
/** @file interfaceproxy.hpp
|
||||
** Facade Interfaces Lifecycle. Communication between the Layers within Lumiera
|
||||
** usually is routed through <b>Layer Separation Interfaces</b>. 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.
|
||||
**
|
||||
** 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
|
||||
** 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()
|
||||
** 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 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.
|
||||
**
|
||||
** 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 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
|
||||
** 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
|
||||
** some translation unit. The usual place is interfaceproxy.cpp, which gets linked into
|
||||
** \c liblumieracommon.so and contains actual specialisations and literal forwarding
|
||||
** code <i>for each individual facade.</i>
|
||||
**
|
||||
** @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 "lib/error.hpp"
|
||||
|
||||
|
||||
|
||||
namespace lumiera {
|
||||
namespace facade {
|
||||
|
||||
/** error-ID for accessing a (currently) closed facade */
|
||||
LUMIERA_ERROR_DECLARE(FACADE_LIFECYCLE);
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
*/
|
||||
template<class FA>
|
||||
class Accessor
|
||||
{
|
||||
protected:
|
||||
static FA* implProxy_;
|
||||
|
||||
|
||||
public:
|
||||
FA&
|
||||
operator() ()
|
||||
{
|
||||
if (implProxy_)
|
||||
return *implProxy_;
|
||||
else
|
||||
throw error::State("Facade interface currently closed.");
|
||||
}
|
||||
};
|
||||
|
||||
template<class IHA>
|
||||
void openProxy (IHA const&);
|
||||
|
||||
template<class IHA>
|
||||
void closeProxy ();
|
||||
|
||||
template<class IHA>
|
||||
class Proxy;
|
||||
|
||||
|
||||
} // namespace facade
|
||||
|
||||
} // namespace lumiera
|
||||
|
||||
#endif
|
||||
|
|
@ -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 <string>
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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<RecursiveLock_NoWait>
|
||||
{
|
||||
typedef std::vector<char*> MemTable;
|
||||
TypeInfo type_;
|
||||
|
|
@ -81,7 +83,7 @@ namespace lib {
|
|||
void
|
||||
AllocationCluster::MemoryManager::reset (TypeInfo info)
|
||||
{
|
||||
ClassLock<MemoryManager> guard();
|
||||
Lock instance();
|
||||
|
||||
if (0 < mem_.size()) purge();
|
||||
type_ = info;
|
||||
|
|
@ -96,7 +98,7 @@ namespace lib {
|
|||
void
|
||||
AllocationCluster::MemoryManager::purge()
|
||||
{
|
||||
ClassLock<MemoryManager> 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<MemoryManager> 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<MemoryManager> guard();
|
||||
Lock instance();
|
||||
|
||||
REQUIRE (pendingAlloc);
|
||||
ASSERT (top_ < mem_.size());
|
||||
|
|
@ -174,8 +176,8 @@ namespace lib {
|
|||
AllocationCluster::~AllocationCluster() throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
ClassLock<AllocationCluster> guard();
|
||||
{ // avoiding a per-instance lock for now.
|
||||
ClassLock<AllocationCluster> 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<AllocationCluster> guard(); /////TODO: decide tradeoff: lock just the instance, or lock the AllocationCluster class?
|
||||
{ // avoiding a per-instance lock for now.
|
||||
ClassLock<AllocationCluster> guard(); // (see note in the class description)
|
||||
|
||||
if (slot > typeHandlers_.size())
|
||||
typeHandlers_.resize(slot);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<bool(string::value_type)> 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)
|
||||
|
|
|
|||
131
src/lib/singleton-ref.hpp
Normal file
131
src/lib/singleton-ref.hpp
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
SINGLETON-REF.hpp - helper template providing singleton-like access for implementation code
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
/** @file 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 <boost/noncopyable.hpp>
|
||||
|
||||
|
||||
namespace lib {
|
||||
|
||||
namespace singleton {
|
||||
|
||||
/***************************************
|
||||
* Detail/Policy class specifying
|
||||
* how the SingletonRef can be accessed
|
||||
*/
|
||||
template<class TY>
|
||||
class AccessAsReference
|
||||
: boost::noncopyable
|
||||
{
|
||||
TY* obj_;
|
||||
|
||||
typedef AccessAsReference<TY> _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> class Access = singleton::AccessAsReference
|
||||
>
|
||||
struct SingletonRef
|
||||
: public B
|
||||
{
|
||||
|
||||
typedef Access<TY> Accessor;
|
||||
Accessor& accessor_;
|
||||
|
||||
SingletonRef(TY * instance, Accessor& acc)
|
||||
: accessor_(acc)
|
||||
{
|
||||
accessor_.open (instance);
|
||||
}
|
||||
|
||||
~SingletonRef()
|
||||
{
|
||||
accessor_.close ();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace lib
|
||||
#endif
|
||||
|
|
@ -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.
|
||||
**
|
||||
|
|
|
|||
|
|
@ -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> class Create = singleton::StaticCreate // how to create/destroy the instance
|
||||
, template <class> class Life = singleton::AutoDestroy // how to manage Singleton Lifecycle
|
||||
, template <class> class Threading = singleton::IgnoreThreadsafety //TODO use Multithreaded!!!
|
||||
< class SI
|
||||
, template <class> class Create = singleton::StaticCreate
|
||||
, template <class> class Life = singleton::AutoDestroy
|
||||
>
|
||||
class SingletonFactory
|
||||
{
|
||||
typedef typename Threading<SI>::VolatileType SType;
|
||||
typedef typename Threading<SI>::Lock ThreadLock;
|
||||
static SType* pInstance_;
|
||||
typedef SI* volatile PType;
|
||||
typedef lib::ClassLock<SI> ThreadLock;
|
||||
|
||||
static PType pInstance_;
|
||||
static bool isDead_;
|
||||
|
||||
public:
|
||||
|
|
@ -110,21 +119,19 @@ namespace lumiera
|
|||
template
|
||||
< class SI,
|
||||
template <class> class C,
|
||||
template <class> class L,
|
||||
template <class> class T
|
||||
template <class> class L
|
||||
>
|
||||
typename SingletonFactory<SI,C,L,T>::SType*
|
||||
SingletonFactory<SI,C,L,T>::pInstance_;
|
||||
typename SingletonFactory<SI,C,L>::PType
|
||||
SingletonFactory<SI,C,L>::pInstance_;
|
||||
|
||||
template
|
||||
< class SI,
|
||||
template <class> class C,
|
||||
template <class> class L,
|
||||
template <class> class T
|
||||
template <class> class L
|
||||
>
|
||||
bool SingletonFactory<SI,C,L,T>::isDead_;
|
||||
|
||||
|
||||
bool SingletonFactory<SI,C,L>::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
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ This code is heavily inspired by
|
|||
#define LUMIERA_SINGLETONPOLICIES_H
|
||||
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/sync-classlock.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -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 actually implement this policy using the Lumiera databackend.
|
||||
*/
|
||||
template<class S>
|
||||
struct Multithreaded
|
||||
{
|
||||
typedef volatile S VolatileType;
|
||||
typedef lib::ClassLock<S> Lock;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Policy just ignoring thread safety
|
||||
*/
|
||||
template<class S>
|
||||
struct IgnoreThreadsafety
|
||||
{
|
||||
typedef S VolatileType;
|
||||
struct Lock {};
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace singleton
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
@ -123,13 +123,11 @@ namespace lumiera {
|
|||
< class SI // the class to use as Interface for the Singleton
|
||||
, template <class> class Create = singleton::StaticCreate // how to create/destroy the instance
|
||||
, template <class> class Life = singleton::AutoDestroy // how to manage Singleton Lifecycle
|
||||
, template <class> class Threading = singleton::IgnoreThreadsafety //TODO use Multithreaded!!!
|
||||
>
|
||||
class SingletonSubclassFactory
|
||||
: public SingletonFactory< SI
|
||||
, singleton::Adapter<Create,SI>::template Adapted
|
||||
, Life
|
||||
, Threading
|
||||
>
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -74,11 +74,15 @@
|
|||
extern "C" {
|
||||
#include "lib/mutex.h"
|
||||
#include "lib/condition.h"
|
||||
#include "lib/reccondition.h"
|
||||
}
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <pthread.h>
|
||||
#include <cerrno>
|
||||
#include <ctime>
|
||||
|
||||
using boost::noncopyable;
|
||||
|
||||
|
||||
namespace lib {
|
||||
|
|
@ -106,7 +110,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 +124,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------
|
||||
|
|
@ -131,11 +135,11 @@ namespace lib {
|
|||
|
||||
|
||||
struct Wrapped_LumieraRecCond
|
||||
: public lumiera_condition //////////////////////////////////////////TODO use correct implementation here!
|
||||
: public lumiera_reccondition
|
||||
{
|
||||
protected:
|
||||
Wrapped_LumieraRecCond() { lumiera_condition_init (this, "Obj.Monitor Condition", &NOBUG_FLAG(sync) ); } ////////TODO
|
||||
~Wrapped_LumieraRecCond() { lumiera_condition_destroy (this, &NOBUG_FLAG(sync) ); }
|
||||
Wrapped_LumieraRecCond() { lumiera_reccondition_init (this, "Obj.Monitor RecCondition", &NOBUG_FLAG(sync) ); } ////////TODO
|
||||
~Wrapped_LumieraRecCond() { lumiera_reccondition_destroy (this, &NOBUG_FLAG(sync) ); }
|
||||
|
||||
//------------------Resource-Tracking------
|
||||
void __may_block() { TODO ("Record we may block on mutex"); }
|
||||
|
|
@ -157,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()
|
||||
|
|
@ -282,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 IMPL>
|
||||
class Monitor
|
||||
|
|
@ -293,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(); }
|
||||
|
||||
|
|
@ -370,13 +386,13 @@ namespace lib {
|
|||
|
||||
public:
|
||||
class Lock
|
||||
: private noncopyable
|
||||
{
|
||||
Monitor& mon_;
|
||||
|
||||
public:
|
||||
template<class X>
|
||||
Lock(X* it) : mon_(getMonitor(it)){ mon_.acquireLock(); }
|
||||
Lock(Monitor& m) : mon_(m) { mon_.acquireLock(); }
|
||||
~Lock() { mon_.releaseLock(); }
|
||||
|
||||
void notify() { mon_.signal(false);}
|
||||
|
|
@ -385,11 +401,12 @@ namespace lib {
|
|||
|
||||
template<typename C>
|
||||
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<class X>
|
||||
Lock(X* it, bool (X::*method)(void))
|
||||
: mon_(getMonitor(it))
|
||||
|
|
@ -397,6 +414,11 @@ namespace lib {
|
|||
mon_.acquireLock();
|
||||
mon_.wait(*it,method);
|
||||
}
|
||||
|
||||
protected:
|
||||
/** for creating a ClassLock */
|
||||
Lock(Monitor& m) : mon_(m)
|
||||
{ mon_.acquireLock(); }
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -31,15 +31,14 @@
|
|||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
|
||||
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
|
||||
|
|
|
|||
117
src/lib/thread-wrapper.hpp
Normal file
117
src/lib/thread-wrapper.hpp
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
THREADWRAPPER.hpp - thin convenience wrapper for starting lumiera threads
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LIB_THREADWRAPPER_H
|
||||
#define LIB_THREADWRAPPER_H
|
||||
|
||||
|
||||
#include "include/nobugcfg.h"
|
||||
#include "lib/sync.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "lib/threads.h"
|
||||
}
|
||||
|
||||
#include <tr1/functional>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
|
||||
namespace lib {
|
||||
|
||||
using std::tr1::bind;
|
||||
using std::tr1::function;
|
||||
using lumiera::Literal;
|
||||
|
||||
|
||||
/**
|
||||
* 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 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.
|
||||
* 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
|
||||
: public Sync<NonrecursiveLock_Waitable>,
|
||||
boost::noncopyable
|
||||
{
|
||||
volatile bool started_;
|
||||
|
||||
typedef function<void(void)> Operation;
|
||||
Operation const& operation_;
|
||||
|
||||
static void
|
||||
run (void* arg)
|
||||
{
|
||||
ASSERT (arg);
|
||||
Thread* startingWrapper = reinterpret_cast<Thread*>(arg);
|
||||
Operation _doIt_(startingWrapper->operation_);
|
||||
{
|
||||
Lock sync(startingWrapper);
|
||||
startingWrapper->started_ = true;
|
||||
sync.notify(); // handshake signalling we've gotten the parameter
|
||||
}
|
||||
|
||||
_doIt_(); // execute the actual operation in the new thread
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
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..
|
||||
, this // passing this start context as parameter
|
||||
, 0 // no condition variable provided (for now...)
|
||||
, purpose.c_str()
|
||||
, logging_flag
|
||||
);
|
||||
|
||||
if (!res)
|
||||
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
|
||||
sync.wait (started_);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace lib
|
||||
#endif
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
|
||||
//TODO: Lumiera header includes//
|
||||
#include "backend/threads.h"
|
||||
#include "lib/threads.h"
|
||||
|
||||
//TODO: internal/static forward declarations//
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -60,6 +60,13 @@ namespace util {
|
|||
return !pContainer || pContainer->empty();
|
||||
}
|
||||
|
||||
template <class CONT>
|
||||
inline bool
|
||||
isnil (CONT* pContainer)
|
||||
{
|
||||
return !pContainer || pContainer->empty();
|
||||
}
|
||||
|
||||
inline bool
|
||||
isnil (const char* pCStr)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 TAR, class TOOL>
|
||||
class Dispatcher
|
||||
|
|
@ -140,7 +142,7 @@ namespace lumiera {
|
|||
void
|
||||
accomodate (size_t index)
|
||||
{
|
||||
ClassLock<Dispatcher> guard();
|
||||
ClassLock<Dispatcher> guard(); // note: this lock is also used for the singleton!
|
||||
if (index > table_.size())
|
||||
table_.resize (index); // performance bottleneck?? TODO: measure the real impact!
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<asset::Proc>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -82,8 +82,8 @@ 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.
|
||||
* 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
|
||||
* 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
|
||||
|
|
@ -144,8 +144,7 @@ namespace asset
|
|||
#include "proc/asset/pipe.hpp"
|
||||
|
||||
|
||||
namespace asset
|
||||
{
|
||||
namespace asset {
|
||||
|
||||
template P<Pipe> StructFactory::operator() (const Query<Pipe>& query);
|
||||
template P<Track> StructFactory::operator() (const Query<Track>& query);
|
||||
|
|
|
|||
|
|
@ -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<asset::Struct>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -183,16 +183,19 @@ namespace asset {
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
recursive_call (AssetManager* instance, PAsset& pA)
|
||||
{
|
||||
instance->remove (pA->getID());
|
||||
}
|
||||
|
||||
function<void(PAsset&)>
|
||||
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<void(PAsset&)>
|
||||
detach_child_recursively () ///< @return a functor recursively invoking remove(child)
|
||||
{
|
||||
return bind( &recursive_call, &AssetManager::instance(), _1 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<Pipe>&);
|
||||
template bool DefsManager::forget (const PPipe&);
|
||||
|
||||
|
||||
|
||||
} // namespace mobject::session
|
||||
|
||||
} // namespace mobject
|
||||
|
|
|
|||
|
|
@ -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<class TAR>
|
||||
P<TAR> create (const lumiera::Query<TAR>&);
|
||||
|
||||
/** 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<class TAR>
|
||||
|
|
|
|||
|
|
@ -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<TableEntry> > 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<TAR> 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<TAR> findNext () throw()
|
||||
|
|
@ -233,7 +233,7 @@ namespace mobject {
|
|||
|
||||
public:
|
||||
P<TAR> 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<TAR> (registry.begin(), end); // just ennumerate contents
|
||||
return Iter<TAR> (registry.begin(), end); // just enumerate contents
|
||||
else
|
||||
return Iter<TAR> (pos, registry.begin(), end); // start with direct match
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,38 +180,38 @@ END
|
|||
|
||||
|
||||
TEST "Factory_test" Factory_test 5 <<END
|
||||
out: ctor TargetObj(5) successfull
|
||||
out: ctor TargetObj(5) successful
|
||||
out: now the smart-ptr has refcount=3
|
||||
out: .....TargetObj(5): data="*****", array[5]={0,1,2,3,4,}
|
||||
out: dtor ~TargetObj(5) successfull
|
||||
out: dtor ~TargetObj(5) successful
|
||||
END
|
||||
|
||||
|
||||
TEST "Factory_special_test" Factory_special_test 5 <<END
|
||||
out: checkPlacement--------
|
||||
out: ctor TargetObj(5) successfull
|
||||
out: ctor TargetObj(5) successful
|
||||
out: created 3 shared_ptrs to Object placed in static buffer.
|
||||
out: .....TargetObj(5): data="*****", array[5]={0,1,2,3,4,}
|
||||
out: dtor ~TargetObj(5) successfull
|
||||
out: ctor TargetObj(6) successfull
|
||||
out: dtor ~TargetObj(5) successful
|
||||
out: ctor TargetObj(6) successful
|
||||
out: created 4 shared_ptrs to Object placed in static buffer.
|
||||
out: dtor ~TargetObj(6) successfull
|
||||
out: dtor ~TargetObj(6) successful
|
||||
out: checkPrivate--------
|
||||
out: ctor TargetObj(5) successfull
|
||||
out: ctor TargetObj(5) successful
|
||||
out: created 3 shared_ptrs to paranoid Object.
|
||||
out: .....TargetObj(5): data="*****", array[5]={0,1,2,3,4,}
|
||||
out: dtor ~TargetObj(5) successfull
|
||||
out: dtor ~TargetObj(5) successful
|
||||
out: checkMalloc--------
|
||||
out: ctor TargetObj(7) successfull
|
||||
out: ctor TargetObj(7) successful
|
||||
out: created auto_ptr to malloc-ed Object.
|
||||
out: .....TargetObj(7): data="*******", array[7]={0,1,2,3,4,5,6,}
|
||||
out: dtor ~TargetObj(7) successfull
|
||||
out: dtor ~TargetObj(7) successful
|
||||
out: checkPImpl--------
|
||||
out: ctor TargetObj(12) successfull
|
||||
out: ctor TargetObj(12) successful
|
||||
out: created auto_ptr to Interface Object.
|
||||
out: .....ImplObj::funky() called
|
||||
out: .....TargetObj(12): data="************", array[12]={0,1,2,3,4,5,6,7,8,9,10,11,}
|
||||
out: dtor ~TargetObj(12) successfull
|
||||
out: dtor ~TargetObj(12) successful
|
||||
END
|
||||
|
||||
|
||||
|
|
@ -251,10 +251,10 @@ END
|
|||
|
||||
TEST "SingletonSubclass_test" SingletonSubclass_test 13 <<END
|
||||
out: using the Singleton should create TargetObj(13)...
|
||||
out: ctor TargetObj(13) successfull
|
||||
out: ctor TargetObj(13) successful
|
||||
out: calling a non-static method on the Singleton-Implementation
|
||||
out: .....TargetObj(13): data="*************", array[13]={0,1,2,3,4,5,6,7,8,9,10,11,12,}
|
||||
out: dtor ~TargetObj(13) successfull
|
||||
out: dtor ~TargetObj(13) successful
|
||||
END
|
||||
|
||||
|
||||
|
|
@ -297,15 +297,15 @@ END
|
|||
|
||||
TEST "Singleton_test" Singleton_test 23 <<END
|
||||
out: testing TargetObj(23) as Singleton(statically allocated)
|
||||
out: ctor TargetObj(23) successfull
|
||||
out: ctor TargetObj(23) successful
|
||||
out: calling a non-static method on the Singleton instance
|
||||
out: .....TargetObj(23): data="***********************", array[23]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,}
|
||||
out: testing TargetObj(24) as Singleton(heap allocated)
|
||||
out: ctor TargetObj(24) successfull
|
||||
out: ctor TargetObj(24) successful
|
||||
out: calling a non-static method on the Singleton instance
|
||||
out: .....TargetObj(24): data="************************", array[24]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,}
|
||||
out: dtor ~TargetObj(23) successfull
|
||||
out: dtor ~TargetObj(24) successfull
|
||||
out: dtor ~TargetObj(23) successful
|
||||
out: dtor ~TargetObj(24) successful
|
||||
END
|
||||
|
||||
|
||||
|
|
@ -332,6 +332,21 @@ return: 0
|
|||
END
|
||||
|
||||
|
||||
TEST "Create 20 Threads passing context" ThreadWrapper_test <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
TEST "Starting and stopping subsystems" SubsystemRunner_test <<END
|
||||
out: -----singleSubsys_complete_cycle-----
|
||||
out: -----singleSubsys_start_failure-----
|
||||
out: -----singleSubsys_emegency_exit-----
|
||||
out: -----dependentSubsys_complete_cycle-----
|
||||
out: -----dependentSubsys_start_failure-----
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
TEST "TestOption_test" TestOption_test <<END
|
||||
out: Testing invocation with cmdline: ...
|
||||
out: --> Testgroup=ALL
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ END
|
|||
|
||||
TEST "QueryUtils_test" QueryUtils_test normalizeID <<END
|
||||
out: ..original : a A AA dufte 1a _1 A_A BÄH White space §&Ω%€GΩ%€ar Ω baäääääge!!!!! :
|
||||
out: normalized : a a aA dufte o1a o_1 a_A bH o white_space gar_bage :
|
||||
out: normalised : a a aA dufte o1a o_1 a_A bH o white_space gar_bage :
|
||||
END
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -59,9 +59,11 @@ 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 \
|
||||
$(testlib_srcdir)/thread-wrapper-test.cpp \
|
||||
$(testlib_srcdir)/test/cmdlinewrappertest.cpp \
|
||||
$(testlib_srcdir)/test/testoptiontest.cpp \
|
||||
$(testlib_srcdir)/vectortransfertest.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 ();
|
||||
|
|
|
|||
|
|
@ -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 <Ichthyostega@web.de>
|
||||
|
|
@ -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");
|
||||
|
|
@ -91,17 +89,17 @@ namespace lumiera
|
|||
|
||||
|
||||
/** @test simply throw some exception and pass context info */
|
||||
void throwSpecial (string _) { throw SpecificError(); }
|
||||
void throwDerived (string _) { throw DerivedError(); }
|
||||
void throwSpecial (string ) { throw SpecificError(); }
|
||||
void throwDerived (string ) { throw DerivedError(); }
|
||||
void throwFatal (string _) { throw error::Fatal(_); }
|
||||
void throwInvalid (string _) { throw error::Invalid(_); }
|
||||
void throwExternal(string _) { throw error::External(_); }
|
||||
void throwRuntime (string _) { throw std::runtime_error(_); }
|
||||
void throwExceptn (string _) { throw std::exception(); }
|
||||
|
||||
void throwExceptn (string ) { throw std::exception(); }
|
||||
|
||||
|
||||
/** @test catching, repackaging and rethrowing of errors.
|
||||
* This feature is important for passing exceptions transparentely
|
||||
* This feature is important for passing exceptions transparently
|
||||
* over several layers. The nested operation will throw an error::External,
|
||||
* which we are able to catch because it is derived from std::exception.
|
||||
* We don't need to know the exact type, but we can classify the error situation
|
||||
|
|
@ -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,15 +170,15 @@ 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());
|
||||
}
|
||||
|
||||
|
||||
/** @test terminate the Application by throwing an undclared exception.
|
||||
/** @test terminate the Application by throwing an undeclared exception.
|
||||
* this should result in the global unknown() handler to be called,
|
||||
* so usually it will terminate the testrun.
|
||||
* so usually it will terminate the test run.
|
||||
* @note inside error.hpp, an initialisation hook has been installed into
|
||||
* AppState, causing our own unknown() handler to be installed and
|
||||
* invoked, which gives additional diagnostics.*/
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -78,7 +78,8 @@ namespace lumiera
|
|||
*/
|
||||
class TypeList_test : public Test
|
||||
{
|
||||
virtual void run(Arg arg)
|
||||
void
|
||||
run (Arg)
|
||||
{
|
||||
AssembledClass wow_me_has_numbers;
|
||||
|
||||
|
|
|
|||
|
|
@ -44,12 +44,10 @@ using std::cout;
|
|||
|
||||
|
||||
|
||||
namespace lumiera
|
||||
{
|
||||
namespace query
|
||||
{
|
||||
namespace test
|
||||
{
|
||||
namespace lumiera {
|
||||
namespace query {
|
||||
namespace test{
|
||||
|
||||
|
||||
struct Thing
|
||||
{
|
||||
|
|
@ -59,7 +57,7 @@ namespace lumiera
|
|||
|
||||
|
||||
/************************************************************************
|
||||
* @test check the various small helpers and utilities we utilize
|
||||
* @test check the various small helpers and utilities we utilise
|
||||
* for dealing with ConfigQuery
|
||||
*/
|
||||
class QueryUtils_test : public Test
|
||||
|
|
@ -88,7 +86,7 @@ namespace lumiera
|
|||
|
||||
|
||||
|
||||
/** @test sanitizing and normalizing various tokens */
|
||||
/** @test sanitising and normalising various tokens */
|
||||
void
|
||||
check_normalizeID ()
|
||||
{
|
||||
|
|
@ -101,7 +99,7 @@ namespace lumiera
|
|||
|
||||
for_each (tokens, bind ( &normalizeID, _1 ));
|
||||
|
||||
cout << "normalized : " << tokens << " :\n";
|
||||
cout << "normalised : " << tokens << " :\n";
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -115,7 +113,7 @@ namespace lumiera
|
|||
ASSERT ("tok" == extractID ("pred", "pred(tok), pred(tux)." ));
|
||||
ASSERT ("tok" == extractID ("pred", "other(xyz) pred(tok) pred(tux)" ));
|
||||
ASSERT ("tok" == extractID ("pred", "some( pred(tok)" ));
|
||||
|
||||
|
||||
ASSERT (isnil (extractID ("pred", "pred (tok)")));
|
||||
ASSERT (isnil (extractID ("pred", "pred tok)" )));
|
||||
ASSERT (isnil (extractID ("pred", "pred(tok " )));
|
||||
|
|
@ -127,14 +125,14 @@ namespace lumiera
|
|||
void
|
||||
check_removeTerm ()
|
||||
{
|
||||
// successfull-----Symbol---input-string----------------------extracted------remaining-------------
|
||||
// successful------Symbol---input-string----------------------extracted------remaining-------------
|
||||
ASSERT_removeTerm ("pred", "pred(tok).", "pred(tok)", "." );
|
||||
ASSERT_removeTerm ("pred", " pred( tok )", "pred(tok)", " " );
|
||||
ASSERT_removeTerm ("pred", "pred(tok), pred(tux).", "pred(tok)", "pred(tux)." );
|
||||
ASSERT_removeTerm ("pred", "other(xyz) pred(tok) pred(tux)", "pred(tok)", "other(xyz) pred(tux)" );
|
||||
ASSERT_removeTerm ("pred", "some( pred(tok)", "pred(tok)", "some( " );
|
||||
|
||||
// not successfull
|
||||
// not successful
|
||||
ASSERT_removeTerm ("pred", "pred (tok", "", "pred (tok" );
|
||||
ASSERT_removeTerm ("pred", "pred tok)", "", "pred tok)" );
|
||||
ASSERT_removeTerm ("pred", "pred(tok", "", "pred(tok" );
|
||||
|
|
@ -149,7 +147,7 @@ namespace lumiera
|
|||
|
||||
|
||||
|
||||
/** @test counting of predicates in a quiery
|
||||
/** @test counting of predicates in a query
|
||||
* (currently 4/08 regexp based...)
|
||||
*/
|
||||
void
|
||||
|
|
@ -167,7 +165,7 @@ namespace lumiera
|
|||
|
||||
|
||||
} // namespace test
|
||||
|
||||
|
||||
} // namespace query
|
||||
|
||||
} // namespace lumiera
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ namespace util
|
|||
class RemoveFromSet_test : public Test
|
||||
{
|
||||
virtual void
|
||||
run (Arg arg)
|
||||
run (Arg)
|
||||
{
|
||||
test_remove (" nothing ");
|
||||
test_remove ("0");
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ namespace lib {
|
|||
{
|
||||
|
||||
virtual void
|
||||
run (Arg arg)
|
||||
run (Arg)
|
||||
{
|
||||
|
||||
cout << "checking ScopedHolder<Dummy>...\n";
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ namespace lib {
|
|||
{
|
||||
|
||||
virtual void
|
||||
run (Arg arg)
|
||||
run (Arg)
|
||||
{
|
||||
|
||||
cout << "checking ScopedHolder<Dummy>...\n";
|
||||
|
|
|
|||
435
tests/lib/subsystem-runner-test.cpp
Normal file
435
tests/lib/subsystem-runner-test.cpp
Normal file
|
|
@ -0,0 +1,435 @@
|
|||
/*
|
||||
SubsystemRunner(Test) - validate starting and stopping of dependent subsystems
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
#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"
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/query.hpp"
|
||||
#include "lib/util.hpp"
|
||||
#include "lib/sync.hpp"
|
||||
|
||||
#include <tr1/functional>
|
||||
#include <iostream>
|
||||
|
||||
using std::cout;
|
||||
using std::tr1::bind;
|
||||
using util::isnil;
|
||||
using util::cStr;
|
||||
using test::Test;
|
||||
using lib::Sync;
|
||||
using lib::RecursiveLock_Waitable;
|
||||
using lib::Thread;
|
||||
|
||||
|
||||
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 = 80;
|
||||
const uint MIN_RUNNING_TIME_ms = 10;
|
||||
|
||||
/** the "running" subsystem checks for a
|
||||
* shutdown request every XX milliseconds */
|
||||
const uint TICK_DURATION_ms = 5;
|
||||
|
||||
/** dummy options just to be ignored */
|
||||
util::Cmdline dummyArgs ("");
|
||||
lumiera::Option dummyOpt (dummyArgs);
|
||||
|
||||
/** marker for simulated failure exceptions */
|
||||
LUMIERA_ERROR_DEFINE( TEST, "simulated failure.");
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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<RecursiveLock_Waitable>
|
||||
{
|
||||
Literal id_;
|
||||
Literal spec_;
|
||||
|
||||
volatile bool isUp_;
|
||||
volatile bool didRun_;
|
||||
volatile bool termRequest_;
|
||||
int running_duration_;
|
||||
|
||||
|
||||
bool
|
||||
shouldStart (lumiera::Option&)
|
||||
{
|
||||
Literal startSpec (extractID ("start",spec_));
|
||||
return "true" ==startSpec
|
||||
|| "fail" ==startSpec
|
||||
|| "throw"==startSpec;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
start (lumiera::Option&, Subsys::SigTerm termination)
|
||||
{
|
||||
REQUIRE (!isUp_, "attempt to start %s twice!", cStr(*this));
|
||||
|
||||
Lock guard (this);
|
||||
Literal startSpec (extractID ("start",spec_));
|
||||
ASSERT (!isnil (startSpec));
|
||||
|
||||
if ("true"==startSpec) //----simulate successful subsystem start
|
||||
{
|
||||
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
|
||||
if ("fail"==startSpec) //----not starting, incorrectly reporting success
|
||||
return true;
|
||||
else
|
||||
if ("throw"==startSpec) //---starting flounders
|
||||
throw error::Fatal("simulated failure to start the subsystem", LUMIERA_ERROR_TEST);
|
||||
|
||||
return isUp_;
|
||||
}
|
||||
|
||||
void
|
||||
triggerShutdown () throw()
|
||||
{
|
||||
// note: *not* locking here...
|
||||
termRequest_ = true;
|
||||
|
||||
INFO (test, "triggerShutdown() --> %s....", cStr(*this));
|
||||
}
|
||||
|
||||
bool
|
||||
checkRunningState () throw()
|
||||
{
|
||||
// note: *not* locking here...
|
||||
return isUp_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
run (Subsys::SigTerm termination) ///< simulates a "running" subsystem
|
||||
{
|
||||
Literal runSpec (extractID ("run",spec_));
|
||||
ASSERT (!isnil (runSpec));
|
||||
|
||||
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!
|
||||
string problemReport (problemIndicator.what());
|
||||
|
||||
{
|
||||
Lock guard (this);
|
||||
isUp_ = false;
|
||||
|
||||
INFO (test, "thread %s terminates.", cStr(*this));
|
||||
termination ("true"==runSpec? 0 : &problemReport);
|
||||
} }
|
||||
|
||||
|
||||
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),
|
||||
didRun_(false),
|
||||
termRequest_(false),
|
||||
running_duration_(0)
|
||||
{ }
|
||||
|
||||
~MockSys() { }
|
||||
|
||||
operator string () const { return "MockSys(\""+id_+"\")"; }
|
||||
|
||||
friend inline ostream&
|
||||
operator<< (ostream& os, MockSys const& mosi) { return os << string(mosi); }
|
||||
|
||||
bool didRun () const { return didRun_; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // (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.
|
||||
* 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
|
||||
* @see lumiera::AppState
|
||||
* @see main.cpp
|
||||
*/
|
||||
class SubsystemRunner_test : public Test
|
||||
{
|
||||
|
||||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
singleSubsys_complete_cycle();
|
||||
singleSubsys_start_failure();
|
||||
singleSubsys_emegency_exit();
|
||||
|
||||
dependentSubsys_complete_cycle();
|
||||
dependentSubsys_start_failure();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
singleSubsys_complete_cycle()
|
||||
{
|
||||
cout << "-----singleSubsys_complete_cycle-----\n";
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
MockSys unit4 ("U4", "start(true), run(false).");
|
||||
SubsystemRunner runner(dummyOpt);
|
||||
|
||||
runner.maybeRun (unit1); // this one doesn't start at all, which isn't considered an error
|
||||
|
||||
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
|
||||
}
|
||||
try
|
||||
{
|
||||
runner.maybeRun (unit4);
|
||||
}
|
||||
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 )
|
||||
|
||||
|
||||
runner.wait();
|
||||
|
||||
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()
|
||||
{
|
||||
cout << "-----singleSubsys_emegency_exit-----\n";
|
||||
|
||||
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()
|
||||
{
|
||||
cout << "-----dependentSubsys_complete_cycle-----\n";
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
dependentSubsys_start_failure()
|
||||
{
|
||||
cout << "-----dependentSubsys_start_failure-----\n";
|
||||
|
||||
MockSys unit1 ("U1", "start(true), run(true).");
|
||||
MockSys unit2 ("U2", "start(true), run(true).");
|
||||
MockSys unit3 ("U3", "start(false),run(false)."); // note
|
||||
MockSys unit4 ("U4", "start(true), run(true).");
|
||||
unit2.depends (unit1);
|
||||
unit4.depends (unit3);
|
||||
unit4.depends (unit1);
|
||||
unit3.depends (unit2);
|
||||
SubsystemRunner runner(dummyOpt);
|
||||
|
||||
try
|
||||
{
|
||||
runner.maybeRun (unit4);
|
||||
NOTREACHED;
|
||||
}
|
||||
catch (lumiera::Error&)
|
||||
{
|
||||
ASSERT (lumiera_error() == error::LUMIERA_ERROR_LOGIC); // failure to bring up prerequisites is detected
|
||||
}
|
||||
ASSERT ( unit1.isRunning());
|
||||
ASSERT ( unit2.isRunning());
|
||||
ASSERT (!unit3.isRunning());
|
||||
// shutdown has been triggered for unit4, but may require some time
|
||||
|
||||
bool emergency = runner.wait();
|
||||
|
||||
ASSERT (!emergency); // no problems with the subsystems actually running...
|
||||
ASSERT (!unit1.isRunning());
|
||||
ASSERT (!unit2.isRunning());
|
||||
ASSERT (!unit3.isRunning());
|
||||
ASSERT (!unit4.isRunning());
|
||||
ASSERT ( unit1.didRun());
|
||||
ASSERT ( unit2.didRun());
|
||||
ASSERT (!unit3.didRun());
|
||||
// can't say for sure if unit4 actually did run
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (SubsystemRunner_test, "function common");
|
||||
|
||||
|
||||
|
||||
} // namespace test
|
||||
|
||||
} // namespace lumiera
|
||||
|
|
@ -95,4 +95,4 @@ namespace lib {
|
|||
|
||||
} // namespace test
|
||||
|
||||
} // namespace lumiera
|
||||
} // namespace lib
|
||||
|
|
|
|||
|
|
@ -206,4 +206,4 @@ namespace lib {
|
|||
|
||||
} // namespace test
|
||||
|
||||
} // namespace lumiera
|
||||
} // namespace lib
|
||||
|
|
|
|||
140
tests/lib/sync-timedwait-test.cpp
Normal file
140
tests/lib/sync-timedwait-test.cpp
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
SyncTimedwait(Test) - check the monitor object based timed condition wait
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
#include "lib/test/run.hpp"
|
||||
#include "lib/error.hpp"
|
||||
|
||||
#include "lib/sync.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
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<RecursiveLock_Waitable>
|
||||
{
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
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 lib
|
||||
|
|
@ -185,4 +185,4 @@ namespace lib {
|
|||
|
||||
} // namespace test
|
||||
|
||||
} // namespace lumiera
|
||||
} // namespace lib
|
||||
|
|
|
|||
|
|
@ -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 ");
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ namespace lumiera
|
|||
{
|
||||
for (uint i=0; i<cnt_; ++i)
|
||||
heapArray_[i] = lexical_cast<string>(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_;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
117
tests/lib/thread-wrapper-test.cpp
Normal file
117
tests/lib/thread-wrapper-test.cpp
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
ThreadWrapper(Test) - starting threads and passing context
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
#include "lib/test/run.hpp"
|
||||
|
||||
#include "include/symbol.hpp"
|
||||
#include "lib/thread-wrapper.hpp"
|
||||
#include "lib/sync.hpp"
|
||||
|
||||
#include <tr1/functional>
|
||||
|
||||
using std::tr1::bind;
|
||||
using test::Test;
|
||||
|
||||
|
||||
|
||||
namespace lib {
|
||||
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 lib::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 lib
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ namespace lumiera
|
|||
|
||||
template<class TOOLImpl>
|
||||
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<TOOL,TOOLImpl>::tag;
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Reference in a new issue