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)/subsys.hpp \
|
||||||
$(liblumieracommon_la_srcdir)/appstate.hpp \
|
$(liblumieracommon_la_srcdir)/appstate.hpp \
|
||||||
$(liblumieracommon_la_srcdir)/option.hpp \
|
$(liblumieracommon_la_srcdir)/option.hpp \
|
||||||
$(liblumieracommon_la_srcdir)/subsystemrunner.hpp \
|
$(liblumieracommon_la_srcdir)/subsystem-runner.hpp \
|
||||||
$(liblumieracommon_la_srcdir)/instancehandle.hpp
|
$(liblumieracommon_la_srcdir)/instancehandle.hpp
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
#include "include/lifecycle.h"
|
#include "include/lifecycle.h"
|
||||||
#include "common/appstate.hpp"
|
#include "common/appstate.hpp"
|
||||||
#include "lib/lifecycleregistry.hpp"
|
#include "lib/lifecycleregistry.hpp"
|
||||||
#include "common/subsystemrunner.hpp"
|
#include "common/subsystem-runner.hpp"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "common/config_interface.h"
|
#include "common/config_interface.h"
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,11 @@
|
||||||
|
|
||||||
#include "gui/guifacade.hpp"
|
#include "gui/guifacade.hpp"
|
||||||
#include "include/guinotificationfacade.h"
|
#include "include/guinotificationfacade.h"
|
||||||
|
#include "lib/sync.hpp"
|
||||||
#include "lib/error.hpp"
|
#include "lib/error.hpp"
|
||||||
#include "lib/singleton.hpp"
|
#include "lib/singleton.hpp"
|
||||||
#include "lib/functorutil.hpp"
|
#include "lib/functorutil.hpp"
|
||||||
|
#include "lib/thread-wrapper.hpp"
|
||||||
#include "common/instancehandle.hpp"
|
#include "common/instancehandle.hpp"
|
||||||
|
|
||||||
#include <boost/scoped_ptr.hpp>
|
#include <boost/scoped_ptr.hpp>
|
||||||
|
|
@ -42,6 +44,9 @@ namespace gui {
|
||||||
using lumiera::Subsys;
|
using lumiera::Subsys;
|
||||||
using lumiera::InstanceHandle;
|
using lumiera::InstanceHandle;
|
||||||
using util::dispatchSequenced;
|
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
|
: theGUI_("lumieraorg_Gui", 1, 1, "lumieraorg_GuiStarterPlugin") // load GuiStarterPlugin
|
||||||
{
|
{
|
||||||
ASSERT (theGUI_);
|
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());
|
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 () { }
|
~GuiRunner () { }
|
||||||
|
|
||||||
|
|
||||||
bool kickOff (Subsys::SigTerm& terminationHandle)
|
void kickOff (Subsys::SigTerm& terminationHandle)
|
||||||
{
|
{
|
||||||
return theGUI_->kickOff (reinterpret_cast<void*> (&terminationHandle))
|
theGUI_->kickOff (reinterpret_cast<void*> (&terminationHandle));
|
||||||
&& !lumiera_error_peek();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -78,8 +88,10 @@ namespace gui {
|
||||||
|
|
||||||
scoped_ptr<GuiRunner> facade (0);
|
scoped_ptr<GuiRunner> facade (0);
|
||||||
|
|
||||||
|
|
||||||
class GuiSubsysDescriptor
|
class GuiSubsysDescriptor
|
||||||
: public lumiera::Subsys
|
: public lumiera::Subsys,
|
||||||
|
public Sync<RecursiveLock_NoWait>
|
||||||
{
|
{
|
||||||
operator string () const { return "Lumiera GTK GUI"; }
|
operator string () const { return "Lumiera GTK GUI"; }
|
||||||
|
|
||||||
|
|
@ -98,7 +110,7 @@ namespace gui {
|
||||||
bool
|
bool
|
||||||
start (lumiera::Option&, Subsys::SigTerm termination)
|
start (lumiera::Option&, Subsys::SigTerm termination)
|
||||||
{
|
{
|
||||||
//Lock guard (*this);
|
Lock guard (this);
|
||||||
if (facade) return false; // already started
|
if (facade) return false; // already started
|
||||||
|
|
||||||
facade.reset (
|
facade.reset (
|
||||||
|
|
@ -119,14 +131,14 @@ namespace gui {
|
||||||
bool
|
bool
|
||||||
checkRunningState () throw()
|
checkRunningState () throw()
|
||||||
{
|
{
|
||||||
//Lock guard (*this);
|
|
||||||
return (facade);
|
return (facade);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
closeGuiModule (lumiera::Error *)
|
closeGuiModule (std::string *)
|
||||||
{
|
{
|
||||||
//Lock guard (*this);
|
Lock guard (this);
|
||||||
if (!facade)
|
if (!facade)
|
||||||
{
|
{
|
||||||
WARN (operate, "Termination signal invoked, but GUI is currently closed. "
|
WARN (operate, "Termination signal invoked, but GUI is currently closed. "
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,9 @@
|
||||||
**
|
**
|
||||||
** @see gui::GuiFacade usage example
|
** @see gui::GuiFacade usage example
|
||||||
** @see interface.h
|
** @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 "include/nobugcfg.h"
|
||||||
|
#include "lib/error.hpp"
|
||||||
|
#include "include/interfaceproxy.hpp"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "common/interface.h"
|
#include "common/interface.h"
|
||||||
|
|
@ -47,7 +51,6 @@ extern "C" {
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <boost/noncopyable.hpp>
|
#include <boost/noncopyable.hpp>
|
||||||
//#include <boost/scoped_ptr.hpp>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -55,25 +58,36 @@ extern "C" {
|
||||||
namespace lumiera {
|
namespace lumiera {
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
// using boost::scoped_ptr;
|
|
||||||
|
template<class I, class FA>
|
||||||
|
class InstanceHandle;
|
||||||
|
|
||||||
|
|
||||||
namespace { // implementation details
|
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
|
/** takes a (single) instance definitions, as typically created
|
||||||
* when defining interfaces for external use, and registers them
|
* when defining interfaces for external use, and registers it
|
||||||
* with the InterfaceSystem. Then uses the data found in the
|
* 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
|
LumieraInterface
|
||||||
register_and_open (LumieraInterface* descriptors)
|
register_and_open (LumieraInterface descriptor)
|
||||||
{
|
{
|
||||||
if (!descriptors) return NULL;
|
if (!descriptor) return NULL;
|
||||||
lumiera_interfaceregistry_bulkregister_interfaces (descriptors, NULL);
|
lumiera_interfaceregistry_register_interface (descriptor, NULL);
|
||||||
LumieraInterface masterI = descriptors[0];
|
throwIfError();
|
||||||
return lumiera_interface_open (masterI->interface,
|
return lumiera_interface_open (descriptor->interface,
|
||||||
masterI->version,
|
descriptor->version,
|
||||||
masterI->size,
|
descriptor->size,
|
||||||
masterI->name);
|
descriptor->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** do a lookup within the interfaceregistry
|
/** do a lookup within the interfaceregistry
|
||||||
|
|
@ -87,8 +101,62 @@ namespace lumiera {
|
||||||
ifa->version,
|
ifa->version,
|
||||||
ifa->name));
|
ifa->name));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // (End) impl details
|
} // (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.
|
* 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
|
* 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.
|
* 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
|
* Additionally, choosing a facade interface as second type parameter causes installation
|
||||||
* access through the facade proxy singleton when opening/closing the registration.
|
* 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
|
template< class I ///< fully mangled name of the interface type
|
||||||
, class FA = I ///< facade interface type to be used by clients
|
, class FA = I ///< facade interface type to be used by clients
|
||||||
|
|
@ -105,8 +176,9 @@ namespace lumiera {
|
||||||
class InstanceHandle
|
class InstanceHandle
|
||||||
: private boost::noncopyable
|
: private boost::noncopyable
|
||||||
{
|
{
|
||||||
LumieraInterface* desc_;
|
LumieraInterface desc_;
|
||||||
I* instance_;
|
I* instance_;
|
||||||
|
facade::Link<I,FA> facadeLink_;
|
||||||
|
|
||||||
typedef InstanceHandle<I,FA> _ThisType;
|
typedef InstanceHandle<I,FA> _ThisType;
|
||||||
|
|
||||||
|
|
@ -119,37 +191,42 @@ namespace lumiera {
|
||||||
* @param impName unmangled name of the instance (implementation)
|
* @param impName unmangled name of the instance (implementation)
|
||||||
*/
|
*/
|
||||||
InstanceHandle (string const& iName, uint version, size_t minminor, string const& impName)
|
InstanceHandle (string const& iName, uint version, size_t minminor, string const& impName)
|
||||||
: desc_(0),
|
: desc_(0)
|
||||||
instance_(reinterpret_cast<I*>
|
, instance_(reinterpret_cast<I*>
|
||||||
(lumiera_interface_open (iName.c_str(), version, minminor, impName.c_str())))
|
(lumiera_interface_open (iName.c_str(), version, minminor, impName.c_str())))
|
||||||
{ }
|
, facadeLink_(*this)
|
||||||
|
{
|
||||||
|
throwIfError();
|
||||||
|
}
|
||||||
|
|
||||||
/** Set up an InstanceHandle managing the
|
/** Set up an InstanceHandle managing the
|
||||||
* registration and deregistration of interface(s).
|
* registration and deregistration of interface(s).
|
||||||
* Should be placed at the service providing side.
|
* Should be placed at the service providing side.
|
||||||
* @param descriptors zero terminated array of interface descriptors,
|
* @param a (single) interface descriptor, which can be created with
|
||||||
* usually available through lumiera_plugin_interfaces()
|
* LUMIERA_INTERFACE_INSTANCE and referred to by LUMIERA_INTERFACE_REF
|
||||||
*/
|
*/
|
||||||
InstanceHandle (LumieraInterface* descriptors)
|
InstanceHandle (LumieraInterface descriptor)
|
||||||
: desc_(descriptors),
|
: desc_(descriptor)
|
||||||
instance_(reinterpret_cast<I*> (register_and_open (desc_)))
|
, instance_(reinterpret_cast<I*> (register_and_open (desc_)))
|
||||||
{ }
|
, facadeLink_(*this)
|
||||||
|
{
|
||||||
|
throwIfError();
|
||||||
|
}
|
||||||
|
|
||||||
~InstanceHandle ()
|
~InstanceHandle ()
|
||||||
{
|
{
|
||||||
lumiera_interface_close (&instance_->interface_header_);
|
lumiera_interface_close (&instance_->interface_header_);
|
||||||
if (desc_)
|
if (desc_)
|
||||||
lumiera_interfaceregistry_bulkremove_interfaces (desc_);
|
lumiera_interfaceregistry_remove_interface (desc_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** act as smart pointer providing access through the facade.
|
/** 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* */
|
* @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_; }
|
I& get () const { ENSURE(instance_); return *instance_; }
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -164,13 +241,6 @@ namespace lumiera {
|
||||||
|
|
||||||
|
|
||||||
private:
|
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
|
bool
|
||||||
isValid() const
|
isValid() const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -21,65 +21,118 @@
|
||||||
* *****************************************************/
|
* *****************************************************/
|
||||||
|
|
||||||
|
|
||||||
#include "lib/singletonsubclass.hpp"
|
#include "include/interfaceproxy.hpp"
|
||||||
#include "include/guinotificationfacade.h"
|
#include "common/instancehandle.hpp"
|
||||||
#include "lib/util.hpp"
|
|
||||||
#include "lib/error.hpp"
|
#include "lib/error.hpp"
|
||||||
|
#include "lib/util.hpp"
|
||||||
extern "C" {
|
|
||||||
#include "common/interface.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
using util::cStr;
|
using util::cStr;
|
||||||
|
|
||||||
|
|
||||||
namespace singleton = lumiera::singleton;
|
#include "include/guinotificationfacade.h"
|
||||||
|
|
||||||
namespace gui {
|
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 */
|
/** storage for the facade proxy factory used by client code to invoke through the interface */
|
||||||
lumiera::SingletonSub<GuiNotification> GuiNotification::facade (typeinfo_proxyInstance_to_create);
|
lumiera::facade::Accessor<GuiNotification> GuiNotification::facade;
|
||||||
|
|
||||||
///////////////////////////////////////TODO: this solution is not correct, because it doesn't detect when the interface is shut down!
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace gui
|
} // 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 "common/subsys.hpp"
|
||||||
|
|
||||||
#include "lib/error.hpp"
|
|
||||||
//#include "lib/util.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
//using util::isnil;
|
|
||||||
//using util::cStr;
|
|
||||||
|
|
||||||
namespace lumiera {
|
namespace lumiera {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Subsys::~Subsys() { }
|
Subsys::~Subsys() { }
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -43,7 +36,6 @@ namespace lumiera {
|
||||||
Subsys&
|
Subsys&
|
||||||
Subsys::depends (Subsys& prereq)
|
Subsys::depends (Subsys& prereq)
|
||||||
{
|
{
|
||||||
TODO ("anything else to care when defining a dependency on the prerequisite subsystem??");/////////////////////TODO
|
|
||||||
prereq_.push_back(&prereq);
|
prereq_.push_back(&prereq);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
@ -53,7 +45,6 @@ namespace lumiera {
|
||||||
bool
|
bool
|
||||||
Subsys::isRunning()
|
Subsys::isRunning()
|
||||||
{
|
{
|
||||||
//Lock guard (this);
|
|
||||||
return checkRunningState();
|
return checkRunningState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,12 +65,13 @@ namespace lumiera {
|
||||||
* Dependencies and lifecycle of a partially independent Subsystem of the Application.
|
* Dependencies and lifecycle of a partially independent Subsystem of the Application.
|
||||||
* Using such descriptors, AppState as activated from main() is able to pull up,
|
* Using such descriptors, AppState as activated from main() is able to pull up,
|
||||||
* maintain and shut down the primary parts of the Application.
|
* maintain and shut down the primary parts of the Application.
|
||||||
|
* @note synchronisation is up to the implementor.
|
||||||
*/
|
*/
|
||||||
class Subsys
|
class Subsys
|
||||||
: private noncopyable
|
: private noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef function<void(Error*)> SigTerm;
|
typedef function<void(string*)> SigTerm;
|
||||||
|
|
||||||
virtual ~Subsys();
|
virtual ~Subsys();
|
||||||
|
|
||||||
|
|
@ -82,7 +83,8 @@ namespace lumiera {
|
||||||
* required for running this subsystem */
|
* required for running this subsystem */
|
||||||
Subsys& depends (Subsys& prereq);
|
Subsys& depends (Subsys& prereq);
|
||||||
|
|
||||||
/** @return true if Up */
|
/** @return true if Up
|
||||||
|
* @warning must not block nor throw. */
|
||||||
bool isRunning();
|
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
|
Copyright (C) Lumiera.org
|
||||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
#include <tr1/functional>
|
#include <tr1/functional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
namespace lumiera {
|
namespace lumiera {
|
||||||
|
|
@ -39,13 +40,22 @@ namespace lumiera {
|
||||||
using std::tr1::function;
|
using std::tr1::function;
|
||||||
using std::tr1::placeholders::_1;
|
using std::tr1::placeholders::_1;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
using std::string;
|
||||||
using util::cStr;
|
using util::cStr;
|
||||||
using util::isnil;
|
using util::isnil;
|
||||||
using util::and_all;
|
using util::and_all;
|
||||||
using util::for_each;
|
using util::for_each;
|
||||||
using util::removeall;
|
using util::removeall;
|
||||||
|
using lib::Sync;
|
||||||
|
using lib::RecursiveLock_Waitable;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
/** limit waiting for subsystem shutdown in case of
|
||||||
|
* an emergency shutdown to max 2 seconds */
|
||||||
|
const uint EMERGENCYTIMEOUT = 2000;
|
||||||
|
|
||||||
|
|
||||||
function<bool(Subsys*)>
|
function<bool(Subsys*)>
|
||||||
isRunning() {
|
isRunning() {
|
||||||
return bind (&Subsys::isRunning, _1);
|
return bind (&Subsys::isRunning, _1);
|
||||||
|
|
@ -76,10 +86,9 @@ namespace lumiera {
|
||||||
* Usually, the startup process is conducted from one (main) thread, which enters
|
* Usually, the startup process is conducted from one (main) thread, which enters
|
||||||
* a blocking wait() after starting the subsystems. Awakened by some termination
|
* a blocking wait() after starting the subsystems. Awakened by some termination
|
||||||
* signal from one of the subsystems, termination of any remaining subsystems
|
* 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.
|
* 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* ??
|
* @todo maybe use my refArray (see builder) to use Subsys& instead of Subsys* ??
|
||||||
*
|
*
|
||||||
* @see lumiera::AppState
|
* @see lumiera::AppState
|
||||||
|
|
@ -87,7 +96,7 @@ namespace lumiera {
|
||||||
* @see main.cpp
|
* @see main.cpp
|
||||||
*/
|
*/
|
||||||
class SubsystemRunner
|
class SubsystemRunner
|
||||||
// : Sync
|
: public Sync<RecursiveLock_Waitable>
|
||||||
{
|
{
|
||||||
Option& opts_;
|
Option& opts_;
|
||||||
volatile bool emergency_;
|
volatile bool emergency_;
|
||||||
|
|
@ -109,48 +118,57 @@ namespace lumiera {
|
||||||
void
|
void
|
||||||
maybeRun (Subsys& susy)
|
maybeRun (Subsys& susy)
|
||||||
{
|
{
|
||||||
//Lock guard (this);
|
Lock guard (this);
|
||||||
|
|
||||||
if (!susy.isRunning() && susy.shouldStart (opts_))
|
if (!susy.isRunning() && susy.shouldStart (opts_))
|
||||||
triggerStartup (&susy);
|
triggerStartup (&susy);
|
||||||
if (susy.isRunning())
|
|
||||||
running_.push_back (&susy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
shutdownAll ()
|
shutdownAll ()
|
||||||
{
|
{
|
||||||
//Lock guard (this);
|
Lock guard (this);
|
||||||
for_each (running_, killIt_);
|
for_each (running_, killIt_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
triggerEmergency (bool cond)
|
||||||
|
{
|
||||||
|
Lock guard (this);
|
||||||
|
if (cond) emergency_= true;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
wait ()
|
wait ()
|
||||||
{
|
{
|
||||||
//Lock(this).wait (&SubsystemRunner::allDead);
|
Lock wait_blocking(this, &SubsystemRunner::allDead);
|
||||||
return isEmergencyExit();
|
return isEmergencyExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isEmergencyExit () { return emergency_; }
|
|
||||||
void triggerEmergency (bool cond) { emergency_ |= cond; }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool isEmergencyExit () { return emergency_; }
|
||||||
|
|
||||||
void
|
void
|
||||||
triggerStartup (Subsys* susy)
|
triggerStartup (Subsys* susy)
|
||||||
{
|
{
|
||||||
ASSERT (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_);
|
for_each (susy->getPrerequisites(), start_);
|
||||||
bool started = susy->start (opts_, bind (&SubsystemRunner::sigTerm, this, susy, _1));
|
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() ))
|
if (!and_all (susy->getPrerequisites(), isRunning() ))
|
||||||
{
|
{
|
||||||
susy->triggerShutdown();
|
susy->triggerShutdown();
|
||||||
|
|
@ -158,23 +176,29 @@ namespace lumiera {
|
||||||
} }
|
} }
|
||||||
|
|
||||||
void
|
void
|
||||||
sigTerm (Subsys* susy, Error* problem) ///< called from subsystem on termination
|
sigTerm (Subsys* susy, string* problem) ///< called from subsystem on termination
|
||||||
{
|
{
|
||||||
ASSERT (susy);
|
ASSERT (susy);
|
||||||
//Lock guard (this);
|
Lock sync (this);
|
||||||
triggerEmergency(problem);
|
triggerEmergency(!isnil (problem));
|
||||||
|
INFO (operate, "Subsystem '%s' terminated.", cStr(*susy));
|
||||||
|
WARN_IF (!isnil(problem), operate, "Irregular shutdown caused by: %s", cStr(*problem));
|
||||||
ERROR_IF (susy->isRunning(), lumiera, "Subsystem '%s' signals termination, "
|
ERROR_IF (susy->isRunning(), lumiera, "Subsystem '%s' signals termination, "
|
||||||
"without resetting running state", cStr(*susy));
|
"without resetting running state", cStr(*susy));
|
||||||
removeall (running_, susy);
|
removeall (running_, susy);
|
||||||
shutdownAll();
|
shutdownAll();
|
||||||
//guard.notify();
|
sync.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
allDead ()
|
allDead ()
|
||||||
{
|
{
|
||||||
if (isEmergencyExit())
|
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
|
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_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wall -Wextra -Werror
|
||||||
gtk_gui_la_CXXFLAGS = $(AM_CXXFLAGS) -Wall -Wextra
|
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_LDFLAGS = -module -avoid-version -no-undefined -rpath /dev/null -shrext .lum
|
||||||
|
|
||||||
gtk_gui_la_LIBADD = \
|
gtk_gui_la_LIBADD = \
|
||||||
|
|
@ -72,10 +72,11 @@ gtk_gui_la_LIBADD = \
|
||||||
liblumierabackend.la \
|
liblumierabackend.la \
|
||||||
liblumieraproc.la \
|
liblumieraproc.la \
|
||||||
liblumiera.la \
|
liblumiera.la \
|
||||||
|
libgui.la \
|
||||||
$(LUMIERA_GUI_LIBS) \
|
$(LUMIERA_GUI_LIBS) \
|
||||||
$(NOBUGMT_LUMIERA_LIBS)
|
$(NOBUGMT_LUMIERA_LIBS)
|
||||||
|
|
||||||
gtk_gui_la_SOURCES = \
|
gtk_gui_la_SOURCES = \
|
||||||
$(lumigui_srcdir)/guistart.cpp
|
$(lumigui_srcdir)/guistart.cpp
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -94,18 +95,18 @@ libgui_la_CPPFLAGS = $(AM_CPPFLAGS) \
|
||||||
$(LUMIERA_GUI_CFLAGS)
|
$(LUMIERA_GUI_CFLAGS)
|
||||||
|
|
||||||
libgui_la_SOURCES = \
|
libgui_la_SOURCES = \
|
||||||
$(lumigui_srcdir)/guinotificationfacade.cpp \
|
$(lumigui_srcdir)/notification-service.cpp \
|
||||||
$(lumigui_srcdir)/window-manager.cpp \
|
$(lumigui_srcdir)/window-manager.cpp \
|
||||||
$(lumigui_srcdir)/window-manager.hpp \
|
$(lumigui_srcdir)/window-manager.hpp \
|
||||||
$(lumigui_srcdir)/workspace/actions.cpp \
|
$(lumigui_srcdir)/workspace/actions.cpp \
|
||||||
$(lumigui_srcdir)/workspace/actions.hpp \
|
$(lumigui_srcdir)/workspace/actions.hpp \
|
||||||
$(lumigui_srcdir)/workspace/workspace-window.cpp \
|
$(lumigui_srcdir)/workspace/workspace-window.cpp \
|
||||||
$(lumigui_srcdir)/workspace/workspace-window.hpp \
|
$(lumigui_srcdir)/workspace/workspace-window.hpp \
|
||||||
$(lumigui_srcdir)/dialogs/dialog.hpp \
|
$(lumigui_srcdir)/dialogs/dialog.hpp \
|
||||||
$(lumigui_srcdir)/dialogs/render.cpp \
|
$(lumigui_srcdir)/dialogs/render.cpp \
|
||||||
$(lumigui_srcdir)/dialogs/render.hpp \
|
$(lumigui_srcdir)/dialogs/render.hpp \
|
||||||
$(lumigui_srcdir)/dialogs/preferences-dialog.cpp \
|
$(lumigui_srcdir)/dialogs/preferences-dialog.cpp \
|
||||||
$(lumigui_srcdir)/dialogs/preferences-dialog.hpp \
|
$(lumigui_srcdir)/dialogs/preferences-dialog.hpp \
|
||||||
$(lumigui_srcdir)/dialogs/name-chooser.cpp \
|
$(lumigui_srcdir)/dialogs/name-chooser.cpp \
|
||||||
$(lumigui_srcdir)/dialogs/name-chooser.hpp \
|
$(lumigui_srcdir)/dialogs/name-chooser.hpp \
|
||||||
$(lumigui_srcdir)/panels/panel.cpp \
|
$(lumigui_srcdir)/panels/panel.cpp \
|
||||||
|
|
@ -152,14 +153,14 @@ libgui_la_SOURCES = \
|
||||||
$(lumigui_srcdir)/model/track.hpp \
|
$(lumigui_srcdir)/model/track.hpp \
|
||||||
$(lumigui_srcdir)/model/clip-track.cpp \
|
$(lumigui_srcdir)/model/clip-track.cpp \
|
||||||
$(lumigui_srcdir)/model/clip-track.hpp \
|
$(lumigui_srcdir)/model/clip-track.hpp \
|
||||||
$(lumigui_srcdir)/model/parent-track.cpp \
|
$(lumigui_srcdir)/model/parent-track.cpp \
|
||||||
$(lumigui_srcdir)/model/parent-track.hpp \
|
$(lumigui_srcdir)/model/parent-track.hpp \
|
||||||
$(lumigui_srcdir)/model/group-track.cpp \
|
$(lumigui_srcdir)/model/group-track.cpp \
|
||||||
$(lumigui_srcdir)/model/group-track.hpp \
|
$(lumigui_srcdir)/model/group-track.hpp \
|
||||||
$(lumigui_srcdir)/model/sequence.cpp \
|
$(lumigui_srcdir)/model/sequence.cpp \
|
||||||
$(lumigui_srcdir)/model/sequence.hpp \
|
$(lumigui_srcdir)/model/sequence.hpp \
|
||||||
$(lumigui_srcdir)/model/clip.cpp \
|
$(lumigui_srcdir)/model/clip.cpp \
|
||||||
$(lumigui_srcdir)/model/clip.hpp \
|
$(lumigui_srcdir)/model/clip.hpp \
|
||||||
$(lumigui_srcdir)/output/displayer.cpp \
|
$(lumigui_srcdir)/output/displayer.cpp \
|
||||||
$(lumigui_srcdir)/output/displayer.hpp \
|
$(lumigui_srcdir)/output/displayer.hpp \
|
||||||
$(lumigui_srcdir)/output/gdkdisplayer.cpp \
|
$(lumigui_srcdir)/output/gdkdisplayer.cpp \
|
||||||
|
|
|
||||||
|
|
@ -47,20 +47,14 @@ using namespace gui::model;
|
||||||
|
|
||||||
GtkLumiera the_application;
|
GtkLumiera the_application;
|
||||||
|
|
||||||
int
|
|
||||||
main (int argc, char *argv[])
|
|
||||||
{
|
|
||||||
return the_application.main(argc, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace gui {
|
namespace gui {
|
||||||
|
|
||||||
int
|
void
|
||||||
GtkLumiera::main(int argc, char *argv[])
|
GtkLumiera::main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
NOBUG_INIT;
|
|
||||||
|
|
||||||
Main kit(argc, argv);
|
Main kit(argc, argv);
|
||||||
|
|
||||||
|
|
@ -75,9 +69,9 @@ GtkLumiera::main(int argc, char *argv[])
|
||||||
|
|
||||||
kit.run(main_window);
|
kit.run(main_window);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Glib::ustring
|
Glib::ustring
|
||||||
GtkLumiera::get_home_data_path()
|
GtkLumiera::get_home_data_path()
|
||||||
{
|
{
|
||||||
|
|
@ -109,3 +103,14 @@ const int GtkLumiera::AppAuthorCount = 4;
|
||||||
} // namespace gui
|
} // 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
|
#define GTK_LUMIERA_HPP
|
||||||
|
|
||||||
#include <gtkmm.h>
|
#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 <vector>
|
||||||
#include <boost/utility.hpp>
|
#include <boost/utility.hpp>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
|
@ -69,7 +69,7 @@ namespace gui {
|
||||||
class GtkLumiera : private boost::noncopyable
|
class GtkLumiera : private boost::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
int main(int argc, char *argv[]);
|
void main(int argc, char *argv[]);
|
||||||
|
|
||||||
static Glib::ustring get_home_data_path();
|
static Glib::ustring get_home_data_path();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ namespace gui {
|
||||||
* @internal this function is invoked automatically during the GUI
|
* @internal this function is invoked automatically during the GUI
|
||||||
* loading and startup process. Don't call it manually.
|
* loading and startup process. Don't call it manually.
|
||||||
*/
|
*/
|
||||||
virtual bool kickOff (lumiera::Subsys::SigTerm&) =0;
|
virtual void kickOff (lumiera::Subsys::SigTerm&) =0;
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
@ -100,7 +100,7 @@ namespace gui {
|
||||||
|
|
||||||
/** interface of the GuiStarterPlugin */
|
/** interface of the GuiStarterPlugin */
|
||||||
LUMIERA_INTERFACE_DECLARE (lumieraorg_Gui, 1,
|
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
|
/** @file guistart.cpp
|
||||||
** Start up the Lumiera GTK GUI when loading it as dynamic module.
|
** 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
|
** 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
|
** Lumiera plugin, it allows to kick off the GTK main event loop and thus to bring
|
||||||
** the GUI. The loading and shutdown process is carried out by gui::GuiFacade and
|
** 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().
|
** 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
|
** 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
|
** issued, passing a termination signal (callback) to be executed when the GUI
|
||||||
** terminates. This call returns immediately, after spawning off the main thread
|
** terminates. The \c kickOff() call remains blocked within the main GTK event loop;
|
||||||
** and setting up the termination callback accordingly. Additionally, it cares
|
** thus typically this call should be issued within a separate dedicated GUI thread.
|
||||||
** for opening the primary "business" interface of the GUI, i.e. the interface
|
** Especially, the gui::GuiRunner will ensure this to happen.
|
||||||
** gui::GuiNotification.
|
**
|
||||||
|
** 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 lumiera::AppState
|
||||||
** @see gui::GuiFacade
|
** @see gui::GuiFacade
|
||||||
** @see guifacade.cpp
|
** @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/guifacade.hpp"
|
||||||
|
#include "gui/notification-service.hpp"
|
||||||
#include "common/subsys.hpp"
|
#include "common/subsys.hpp"
|
||||||
#include "lib/singleton.hpp"
|
#include "lib/singleton.hpp"
|
||||||
|
|
||||||
|
|
@ -54,12 +62,9 @@ extern "C" {
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
#include <iostream> /////////////TODO
|
|
||||||
using std::cout; //////////////TODO
|
|
||||||
|
|
||||||
|
|
||||||
using lumiera::Subsys;
|
using lumiera::Subsys;
|
||||||
using gui::LUMIERA_INTERFACE_INAME(lumieraorg_Gui, 1);
|
using gui::LUMIERA_INTERFACE_INAME(lumieraorg_Gui, 1);
|
||||||
|
|
||||||
|
|
@ -69,28 +74,61 @@ namespace gui {
|
||||||
namespace { // implementation details
|
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
|
struct GuiLifecycle
|
||||||
: public GuiFacade
|
|
||||||
{
|
{
|
||||||
|
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"
|
reportOnTermination_(&error_); // inform main thread that the GUI has been shut down.
|
||||||
<< " this is the GuiStarterPlugin speaking!\n"
|
}
|
||||||
<< " now, the Lumiera GUI should be spawned....\n"
|
|
||||||
<< " but actually nothing happens!!!!!!!!!!!!!!\n\n";
|
|
||||||
|
void
|
||||||
terminationHandle(0); // signal immediate shutdown without error
|
run ()
|
||||||
return true;
|
{
|
||||||
|
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
|
} // (End) impl details
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
kickOff (Subsys::SigTerm& reportTermination)
|
||||||
|
{
|
||||||
|
GuiLifecycle(reportTermination).run();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace gui
|
} // namespace gui
|
||||||
|
|
||||||
|
|
@ -179,10 +217,9 @@ extern "C" { /* ================== define an lumieraorg_Gui instance ===========
|
||||||
, NULL /* on open */
|
, NULL /* on open */
|
||||||
, NULL /* on close */
|
, NULL /* on close */
|
||||||
, LUMIERA_INTERFACE_INLINE (kickOff, "\255\142\006\244\057\170\152\312\301\372\220\323\230\026\200\065",
|
, LUMIERA_INTERFACE_INLINE (kickOff, "\255\142\006\244\057\170\152\312\301\372\220\323\230\026\200\065",
|
||||||
bool, (void* termSig),
|
void, (void* termSig),
|
||||||
{
|
{
|
||||||
return gui::facade_().kickOff (
|
gui::kickOff (*reinterpret_cast<Subsys::SigTerm *> (termSig));
|
||||||
*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
|
Copyright (C) Lumiera.org
|
||||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
* *****************************************************/
|
* *****************************************************/
|
||||||
|
|
||||||
|
|
||||||
#include "include/guinotificationfacade.h"
|
#include "gui/notification-service.hpp"
|
||||||
#include "lib/singleton.hpp"
|
#include "lib/singleton.hpp"
|
||||||
#include "include/nobugcfg.h"
|
#include "include/nobugcfg.h"
|
||||||
#include "lib/util.hpp"
|
#include "lib/util.hpp"
|
||||||
|
|
@ -33,35 +33,33 @@ extern "C" {
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace gui {
|
namespace gui {
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using util::cStr;
|
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
|
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 ======================= */
|
/* ================== define an lumieraorg_GuiNotification instance ======================= */
|
||||||
|
|
||||||
LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0
|
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
|
LUMIERA_INTERFACE_INSTANCE (lumieraorg_GuiNotification, 1
|
||||||
,lumieraorg_GuiNotificationFacade
|
,lumieraorg_GuiNotificationFacade
|
||||||
, LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_GuiNotificationFacade_descriptor)
|
, LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_GuiNotificationFacade_descriptor)
|
||||||
|
|
@ -138,15 +146,37 @@ namespace gui {
|
||||||
, NULL /* on close */
|
, NULL /* on close */
|
||||||
, LUMIERA_INTERFACE_INLINE (displayInfo, "\366\075\213\163\207\040\221\233\010\366\174\374\317\126\331\205",
|
, LUMIERA_INTERFACE_INLINE (displayInfo, "\366\075\213\163\207\040\221\233\010\366\174\374\317\126\331\205",
|
||||||
void, (const char* text),
|
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",
|
, LUMIERA_INTERFACE_INLINE (triggerGuiShutdown, "\267\043\244\065\107\314\370\175\063\330\264\257\302\146\326\303",
|
||||||
void, (const char* cause),
|
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
|
} // (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
|
} // 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
|
/** @file guinotificationfacade.hpp
|
||||||
** Interface for the GUI loader and for accessing the GUI interface from the
|
** Main public Interface of the Lumiera GUI. While generally speaking, the GUI
|
||||||
** lower layers of Lumiera. While part of the public interface of the Lumiera GUI,
|
** controls the application and thus acts on its own, it exposes some services
|
||||||
** the implementation of this facility is part of the core application (and not
|
** usable by scripts or the two lower layers. The main purpose of these services
|
||||||
** contained within the GUI dynamic module), because it's job is to load and
|
** is to push informations and status updates into the GUI.
|
||||||
** activate this module and to startup the GUI.
|
|
||||||
**
|
**
|
||||||
** @see lumiera::AppState
|
** @see gui::GuiFacade
|
||||||
** @see lumiera::Option
|
|
||||||
** @see guifacade.cpp
|
|
||||||
** @see main.cpp
|
** @see main.cpp
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -40,7 +37,7 @@
|
||||||
|
|
||||||
#ifdef __cplusplus /* ============== C++ Interface ================= */
|
#ifdef __cplusplus /* ============== C++ Interface ================= */
|
||||||
|
|
||||||
#include "lib/singletonsubclass.hpp"
|
#include "include/interfaceproxy.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
@ -63,7 +60,7 @@ namespace gui {
|
||||||
class GuiNotification
|
class GuiNotification
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static lumiera::SingletonSub<GuiNotification> facade;
|
static lumiera::facade::Accessor<GuiNotification> facade;
|
||||||
|
|
||||||
/** push a user visible notification text */
|
/** push a user visible notification text */
|
||||||
virtual void displayInfo (string const& text) =0;
|
virtual void displayInfo (string const& text) =0;
|
||||||
|
|
@ -83,7 +80,7 @@ namespace gui {
|
||||||
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif /* =========================== CLI Interface ================= */
|
#endif /* =========================== CL Interface ===================== */
|
||||||
|
|
||||||
|
|
||||||
#include "common/interface.h"
|
#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
|
/** @file symbol.hpp
|
||||||
** WIP placeholder definition for a planned Symbol datatype.
|
** 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.
|
** 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
|
** For now we just a typedef is sufficient. A real Symbol datatype should
|
||||||
** - be definable by string constant
|
** - be definable by string constant
|
||||||
|
|
@ -41,11 +41,14 @@
|
||||||
#define LUMIERA_SYMBOL_H
|
#define LUMIERA_SYMBOL_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
namespace lumiera {
|
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)/rwlock.c \
|
||||||
$(liblumiera_la_srcdir)/condition.c \
|
$(liblumiera_la_srcdir)/condition.c \
|
||||||
$(liblumiera_la_srcdir)/reccondition.c \
|
$(liblumiera_la_srcdir)/reccondition.c \
|
||||||
|
$(liblumiera_la_srcdir)/threads.c \
|
||||||
$(liblumiera_la_srcdir)/luid.c \
|
$(liblumiera_la_srcdir)/luid.c \
|
||||||
$(liblumiera_la_srcdir)/safeclib.c \
|
$(liblumiera_la_srcdir)/safeclib.c \
|
||||||
$(liblumiera_la_srcdir)/psplay.c \
|
$(liblumiera_la_srcdir)/psplay.c \
|
||||||
|
|
@ -52,6 +53,7 @@ noinst_HEADERS += \
|
||||||
$(liblumiera_la_srcdir)/rwlock.h \
|
$(liblumiera_la_srcdir)/rwlock.h \
|
||||||
$(liblumiera_la_srcdir)/condition.h \
|
$(liblumiera_la_srcdir)/condition.h \
|
||||||
$(liblumiera_la_srcdir)/reccondition.h \
|
$(liblumiera_la_srcdir)/reccondition.h \
|
||||||
|
$(liblumiera_la_srcdir)/threads.h \
|
||||||
$(liblumiera_la_srcdir)/luid.h \
|
$(liblumiera_la_srcdir)/luid.h \
|
||||||
$(liblumiera_la_srcdir)/safeclib.h \
|
$(liblumiera_la_srcdir)/safeclib.h \
|
||||||
$(liblumiera_la_srcdir)/psplay.h \
|
$(liblumiera_la_srcdir)/psplay.h \
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
#include "lib/allocationcluster.hpp"
|
#include "lib/allocationcluster.hpp"
|
||||||
#include "lib/error.hpp"
|
#include "lib/error.hpp"
|
||||||
#include "lib/util.hpp"
|
#include "lib/util.hpp"
|
||||||
|
#include "lib/sync.hpp"
|
||||||
|
|
||||||
using util::isnil;
|
using util::isnil;
|
||||||
|
|
||||||
|
|
@ -38,9 +39,9 @@ namespace lib {
|
||||||
* successful ctor call of the object being allocated. Allocations and commits
|
* successful ctor call of the object being allocated. Allocations and commits
|
||||||
* can be assumed to come in pairs, thus if an allocation immediately follows
|
* can be assumed to come in pairs, thus if an allocation immediately follows
|
||||||
* another one (without commit), the previous allocation can be considered
|
* 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
|
* (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
|
* it's dtor, either on shutdown or on explicit #purge() -- the type info
|
||||||
* structure handed in on initialisation provides a means for invoking
|
* structure handed in on initialisation provides a means for invoking
|
||||||
* the dtor without actually knowing the object's type.
|
* the dtor without actually knowing the object's type.
|
||||||
|
|
@ -55,6 +56,7 @@ namespace lib {
|
||||||
* on real-world measurements, not guessing.
|
* on real-world measurements, not guessing.
|
||||||
*/
|
*/
|
||||||
class AllocationCluster::MemoryManager
|
class AllocationCluster::MemoryManager
|
||||||
|
: public Sync<RecursiveLock_NoWait>
|
||||||
{
|
{
|
||||||
typedef std::vector<char*> MemTable;
|
typedef std::vector<char*> MemTable;
|
||||||
TypeInfo type_;
|
TypeInfo type_;
|
||||||
|
|
@ -81,7 +83,7 @@ namespace lib {
|
||||||
void
|
void
|
||||||
AllocationCluster::MemoryManager::reset (TypeInfo info)
|
AllocationCluster::MemoryManager::reset (TypeInfo info)
|
||||||
{
|
{
|
||||||
ClassLock<MemoryManager> guard();
|
Lock instance();
|
||||||
|
|
||||||
if (0 < mem_.size()) purge();
|
if (0 < mem_.size()) purge();
|
||||||
type_ = info;
|
type_ = info;
|
||||||
|
|
@ -96,7 +98,7 @@ namespace lib {
|
||||||
void
|
void
|
||||||
AllocationCluster::MemoryManager::purge()
|
AllocationCluster::MemoryManager::purge()
|
||||||
{
|
{
|
||||||
ClassLock<MemoryManager> guard();
|
Lock instance();
|
||||||
|
|
||||||
REQUIRE (type_.killIt, "we need a deleter function");
|
REQUIRE (type_.killIt, "we need a deleter function");
|
||||||
REQUIRE (0 < type_.allocSize, "allocation size unknown");
|
REQUIRE (0 < type_.allocSize, "allocation size unknown");
|
||||||
|
|
@ -120,7 +122,7 @@ namespace lib {
|
||||||
inline void*
|
inline void*
|
||||||
AllocationCluster::MemoryManager::allocate()
|
AllocationCluster::MemoryManager::allocate()
|
||||||
{
|
{
|
||||||
ClassLock<MemoryManager> guard();
|
Lock instance();
|
||||||
|
|
||||||
REQUIRE (0 < type_.allocSize);
|
REQUIRE (0 < type_.allocSize);
|
||||||
REQUIRE (top_ <= mem_.size());
|
REQUIRE (top_ <= mem_.size());
|
||||||
|
|
@ -140,7 +142,7 @@ namespace lib {
|
||||||
inline void
|
inline void
|
||||||
AllocationCluster::MemoryManager::commit (void* pendingAlloc)
|
AllocationCluster::MemoryManager::commit (void* pendingAlloc)
|
||||||
{
|
{
|
||||||
ClassLock<MemoryManager> guard();
|
Lock instance();
|
||||||
|
|
||||||
REQUIRE (pendingAlloc);
|
REQUIRE (pendingAlloc);
|
||||||
ASSERT (top_ < mem_.size());
|
ASSERT (top_ < mem_.size());
|
||||||
|
|
@ -174,8 +176,8 @@ namespace lib {
|
||||||
AllocationCluster::~AllocationCluster() throw()
|
AllocationCluster::~AllocationCluster() throw()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{ // avoiding a per-instance lock for now.
|
||||||
ClassLock<AllocationCluster> guard();
|
ClassLock<AllocationCluster> guard(); // (see note in the class description)
|
||||||
|
|
||||||
TRACE (memory, "shutting down AllocationCluster");
|
TRACE (memory, "shutting down AllocationCluster");
|
||||||
for (size_t i = typeHandlers_.size(); 0 < i; --i)
|
for (size_t i = typeHandlers_.size(); 0 < i; --i)
|
||||||
|
|
@ -213,8 +215,8 @@ namespace lib {
|
||||||
{
|
{
|
||||||
ASSERT (0 < slot);
|
ASSERT (0 < slot);
|
||||||
|
|
||||||
{
|
{ // avoiding a per-instance lock for now.
|
||||||
ClassLock<AllocationCluster> guard(); /////TODO: decide tradeoff: lock just the instance, or lock the AllocationCluster class?
|
ClassLock<AllocationCluster> guard(); // (see note in the class description)
|
||||||
|
|
||||||
if (slot > typeHandlers_.size())
|
if (slot > typeHandlers_.size())
|
||||||
typeHandlers_.resize(slot);
|
typeHandlers_.resize(slot);
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,12 @@ namespace lib {
|
||||||
* the object families are to be discarded. Currently
|
* the object families are to be discarded. Currently
|
||||||
* they are just purged in reverse order defined by
|
* they are just purged in reverse order defined by
|
||||||
* the first request for allocating a certain type.
|
* 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
|
class AllocationCluster
|
||||||
: boost::noncopyable
|
: boost::noncopyable
|
||||||
|
|
|
||||||
|
|
@ -39,14 +39,11 @@ using util::contains;
|
||||||
using util::isnil;
|
using util::isnil;
|
||||||
|
|
||||||
|
|
||||||
namespace lumiera
|
namespace lumiera {
|
||||||
{
|
namespace query {
|
||||||
|
|
||||||
namespace query
|
namespace { // local definitions
|
||||||
{
|
|
||||||
|
|
||||||
namespace // local definitions
|
|
||||||
{
|
|
||||||
typedef boost::function<bool(string::value_type)> ChPredicate;
|
typedef boost::function<bool(string::value_type)> ChPredicate;
|
||||||
|
|
||||||
ChPredicate is_alpha = boost::algorithm::is_alpha();
|
ChPredicate is_alpha = boost::algorithm::is_alpha();
|
||||||
|
|
@ -92,8 +89,8 @@ namespace lumiera
|
||||||
/** (preliminary) helper: instead of really parsing and evaluating the terms,
|
/** (preliminary) helper: instead of really parsing and evaluating the terms,
|
||||||
* just do a regular expression match to extract the literal argument
|
* just do a regular expression match to extract the literal argument
|
||||||
* behind the given predicate symbol. e.g calling
|
* behind the given predicate symbol. e.g calling
|
||||||
* queryID ("stream", "id(abc), stream(mpeg)")
|
* \code extractID ("stream", "id(abc), stream(mpeg)") \endcode
|
||||||
* yields "mpeg"
|
* yields \c "mpeg"
|
||||||
*/
|
*/
|
||||||
const string
|
const string
|
||||||
extractID (Symbol sym, const string& termString)
|
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
|
** This configuration header just pulls in some other implementation headers in
|
||||||
** the right order. The basic class template for creating singletons resides in
|
** the right order. The basic class template for creating singletons resides in
|
||||||
** singletonfactory.hpp, besides we need policy classes defining how to create
|
** 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;
|
** we want to preconfigure singleton factories for some important facilities;
|
||||||
** e.g. sometimes we want to include a hook for injecting Test Mock instances.
|
** 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/singletonpolicies.hpp" // several Policies usable together with SingletonFactory
|
||||||
|
|
||||||
#include "lib/util.hpp"
|
|
||||||
#include "include/nobugcfg.h"
|
#include "include/nobugcfg.h"
|
||||||
|
#include "lib/util.hpp"
|
||||||
|
#include "lib/sync-classlock.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace lumiera
|
namespace lumiera {
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A configurable Template for implementing Singletons.
|
* 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.
|
* 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
|
template
|
||||||
< class SI // the class of the Singleton instance
|
< class SI
|
||||||
, template <class> class Create = singleton::StaticCreate // how to create/destroy the instance
|
, template <class> class Create = singleton::StaticCreate
|
||||||
, template <class> class Life = singleton::AutoDestroy // how to manage Singleton Lifecycle
|
, template <class> class Life = singleton::AutoDestroy
|
||||||
, template <class> class Threading = singleton::IgnoreThreadsafety //TODO use Multithreaded!!!
|
|
||||||
>
|
>
|
||||||
class SingletonFactory
|
class SingletonFactory
|
||||||
{
|
{
|
||||||
typedef typename Threading<SI>::VolatileType SType;
|
typedef SI* volatile PType;
|
||||||
typedef typename Threading<SI>::Lock ThreadLock;
|
typedef lib::ClassLock<SI> ThreadLock;
|
||||||
static SType* pInstance_;
|
|
||||||
|
static PType pInstance_;
|
||||||
static bool isDead_;
|
static bool isDead_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -110,21 +119,19 @@ namespace lumiera
|
||||||
template
|
template
|
||||||
< class SI,
|
< class SI,
|
||||||
template <class> class C,
|
template <class> class C,
|
||||||
template <class> class L,
|
template <class> class L
|
||||||
template <class> class T
|
|
||||||
>
|
>
|
||||||
typename SingletonFactory<SI,C,L,T>::SType*
|
typename SingletonFactory<SI,C,L>::PType
|
||||||
SingletonFactory<SI,C,L,T>::pInstance_;
|
SingletonFactory<SI,C,L>::pInstance_;
|
||||||
|
|
||||||
template
|
template
|
||||||
< class SI,
|
< class SI,
|
||||||
template <class> class C,
|
template <class> class C,
|
||||||
template <class> class L,
|
template <class> class L
|
||||||
template <class> class T
|
|
||||||
>
|
>
|
||||||
bool SingletonFactory<SI,C,L,T>::isDead_;
|
bool SingletonFactory<SI,C,L>::isDead_;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///// TODO: get rid of the static fields?
|
///// TODO: get rid of the static fields?
|
||||||
///// is tricky because of invoking the destructors. If we rely on instance vars,
|
///// 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.
|
///// destructors of static objects at shutdown.
|
||||||
///// It seems this would either cost us much of the flexibility or get complicated
|
///// 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.
|
///// to a point where we could as well implement our own Dependency Injection Manager.
|
||||||
|
|
||||||
} // namespace lumiera
|
} // namespace lumiera
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ This code is heavily inspired by
|
||||||
#define LUMIERA_SINGLETONPOLICIES_H
|
#define LUMIERA_SINGLETONPOLICIES_H
|
||||||
|
|
||||||
#include "lib/error.hpp"
|
#include "lib/error.hpp"
|
||||||
#include "lib/sync-classlock.hpp"
|
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
@ -84,7 +83,7 @@ namespace lumiera {
|
||||||
|
|
||||||
typedef void (*DelFunc)(void);
|
typedef void (*DelFunc)(void);
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Policy relying on the compiler/runtime system for Singleton Lifecycle
|
* Policy relying on the compiler/runtime system for Singleton Lifecycle
|
||||||
*/
|
*/
|
||||||
|
|
@ -98,7 +97,8 @@ namespace lumiera {
|
||||||
* several Singletons, we need to memorise all registered
|
* several Singletons, we need to memorise all registered
|
||||||
* deleter functions for calling them at shutdown.
|
* deleter functions for calling them at shutdown.
|
||||||
*/
|
*/
|
||||||
static void scheduleDelete (DelFunc kill_the_singleton)
|
static void
|
||||||
|
scheduleDelete (DelFunc kill_the_singleton)
|
||||||
{
|
{
|
||||||
class DeleteTrigger
|
class DeleteTrigger
|
||||||
{
|
{
|
||||||
|
|
@ -122,36 +122,15 @@ namespace lumiera {
|
||||||
finally.schedule (kill_the_singleton);
|
finally.schedule (kill_the_singleton);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void onDeadReference ()
|
static void
|
||||||
|
onDeadReference ()
|
||||||
{
|
{
|
||||||
throw error::Logic ("Trying to access the a Singleton instance that has "
|
throw error::Logic ("Trying to access the a Singleton instance that has "
|
||||||
"already been released or finished its lifecycle.");
|
"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
|
} // namespace singleton
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,8 @@ namespace lumiera
|
||||||
/* Forward declarations of all Classes we want to specialise the template */
|
/* Forward declarations of all Classes we want to specialise the template */
|
||||||
/* ********************************************************************** */
|
/* ********************************************************************** */
|
||||||
|
|
||||||
namespace test
|
namespace test {
|
||||||
{
|
|
||||||
class TestSingletonO;
|
class TestSingletonO;
|
||||||
using lumiera::Singleton;
|
using lumiera::Singleton;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,14 +21,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file singletonsubclass.hpp
|
/** @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
|
** 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
|
** Thus the code using the singleton need not know the implementation
|
||||||
** class, but nevertheless gets an non-virtual access function to the
|
** class, but nevertheless gets an non-virtual access function to the
|
||||||
** singleton instance (which can be inlined), and the compiler is
|
** singleton instance (which can be inlined), and the compiler is
|
||||||
** still able to spot type errors. Maybe someone knows a less
|
** 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 configrules.cpp usage example
|
||||||
** @see SingletonSubclass_test
|
** @see SingletonSubclass_test
|
||||||
|
|
@ -50,8 +50,8 @@ namespace lumiera {
|
||||||
using boost::scoped_ptr;
|
using boost::scoped_ptr;
|
||||||
|
|
||||||
|
|
||||||
namespace singleton
|
namespace singleton {
|
||||||
{
|
|
||||||
/**
|
/**
|
||||||
* Helper template to use the general policy classes of the lumiera::Singleton,
|
* Helper template to use the general policy classes of the lumiera::Singleton,
|
||||||
* but change the way they are parametrised on-the-fly.
|
* but change the way they are parametrised on-the-fly.
|
||||||
|
|
@ -63,7 +63,7 @@ namespace lumiera {
|
||||||
struct Link
|
struct Link
|
||||||
{
|
{
|
||||||
virtual ~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;
|
virtual void destroy (I* pSi) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -123,13 +123,11 @@ namespace lumiera {
|
||||||
< class SI // the class to use as Interface for the Singleton
|
< 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 Create = singleton::StaticCreate // how to create/destroy the instance
|
||||||
, template <class> class Life = singleton::AutoDestroy // how to manage Singleton Lifecycle
|
, template <class> class Life = singleton::AutoDestroy // how to manage Singleton Lifecycle
|
||||||
, template <class> class Threading = singleton::IgnoreThreadsafety //TODO use Multithreaded!!!
|
|
||||||
>
|
>
|
||||||
class SingletonSubclassFactory
|
class SingletonSubclassFactory
|
||||||
: public SingletonFactory< SI
|
: public SingletonFactory< SI
|
||||||
, singleton::Adapter<Create,SI>::template Adapted
|
, singleton::Adapter<Create,SI>::template Adapted
|
||||||
, Life
|
, Life
|
||||||
, Threading
|
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -74,11 +74,15 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "lib/mutex.h"
|
#include "lib/mutex.h"
|
||||||
#include "lib/condition.h"
|
#include "lib/condition.h"
|
||||||
|
#include "lib/reccondition.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include <boost/noncopyable.hpp>
|
||||||
|
#include <pthread.h>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
|
using boost::noncopyable;
|
||||||
|
|
||||||
|
|
||||||
namespace lib {
|
namespace lib {
|
||||||
|
|
@ -106,7 +110,7 @@ namespace lib {
|
||||||
: public lumiera_mutex
|
: public lumiera_mutex
|
||||||
{
|
{
|
||||||
protected:
|
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)); }
|
~Wrapped_LumieraRecMutex() { lumiera_mutex_destroy (this, &NOBUG_FLAG(sync)); }
|
||||||
|
|
||||||
//------------------Resource-Tracking------
|
//------------------Resource-Tracking------
|
||||||
|
|
@ -120,7 +124,7 @@ namespace lib {
|
||||||
: public lumiera_condition
|
: public lumiera_condition
|
||||||
{
|
{
|
||||||
protected:
|
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) ); }
|
~Wrapped_LumieraExcCond() { lumiera_condition_destroy (this, &NOBUG_FLAG(sync) ); }
|
||||||
|
|
||||||
//------------------Resource-Tracking------
|
//------------------Resource-Tracking------
|
||||||
|
|
@ -131,11 +135,11 @@ namespace lib {
|
||||||
|
|
||||||
|
|
||||||
struct Wrapped_LumieraRecCond
|
struct Wrapped_LumieraRecCond
|
||||||
: public lumiera_condition //////////////////////////////////////////TODO use correct implementation here!
|
: public lumiera_reccondition
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
Wrapped_LumieraRecCond() { lumiera_condition_init (this, "Obj.Monitor Condition", &NOBUG_FLAG(sync) ); } ////////TODO
|
Wrapped_LumieraRecCond() { lumiera_reccondition_init (this, "Obj.Monitor RecCondition", &NOBUG_FLAG(sync) ); } ////////TODO
|
||||||
~Wrapped_LumieraRecCond() { lumiera_condition_destroy (this, &NOBUG_FLAG(sync) ); }
|
~Wrapped_LumieraRecCond() { lumiera_reccondition_destroy (this, &NOBUG_FLAG(sync) ); }
|
||||||
|
|
||||||
//------------------Resource-Tracking------
|
//------------------Resource-Tracking------
|
||||||
void __may_block() { TODO ("Record we may block on mutex"); }
|
void __may_block() { TODO ("Record we may block on mutex"); }
|
||||||
|
|
@ -157,6 +161,11 @@ namespace lib {
|
||||||
using MTX::__enter;
|
using MTX::__enter;
|
||||||
using MTX::__leave;
|
using MTX::__leave;
|
||||||
|
|
||||||
|
~Mutex () { }
|
||||||
|
Mutex () { }
|
||||||
|
Mutex (const Mutex&); ///< noncopyable...
|
||||||
|
const Mutex& operator= (const Mutex&);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void
|
void
|
||||||
acquire()
|
acquire()
|
||||||
|
|
@ -282,6 +291,8 @@ namespace lib {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object Monitor for synchronisation and waiting.
|
* Object Monitor for synchronisation and waiting.
|
||||||
|
* Implemented by a (wrapped) set of sync primitives,
|
||||||
|
* which are default constructible and noncopyable.
|
||||||
*/
|
*/
|
||||||
template<class IMPL>
|
template<class IMPL>
|
||||||
class Monitor
|
class Monitor
|
||||||
|
|
@ -293,6 +304,11 @@ namespace lib {
|
||||||
Monitor() {}
|
Monitor() {}
|
||||||
~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 acquireLock() { IMPL::acquire(); }
|
||||||
void releaseLock() { IMPL::release(); }
|
void releaseLock() { IMPL::release(); }
|
||||||
|
|
||||||
|
|
@ -370,13 +386,13 @@ namespace lib {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class Lock
|
class Lock
|
||||||
|
: private noncopyable
|
||||||
{
|
{
|
||||||
Monitor& mon_;
|
Monitor& mon_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template<class X>
|
template<class X>
|
||||||
Lock(X* it) : mon_(getMonitor(it)){ mon_.acquireLock(); }
|
Lock(X* it) : mon_(getMonitor(it)){ mon_.acquireLock(); }
|
||||||
Lock(Monitor& m) : mon_(m) { mon_.acquireLock(); }
|
|
||||||
~Lock() { mon_.releaseLock(); }
|
~Lock() { mon_.releaseLock(); }
|
||||||
|
|
||||||
void notify() { mon_.signal(false);}
|
void notify() { mon_.signal(false);}
|
||||||
|
|
@ -385,11 +401,12 @@ namespace lib {
|
||||||
|
|
||||||
template<typename C>
|
template<typename C>
|
||||||
bool wait (C& cond, ulong time=0) { return mon_.wait(cond,time);}
|
bool wait (C& cond, ulong time=0) { return mon_.wait(cond,time);}
|
||||||
|
bool isTimedWait() { return mon_.isTimedWait(); }
|
||||||
|
|
||||||
|
|
||||||
/** convenience shortcut:
|
/** convenience shortcut:
|
||||||
* Locks and immediately enters wait state,
|
* Locks and immediately enters wait state,
|
||||||
* observing a condition defined as member function.
|
* observing a condition defined as member function. */
|
||||||
*/
|
|
||||||
template<class X>
|
template<class X>
|
||||||
Lock(X* it, bool (X::*method)(void))
|
Lock(X* it, bool (X::*method)(void))
|
||||||
: mon_(getMonitor(it))
|
: mon_(getMonitor(it))
|
||||||
|
|
@ -397,6 +414,11 @@ namespace lib {
|
||||||
mon_.acquireLock();
|
mon_.acquireLock();
|
||||||
mon_.wait(*it,method);
|
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>
|
#include <boost/scoped_ptr.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace lumiera
|
namespace lumiera {
|
||||||
{
|
namespace test {
|
||||||
namespace test
|
|
||||||
{
|
|
||||||
using boost::scoped_ptr;
|
using boost::scoped_ptr;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Special SingletonFactory allowing to inject some instance of the Singleton
|
* 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,
|
* This allows installing a Mock Subclass of the Singleton for running tests,
|
||||||
* while the Singleton can be used as usual in production code.
|
* while the Singleton can be used as usual in production code.
|
||||||
* @note we use the default policies or SingletonFactory
|
* @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//
|
//TODO: Lumiera header includes//
|
||||||
#include "backend/threads.h"
|
#include "lib/threads.h"
|
||||||
|
|
||||||
//TODO: internal/static forward declarations//
|
//TODO: internal/static forward declarations//
|
||||||
|
|
||||||
|
|
@ -98,10 +98,11 @@ lumiera_thread_run (enum lumiera_thread_class kind,
|
||||||
pthread_mutex_lock (&threads_mutex);
|
pthread_mutex_lock (&threads_mutex);
|
||||||
|
|
||||||
pthread_t dummy;
|
pthread_t dummy;
|
||||||
pthread_create (&dummy, &attrs, pthread_runner, &thread);
|
int error = pthread_create (&dummy, &attrs, pthread_runner, &thread);
|
||||||
|
|
||||||
pthread_mutex_unlock (&threads_mutex);
|
pthread_mutex_unlock (&threads_mutex);
|
||||||
|
|
||||||
|
if (error) return 0; /////TODO temporary addition by Ichthyo; probably we'll set lumiera_error?
|
||||||
return (LumieraThread) 1;
|
return (LumieraThread) 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,6 +60,13 @@ namespace util {
|
||||||
return !pContainer || pContainer->empty();
|
return !pContainer || pContainer->empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class CONT>
|
||||||
|
inline bool
|
||||||
|
isnil (CONT* pContainer)
|
||||||
|
{
|
||||||
|
return !pContainer || pContainer->empty();
|
||||||
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
isnil (const char* pCStr)
|
isnil (const char* pCStr)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,8 @@ namespace lumiera {
|
||||||
* For each possible call entry point via some subclass of the visitable hierarchy,
|
* 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
|
* we maintain a dispatcher table to keep track of all concrete tool implementations
|
||||||
* able to receive and process calls on objects of this subclass.
|
* 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>
|
template<class TAR, class TOOL>
|
||||||
class Dispatcher
|
class Dispatcher
|
||||||
|
|
@ -140,7 +142,7 @@ namespace lumiera {
|
||||||
void
|
void
|
||||||
accomodate (size_t index)
|
accomodate (size_t index)
|
||||||
{
|
{
|
||||||
ClassLock<Dispatcher> guard();
|
ClassLock<Dispatcher> guard(); // note: this lock is also used for the singleton!
|
||||||
if (index > table_.size())
|
if (index > table_.size())
|
||||||
table_.resize (index); // performance bottleneck?? TODO: measure the real impact!
|
table_.resize (index); // performance bottleneck?? TODO: measure the real impact!
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,8 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace asset
|
namespace asset {
|
||||||
{
|
|
||||||
|
|
||||||
class Proc;
|
class Proc;
|
||||||
class ProcFactory;
|
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>
|
class ProcFactory : public lumiera::Factory<asset::Proc>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -82,8 +82,8 @@ namespace asset
|
||||||
|
|
||||||
|
|
||||||
/** Factory method for Structural Asset instances.
|
/** Factory method for Structural Asset instances.
|
||||||
* First tries to relove the asset by issuing an capability query.
|
* First tries to resolve the asset by issuing an capability query.
|
||||||
* If unsuccessfull, use some internally specialized ctor call.
|
* If unsuccessful, use some internally specialised ctor call.
|
||||||
* @todo work out the struct asset naming scheme!
|
* @todo work out the struct asset naming scheme!
|
||||||
* @return an Struct smart ptr linked to the internally registered smart ptr
|
* @return an Struct smart ptr linked to the internally registered smart ptr
|
||||||
* created as a side effect of calling the concrete Struct subclass ctor.
|
* created as a side effect of calling the concrete Struct subclass ctor.
|
||||||
|
|
@ -109,7 +109,7 @@ namespace asset
|
||||||
|
|
||||||
|
|
||||||
/** Factory method for creating Pipes explicitly.
|
/** 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.
|
* default processing pattern (ProcPatt) for this streamID.
|
||||||
* The Pipe ctor will fill out the shortDesc and longDesc
|
* The Pipe ctor will fill out the shortDesc and longDesc
|
||||||
* automatically, based on pipeID and streamID (and they
|
* automatically, based on pipeID and streamID (and they
|
||||||
|
|
@ -144,8 +144,7 @@ namespace asset
|
||||||
#include "proc/asset/pipe.hpp"
|
#include "proc/asset/pipe.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace asset
|
namespace asset {
|
||||||
{
|
|
||||||
|
|
||||||
template P<Pipe> StructFactory::operator() (const Query<Pipe>& query);
|
template P<Pipe> StructFactory::operator() (const Query<Pipe>& query);
|
||||||
template P<Track> StructFactory::operator() (const Query<Track>& query);
|
template P<Track> StructFactory::operator() (const Query<Track>& query);
|
||||||
|
|
|
||||||
|
|
@ -49,8 +49,8 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace asset
|
namespace asset {
|
||||||
{
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::wstring;
|
using std::wstring;
|
||||||
using boost::scoped_ptr;
|
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>
|
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.
|
* queries are resolved and when to create new objects automatically.
|
||||||
* @todo better use a general struct traits class, esp.for creating the Ident
|
* @todo better use a general struct traits class, esp.for creating the Ident
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -183,16 +183,19 @@ namespace asset {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
namespace { // details implementing AssetManager::remove
|
||||||
recursive_call (AssetManager* instance, PAsset& pA)
|
|
||||||
{
|
void
|
||||||
instance->remove (pA->getID());
|
recursive_call (AssetManager* instance, PAsset& pA)
|
||||||
}
|
{
|
||||||
|
instance->remove (pA->getID());
|
||||||
function<void(PAsset&)>
|
}
|
||||||
detach_child_recursively () ///< @return a functor recursively invoking remove(child)
|
|
||||||
{
|
function<void(PAsset&)>
|
||||||
return bind( &recursive_call, &AssetManager::instance(), _1 );
|
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
|
* Global access point for the services implemented by the Proc-Layer.
|
||||||
* and for defining the public interface(s) for addressing the GUI
|
|
||||||
* from Backend or Proc-Layer.
|
|
||||||
*
|
*
|
||||||
* If running Lumiera with a GUI is required (the default case),
|
* @todo this is a dummy placeholder as of 1/2009. Currently, there
|
||||||
* it is loaded as dynamic module, thus defining the interface(s)
|
* is only implementation-level code within the Proc-Layer and
|
||||||
* for any further access. After successfully loading and starting
|
* the interfaces need to be worked out.
|
||||||
* 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.
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct Facade
|
struct Facade
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ namespace mobject {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** initialize the most basic internal defaults. */
|
/** initialise the most basic internal defaults. */
|
||||||
DefsManager::DefsManager () throw()
|
DefsManager::DefsManager () throw()
|
||||||
: defsRegistry(new DefsRegistry)
|
: defsRegistry(new DefsRegistry)
|
||||||
{
|
{
|
||||||
|
|
@ -142,11 +142,10 @@ namespace mobject {
|
||||||
#include "proc/asset/track.hpp"
|
#include "proc/asset/track.hpp"
|
||||||
#include "proc/mobject/session/track.hpp"
|
#include "proc/mobject/session/track.hpp"
|
||||||
|
|
||||||
namespace mobject
|
namespace mobject {
|
||||||
{
|
namespace session {
|
||||||
namespace session
|
|
||||||
{
|
|
||||||
|
|
||||||
using asset::Pipe;
|
using asset::Pipe;
|
||||||
using asset::PPipe;
|
using asset::PPipe;
|
||||||
using asset::ProcPatt;
|
using asset::ProcPatt;
|
||||||
|
|
@ -164,7 +163,8 @@ namespace mobject
|
||||||
|
|
||||||
template bool DefsManager::define (const PPipe&, const Query<Pipe>&);
|
template bool DefsManager::define (const PPipe&, const Query<Pipe>&);
|
||||||
template bool DefsManager::forget (const PPipe&);
|
template bool DefsManager::forget (const PPipe&);
|
||||||
|
|
||||||
|
|
||||||
} // namespace mobject::session
|
} // namespace mobject::session
|
||||||
|
|
||||||
} // namespace mobject
|
} // namespace mobject
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,8 @@ namespace mobject {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Organize a collection of preconfigured default objects.
|
* Organise a collection of preconfigured default objects.
|
||||||
* For various kinds of objects we can tweek the default parametrisation
|
* For various kinds of objects we can tweak the default parametrisation
|
||||||
* as part of the general session configuration. A ref to an instance of
|
* 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
|
* 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
|
* to fill in parts of the configuration of new objects, if the user
|
||||||
|
|
@ -88,10 +88,10 @@ namespace mobject {
|
||||||
template<class TAR>
|
template<class TAR>
|
||||||
P<TAR> create (const lumiera::Query<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,
|
* query. The latter may cause some properties of the object to be set,
|
||||||
* trigger creation of additional objects, and may fail altogether.
|
* 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
|
* @note only a weak ref to the object is stored
|
||||||
*/
|
*/
|
||||||
template<class TAR>
|
template<class TAR>
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
** A piece of implementation code factored out into a separate header (include).
|
** 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
|
** 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
|
** 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.
|
** to be filled with data and defaults for the specific Types.
|
||||||
**
|
**
|
||||||
** @see mobject::session::DefsManager
|
** @see mobject::session::DefsManager
|
||||||
|
|
@ -80,7 +80,7 @@ namespace mobject {
|
||||||
};
|
};
|
||||||
|
|
||||||
/** we maintain an independent defaults registry
|
/** we maintain an independent defaults registry
|
||||||
* for every participating kind of objects */
|
* for every participating kind of object. */
|
||||||
typedef std::vector< P<TableEntry> > Table;
|
typedef std::vector< P<TableEntry> > Table;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -180,8 +180,8 @@ namespace mobject {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal Helper for organizing preconfigured default objects.
|
* @internal Helper for organising preconfigured default objects.
|
||||||
* Maintaines a collection of objects known or encountered as "default"
|
* Maintains a collection of objects known or encountered as "default"
|
||||||
* for a given type. This collection is ordered by "degree of constriction",
|
* for a given type. This collection is ordered by "degree of constriction",
|
||||||
* which is implemented by counting the number of predicates in the query
|
* which is implemented by counting the number of predicates in the query
|
||||||
* used to define or identify each object.
|
* used to define or identify each object.
|
||||||
|
|
@ -206,17 +206,17 @@ namespace mobject {
|
||||||
II p,i,e;
|
II p,i,e;
|
||||||
P<TAR> next, ptr;
|
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)
|
: p(from), i(from), e(to)
|
||||||
{
|
{
|
||||||
if (i!=e) ++i; // p is next to be tested, i always one ahead
|
if (i!=e) ++i; // p is next to be tested, i always one ahead
|
||||||
operator++ ();
|
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)
|
: 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()
|
P<TAR> findNext () throw()
|
||||||
|
|
@ -233,7 +233,7 @@ namespace mobject {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
P<TAR> operator* () { return ptr; }
|
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++ (int) { Iter tmp=*this; operator++(); return tmp; }
|
||||||
Iter& operator++ ()
|
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
|
* 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 \em same query, this one will be first in the sequence. Besides,
|
||||||
* the sequence will yield all still existing registered "default" objects
|
* the sequence will yield all still existing registered "default" objects
|
||||||
* of this kind, ordered ascending by "degree of constriction", i.e. starting
|
* 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
|
* @return a forward input iterator yielding this sequence
|
||||||
* @note none of the queries will be evaluated (we're just counting predicates)
|
* @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();
|
typename Registry::iterator end = registry.end();
|
||||||
|
|
||||||
if (pos==end)
|
if (pos==end)
|
||||||
return Iter<TAR> (registry.begin(), end); // just ennumerate contents
|
return Iter<TAR> (registry.begin(), end); // just enumerate contents
|
||||||
else
|
else
|
||||||
return Iter<TAR> (pos, registry.begin(), end); // start with direct match
|
return Iter<TAR> (pos, registry.begin(), end); // start with direct match
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -180,38 +180,38 @@ END
|
||||||
|
|
||||||
|
|
||||||
TEST "Factory_test" Factory_test 5 <<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: now the smart-ptr has refcount=3
|
||||||
out: .....TargetObj(5): data="*****", array[5]={0,1,2,3,4,}
|
out: .....TargetObj(5): data="*****", array[5]={0,1,2,3,4,}
|
||||||
out: dtor ~TargetObj(5) successfull
|
out: dtor ~TargetObj(5) successful
|
||||||
END
|
END
|
||||||
|
|
||||||
|
|
||||||
TEST "Factory_special_test" Factory_special_test 5 <<END
|
TEST "Factory_special_test" Factory_special_test 5 <<END
|
||||||
out: checkPlacement--------
|
out: checkPlacement--------
|
||||||
out: ctor TargetObj(5) successfull
|
out: ctor TargetObj(5) successful
|
||||||
out: created 3 shared_ptrs to Object placed in static buffer.
|
out: created 3 shared_ptrs to Object placed in static buffer.
|
||||||
out: .....TargetObj(5): data="*****", array[5]={0,1,2,3,4,}
|
out: .....TargetObj(5): data="*****", array[5]={0,1,2,3,4,}
|
||||||
out: dtor ~TargetObj(5) successfull
|
out: dtor ~TargetObj(5) successful
|
||||||
out: ctor TargetObj(6) successfull
|
out: ctor TargetObj(6) successful
|
||||||
out: created 4 shared_ptrs to Object placed in static buffer.
|
out: created 4 shared_ptrs to Object placed in static buffer.
|
||||||
out: dtor ~TargetObj(6) successfull
|
out: dtor ~TargetObj(6) successful
|
||||||
out: checkPrivate--------
|
out: checkPrivate--------
|
||||||
out: ctor TargetObj(5) successfull
|
out: ctor TargetObj(5) successful
|
||||||
out: created 3 shared_ptrs to paranoid Object.
|
out: created 3 shared_ptrs to paranoid Object.
|
||||||
out: .....TargetObj(5): data="*****", array[5]={0,1,2,3,4,}
|
out: .....TargetObj(5): data="*****", array[5]={0,1,2,3,4,}
|
||||||
out: dtor ~TargetObj(5) successfull
|
out: dtor ~TargetObj(5) successful
|
||||||
out: checkMalloc--------
|
out: checkMalloc--------
|
||||||
out: ctor TargetObj(7) successfull
|
out: ctor TargetObj(7) successful
|
||||||
out: created auto_ptr to malloc-ed Object.
|
out: created auto_ptr to malloc-ed Object.
|
||||||
out: .....TargetObj(7): data="*******", array[7]={0,1,2,3,4,5,6,}
|
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: checkPImpl--------
|
||||||
out: ctor TargetObj(12) successfull
|
out: ctor TargetObj(12) successful
|
||||||
out: created auto_ptr to Interface Object.
|
out: created auto_ptr to Interface Object.
|
||||||
out: .....ImplObj::funky() called
|
out: .....ImplObj::funky() called
|
||||||
out: .....TargetObj(12): data="************", array[12]={0,1,2,3,4,5,6,7,8,9,10,11,}
|
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
|
END
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -251,10 +251,10 @@ END
|
||||||
|
|
||||||
TEST "SingletonSubclass_test" SingletonSubclass_test 13 <<END
|
TEST "SingletonSubclass_test" SingletonSubclass_test 13 <<END
|
||||||
out: using the Singleton should create TargetObj(13)...
|
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: 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: .....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
|
END
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -297,15 +297,15 @@ END
|
||||||
|
|
||||||
TEST "Singleton_test" Singleton_test 23 <<END
|
TEST "Singleton_test" Singleton_test 23 <<END
|
||||||
out: testing TargetObj(23) as Singleton(statically allocated)
|
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: 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: .....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: 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: 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: .....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(23) successful
|
||||||
out: dtor ~TargetObj(24) successfull
|
out: dtor ~TargetObj(24) successful
|
||||||
END
|
END
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -332,6 +332,21 @@ return: 0
|
||||||
END
|
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
|
TEST "TestOption_test" TestOption_test <<END
|
||||||
out: Testing invocation with cmdline: ...
|
out: Testing invocation with cmdline: ...
|
||||||
out: --> Testgroup=ALL
|
out: --> Testgroup=ALL
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ END
|
||||||
|
|
||||||
TEST "QueryUtils_test" QueryUtils_test normalizeID <<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: ..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
|
END
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,9 +59,11 @@ test_lib_SOURCES = \
|
||||||
$(testlib_srcdir)/singletontestmocktest.cpp \
|
$(testlib_srcdir)/singletontestmocktest.cpp \
|
||||||
$(testlib_srcdir)/streamtypebasicstest.cpp \
|
$(testlib_srcdir)/streamtypebasicstest.cpp \
|
||||||
$(testlib_srcdir)/streamtypelifecycletest.cpp \
|
$(testlib_srcdir)/streamtypelifecycletest.cpp \
|
||||||
|
$(testlib_srcdir)/subsystem-runner-test.cpp \
|
||||||
$(testlib_srcdir)/sync-classlock-test.cpp \
|
$(testlib_srcdir)/sync-classlock-test.cpp \
|
||||||
$(testlib_srcdir)/sync-locking-test.cpp \
|
$(testlib_srcdir)/sync-locking-test.cpp \
|
||||||
$(testlib_srcdir)/sync-waiting-test.cpp \
|
$(testlib_srcdir)/sync-waiting-test.cpp \
|
||||||
|
$(testlib_srcdir)/thread-wrapper-test.cpp \
|
||||||
$(testlib_srcdir)/test/cmdlinewrappertest.cpp \
|
$(testlib_srcdir)/test/cmdlinewrappertest.cpp \
|
||||||
$(testlib_srcdir)/test/testoptiontest.cpp \
|
$(testlib_srcdir)/test/testoptiontest.cpp \
|
||||||
$(testlib_srcdir)/vectortransfertest.cpp \
|
$(testlib_srcdir)/vectortransfertest.cpp \
|
||||||
|
|
|
||||||
|
|
@ -31,10 +31,9 @@
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
|
|
||||||
namespace asset
|
namespace asset {
|
||||||
{
|
namespace test{
|
||||||
namespace test
|
|
||||||
{
|
|
||||||
using lumiera::P;
|
using lumiera::P;
|
||||||
using std::tr1::shared_ptr;
|
using std::tr1::shared_ptr;
|
||||||
using std::tr1::weak_ptr;
|
using std::tr1::weak_ptr;
|
||||||
|
|
@ -71,7 +70,7 @@ namespace asset
|
||||||
class CustomSharedPtr_test : public Test
|
class CustomSharedPtr_test : public Test
|
||||||
{
|
{
|
||||||
virtual void
|
virtual void
|
||||||
run (Arg arg)
|
run (Arg)
|
||||||
{
|
{
|
||||||
check_refcounting ();
|
check_refcounting ();
|
||||||
check_shared_ownership ();
|
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
|
Copyright (C) Lumiera.org
|
||||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||||
|
|
@ -41,13 +41,11 @@ using std::cout;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace lumiera
|
namespace lumiera {
|
||||||
{
|
namespace test {
|
||||||
namespace test
|
|
||||||
{
|
|
||||||
|
|
||||||
/** local specific error-constant for use in the
|
/** 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(LIFE_AND_UNIVERSE, "and everything?");
|
||||||
LUMIERA_ERROR_DEFINE(DERIVED, "convoluted exception");
|
LUMIERA_ERROR_DEFINE(DERIVED, "convoluted exception");
|
||||||
|
|
@ -91,17 +89,17 @@ namespace lumiera
|
||||||
|
|
||||||
|
|
||||||
/** @test simply throw some exception and pass context info */
|
/** @test simply throw some exception and pass context info */
|
||||||
void throwSpecial (string _) { throw SpecificError(); }
|
void throwSpecial (string ) { throw SpecificError(); }
|
||||||
void throwDerived (string _) { throw DerivedError(); }
|
void throwDerived (string ) { throw DerivedError(); }
|
||||||
void throwFatal (string _) { throw error::Fatal(_); }
|
void throwFatal (string _) { throw error::Fatal(_); }
|
||||||
void throwInvalid (string _) { throw error::Invalid(_); }
|
void throwInvalid (string _) { throw error::Invalid(_); }
|
||||||
void throwExternal(string _) { throw error::External(_); }
|
void throwExternal(string _) { throw error::External(_); }
|
||||||
void throwRuntime (string _) { throw std::runtime_error(_); }
|
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.
|
/** @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,
|
* over several layers. The nested operation will throw an error::External,
|
||||||
* which we are able to catch because it is derived from std::exception.
|
* 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
|
* 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); }
|
try { nestedThrower (msg); }
|
||||||
catch (Error& e)
|
catch (Error& e)
|
||||||
{
|
{
|
||||||
cout << "2nd intermediate handler caught: " << e.what()
|
cout << "2nd intermediate handler caught: " << e.what()
|
||||||
<< "....will rethrow as error::Config\n";
|
<< "....will rethrow as error::Config\n";
|
||||||
throw error::Config (e);
|
throw error::Config (e);
|
||||||
}
|
}
|
||||||
|
|
@ -172,15 +170,15 @@ namespace lumiera
|
||||||
ASSERT (err2.rootCause() == err1.what());
|
ASSERT (err2.rootCause() == err1.what());
|
||||||
ASSERT (err3.rootCause() == err1.what());
|
ASSERT (err3.rootCause() == err1.what());
|
||||||
ASSERT (err4.rootCause() == err1.what());
|
ASSERT (err4.rootCause() == err1.what());
|
||||||
|
|
||||||
ASSERT (err5.rootCause() == rerr.what());
|
ASSERT (err5.rootCause() == rerr.what());
|
||||||
ASSERT (err6.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,
|
* 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
|
* @note inside error.hpp, an initialisation hook has been installed into
|
||||||
* AppState, causing our own unknown() handler to be installed and
|
* AppState, causing our own unknown() handler to be installed and
|
||||||
* invoked, which gives additional diagnostics.*/
|
* invoked, which gives additional diagnostics.*/
|
||||||
|
|
@ -214,22 +212,22 @@ namespace lumiera
|
||||||
(this->*funky) (context);
|
(this->*funky) (context);
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (SpecificError& e) { cout << "caught: " << e.what() << "..the answer is: " << e.revealIt() << "\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::Logic& e) { cout << "caught error::Logic: " << e.what() << "\n"; }
|
||||||
catch (error::Invalid&e) { cout << "caught error::Invalid: " << 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 (Error& e) { cout << "caught lumiera::Error: " << e.what() << "\n"; }
|
||||||
catch (runtime_error& e) { cout << "caught std::runtime_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 (exception& e) { cout << "caught std::exception. (unspecific)" << "\n"; }
|
||||||
catch (...) { cout << "caught an unknown exception\n"; }
|
catch (...) { cout << "caught an unknown exception\n"; }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** register this test class... */
|
/** register this test class... */
|
||||||
LAUNCHER (ExceptionError_test, "function common");
|
LAUNCHER (ExceptionError_test, "function common");
|
||||||
|
|
||||||
|
|
||||||
} // namespace test
|
} // namespace test
|
||||||
|
|
||||||
} // namespace util
|
} // namespace util
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ namespace lumiera
|
||||||
class LifeCycle_test : public Test
|
class LifeCycle_test : public Test
|
||||||
{
|
{
|
||||||
virtual void
|
virtual void
|
||||||
run (Arg arg)
|
run (Arg)
|
||||||
{
|
{
|
||||||
ASSERT (basicInit, "the basic-init callback hasn't been invoked automatically");
|
ASSERT (basicInit, "the basic-init callback hasn't been invoked automatically");
|
||||||
ASSERT (1 == basicInit, "the basic-init callback has been invoked more than once");
|
ASSERT (1 == basicInit, "the basic-init callback has been invoked more than once");
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,8 @@ namespace lumiera
|
||||||
*/
|
*/
|
||||||
class TypeList_test : public Test
|
class TypeList_test : public Test
|
||||||
{
|
{
|
||||||
virtual void run(Arg arg)
|
void
|
||||||
|
run (Arg)
|
||||||
{
|
{
|
||||||
AssembledClass wow_me_has_numbers;
|
AssembledClass wow_me_has_numbers;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,12 +44,10 @@ using std::cout;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace lumiera
|
namespace lumiera {
|
||||||
{
|
namespace query {
|
||||||
namespace query
|
namespace test{
|
||||||
{
|
|
||||||
namespace test
|
|
||||||
{
|
|
||||||
|
|
||||||
struct Thing
|
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
|
* for dealing with ConfigQuery
|
||||||
*/
|
*/
|
||||||
class QueryUtils_test : public Test
|
class QueryUtils_test : public Test
|
||||||
|
|
@ -88,7 +86,7 @@ namespace lumiera
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** @test sanitizing and normalizing various tokens */
|
/** @test sanitising and normalising various tokens */
|
||||||
void
|
void
|
||||||
check_normalizeID ()
|
check_normalizeID ()
|
||||||
{
|
{
|
||||||
|
|
@ -101,7 +99,7 @@ namespace lumiera
|
||||||
|
|
||||||
for_each (tokens, bind ( &normalizeID, _1 ));
|
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", "pred(tok), pred(tux)." ));
|
||||||
ASSERT ("tok" == extractID ("pred", "other(xyz) pred(tok) pred(tux)" ));
|
ASSERT ("tok" == extractID ("pred", "other(xyz) pred(tok) pred(tux)" ));
|
||||||
ASSERT ("tok" == extractID ("pred", "some( pred(tok)" ));
|
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)" )));
|
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
|
void
|
||||||
check_removeTerm ()
|
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(tok)", " " );
|
ASSERT_removeTerm ("pred", " pred( tok )", "pred(tok)", " " );
|
||||||
ASSERT_removeTerm ("pred", "pred(tok), pred(tux).", "pred(tok)", "pred(tux)." );
|
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", "other(xyz) pred(tok) pred(tux)", "pred(tok)", "other(xyz) pred(tux)" );
|
||||||
ASSERT_removeTerm ("pred", "some( pred(tok)", "pred(tok)", "some( " );
|
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)" );
|
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...)
|
* (currently 4/08 regexp based...)
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
|
|
@ -167,7 +165,7 @@ namespace lumiera
|
||||||
|
|
||||||
|
|
||||||
} // namespace test
|
} // namespace test
|
||||||
|
|
||||||
} // namespace query
|
} // namespace query
|
||||||
|
|
||||||
} // namespace lumiera
|
} // namespace lumiera
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ namespace util
|
||||||
class RemoveFromSet_test : public Test
|
class RemoveFromSet_test : public Test
|
||||||
{
|
{
|
||||||
virtual void
|
virtual void
|
||||||
run (Arg arg)
|
run (Arg)
|
||||||
{
|
{
|
||||||
test_remove (" nothing ");
|
test_remove (" nothing ");
|
||||||
test_remove ("0");
|
test_remove ("0");
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ namespace lib {
|
||||||
{
|
{
|
||||||
|
|
||||||
virtual void
|
virtual void
|
||||||
run (Arg arg)
|
run (Arg)
|
||||||
{
|
{
|
||||||
|
|
||||||
cout << "checking ScopedHolder<Dummy>...\n";
|
cout << "checking ScopedHolder<Dummy>...\n";
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ namespace lib {
|
||||||
{
|
{
|
||||||
|
|
||||||
virtual void
|
virtual void
|
||||||
run (Arg arg)
|
run (Arg)
|
||||||
{
|
{
|
||||||
|
|
||||||
cout << "checking ScopedHolder<Dummy>...\n";
|
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 test
|
||||||
|
|
||||||
} // namespace lumiera
|
} // namespace lib
|
||||||
|
|
|
||||||
|
|
@ -206,4 +206,4 @@ namespace lib {
|
||||||
|
|
||||||
} // namespace test
|
} // 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 test
|
||||||
|
|
||||||
} // namespace lumiera
|
} // namespace lib
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,8 @@ namespace util
|
||||||
/** @test for util::Cmdline, wrapping various example cmdlines */
|
/** @test for util::Cmdline, wrapping various example cmdlines */
|
||||||
class CmdlineWrapper_test : public Test
|
class CmdlineWrapper_test : public Test
|
||||||
{
|
{
|
||||||
virtual void run (Arg arg)
|
void
|
||||||
|
run (Arg)
|
||||||
{
|
{
|
||||||
testLine("");
|
testLine("");
|
||||||
testLine("\n\t ");
|
testLine("\n\t ");
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,8 @@ namespace test
|
||||||
*/
|
*/
|
||||||
class TestOption_test : public Test
|
class TestOption_test : public Test
|
||||||
{
|
{
|
||||||
virtual void run(Arg arg)
|
void
|
||||||
|
run (Arg)
|
||||||
{
|
{
|
||||||
noOptions();
|
noOptions();
|
||||||
help();
|
help();
|
||||||
|
|
@ -53,6 +54,7 @@ namespace test
|
||||||
additionalCmd2();
|
additionalCmd2();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** @test performs the actual test for the option parser test::TestOption */
|
/** @test performs the actual test for the option parser test::TestOption */
|
||||||
void doIt (const string cmdline)
|
void doIt (const string cmdline)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ namespace lumiera
|
||||||
{
|
{
|
||||||
for (uint i=0; i<cnt_; ++i)
|
for (uint i=0; i<cnt_; ++i)
|
||||||
heapArray_[i] = lexical_cast<string>(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 heapData_;
|
||||||
delete[] heapArray_;
|
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)
|
TransDummy (const TransDummy& o)
|
||||||
|
: Dummy()
|
||||||
{
|
{
|
||||||
TRACE (test, "COPY-ctor TransDummy( ref=%x ) --> this=%x", &o,this);
|
TRACE (test, "COPY-ctor TransDummy( ref=%x ) --> this=%x", &o,this);
|
||||||
ASSERT (!o, "protocol violation: real copy operations inhibited");
|
ASSERT (!o, "protocol violation: real copy operations inhibited");
|
||||||
|
|
@ -113,18 +114,17 @@ namespace lib {
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************************
|
/**********************************************************************************
|
||||||
* @test ScopedHolder and ScopedPtrHolder are initially empty and copyable.
|
* @test growing (re-allocating) a vector with noncopyable objects, with the
|
||||||
* After taking ownership, they prohibit copy operations, manage the
|
* help of a special Allocator and a custom \c transfer_control operation
|
||||||
* lifecycle of the contained object and provide smart-ptr like access.
|
* provided by the contained objects. The idea is to allow some special
|
||||||
* A series of identical tests is conducted both with the ScopedPtrHolder
|
* copy-operations for the purpose of re-allocations within the vector,
|
||||||
* (the contained objects are heap allocated but managed by the holder)
|
* without requiring the object to be really copyable.
|
||||||
* and with the ScopedHolder (objects placed inline)
|
|
||||||
*/
|
*/
|
||||||
class VectorTransfer_test : public Test
|
class VectorTransfer_test : public Test
|
||||||
{
|
{
|
||||||
|
|
||||||
virtual void
|
virtual void
|
||||||
run (Arg arg)
|
run (Arg)
|
||||||
{
|
{
|
||||||
cout << "\n..setup table space for 2 elements\n";
|
cout << "\n..setup table space for 2 elements\n";
|
||||||
TransDummyVector table;
|
TransDummyVector table;
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ namespace lumiera
|
||||||
|
|
||||||
template<class TOOLImpl>
|
template<class TOOLImpl>
|
||||||
static Tag&
|
static Tag&
|
||||||
get (TOOLImpl* const concreteTool=0)
|
get (TOOLImpl* const =0) // param used to pass type info
|
||||||
{
|
{
|
||||||
// we have a race condition here...
|
// we have a race condition here...
|
||||||
Tag& t = TagTypeRegistry<TOOL,TOOLImpl>::tag;
|
Tag& t = TagTypeRegistry<TOOL,TOOLImpl>::tag;
|
||||||
|
|
@ -410,7 +410,7 @@ namespace lumiera
|
||||||
*/
|
*/
|
||||||
class VisitingTool_concept : public Test
|
class VisitingTool_concept : public Test
|
||||||
{
|
{
|
||||||
virtual void run(Arg arg)
|
virtual void run(Arg)
|
||||||
{
|
{
|
||||||
known_visitor_known_class();
|
known_visitor_known_class();
|
||||||
visitor_not_visiting_some_class();
|
visitor_not_visiting_some_class();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue