Commit b84c1c68 authored by Sebastian Eichelbaum's avatar Sebastian Eichelbaum
Browse files

[CHANGE #296] ensured post-poned load of toolbox extensions.

parent 5f4d1e6f
......@@ -265,12 +265,14 @@ struct WSharedLib::data
#endif
WSharedLib::WSharedLib( boost::filesystem::path lib ):
m_data( new data( lib.string() ) )
m_data( new data( lib.string() ) ),
m_libPath( lib )
{
}
WSharedLib::WSharedLib( const WSharedLib& rhs ):
m_data( new data( rhs.m_data->m_path ) )
m_data( new data( rhs.m_data->m_path ) ),
m_libPath( rhs.m_libPath )
{
}
......@@ -321,3 +323,10 @@ std::string WSharedLib::getSystemLibPath()
return "../lib";
}
std::string WSharedLib::getLibraryName()
{
// we want to strip the search directory from the path
std::string relPath( m_libPath.filename().string() );
return relPath;
}
......@@ -140,6 +140,13 @@ public:
*/
static std::string getSystemLibPath();
/**
* Returns the filename of the library without path.
*
* \return the filename.
*/
std::string getLibraryName();
protected:
private:
//! neutral function pointer type
......@@ -168,6 +175,9 @@ private:
//! internal data
data* m_data;
//! path to lib
boost::filesystem::path m_libPath;
};
template < typename FuncType >
......
......@@ -239,6 +239,11 @@ void WGraphicsEngine::finalizeStartup()
m_startThreadingCondition.notify();
}
void WGraphicsEngine::waitForFinalize()
{
m_startThreadingCondition.wait();
}
void WGraphicsEngine::requestShaderReload()
{
m_reloadShadersSignal();
......
......@@ -47,8 +47,6 @@
#include "WGEViewer.h"
#include "WGESignals.h"
/**
* Base class for initializing the graphics engine. This Class also serves as adaptor to access the graphics
* engine.
......@@ -150,6 +148,11 @@ public:
*/
void finalizeStartup();
/**
* Wait until someone called \ref finalizeStartup().
*/
void waitForFinalize();
/**
* Enables multithreaded view. This MUST be called before run(). On Mac, this has no function.
*
......
......@@ -39,6 +39,7 @@
#include "../common/WRealtimeTimer.h"
#include "../dataHandler/WDataHandler.h"
#include "../gui/WGUI.h"
#include "exceptions/WKernelException.h"
#include "WKernel.h"
#include "WModuleContainer.h"
#include "WModuleFactory.h"
......@@ -153,12 +154,31 @@ void WKernel::threadMain()
{
m_gui->isInitialized().wait();
}
else
{
wlog::warn( "Kernel" ) << "Expected GUI instance but none was initialized.";
}
// start GE
if( m_graphicsEngine )
{
m_graphicsEngine->run();
// wait for it to be ready
m_graphicsEngine->waitForFinalize();
}
else
{
wlog::warn( "Kernel" ) << "Expected GE instance but none was initialized.";
}
// do extension loading
wlog::info( "Kernel" ) << "Initializing extensions.";
WModuleFactory::getModuleLoader()->initializeExtensions();
// done. Notify anyone waiting
wlog::info( "Kernel" ) << "Initialization completed.";
m_startupCompleted.notify();
// actually there is nothing more to do here
waitForStop();
......@@ -206,3 +226,16 @@ WTimer::ConstSPtr WKernel::getTimer() const
return m_timer;
}
boost::signals2::connection WKernel::subscribeSignal( WKernel::KERNEL_SIGNAL signal, WKernel::t_KernelGenericSignalHandlerType notifier )
{
switch( signal )
{
case KERNEL_STARTUPCOMPLETE:
return m_startupCompleted.subscribeSignal( notifier );
default:
std::ostringstream s;
s << "Could not subscribe to unknown signal.";
throw WKernelException( s.str() );
break;
}
}
......@@ -36,8 +36,6 @@
#include "WBatchLoader.h"
// forward declarations
class WGUI;
class WModule;
......@@ -63,6 +61,26 @@ class WThreadedRunner;
class WKernel: public WThreadedRunner
{
public:
/**
* Signal for generic events.
*
*/
typedef boost::function< void ( void ) > t_KernelGenericSignalHandlerType;
/**
* Generic signal type used in the most signals.
*/
typedef boost::signals2::signal< void ( void ) > t_KernelGenericSignalType;
/**
* Enum of all possible signals WKernel instances can emit.
*/
typedef enum
{
KERNEL_STARTUPCOMPLETE // when kernel, GE and GUI are correctly initialized
}
KERNEL_SIGNAL;
/**
* Returns pointer to the running kernel or a new if no kernel was there.
* If a running kernel exists the function return it and does not check if
......@@ -79,6 +97,16 @@ public:
*/
virtual ~WKernel();
/**
* Subscribe to several signals.
*
* \param signal the signal to subscribe
* \param notifier the notifier to call
*
* \return connection variable. Keep this in any case. If not, the connection may be lost.
*/
boost::signals2::connection subscribeSignal( KERNEL_SIGNAL signal, t_KernelGenericSignalHandlerType notifier );
/**
* Stops execution of the modules in the root container. Note that this does not wait for the kernel thread since this could
* cause a dead lock. This is actually an alias for getRootContainer()->stop().
......@@ -255,6 +283,11 @@ private:
* The ow system timer.
*/
WTimer::SPtr m_timer;
/**
* Notified when the startup, including GE and GUI has been completed.
*/
WConditionOneShot m_startupCompleted;
};
#endif // WKERNEL_H
......
......@@ -42,7 +42,7 @@ boost::shared_ptr< WModuleFactory > WModuleFactory::m_instance = boost::shared_p
WModuleFactory::WModuleFactory():
m_prototypes(),
m_moduleLoader()
m_moduleLoader( new WModuleLoader() )
{
// initialize members
}
......@@ -52,6 +52,11 @@ WModuleFactory::~WModuleFactory()
// cleanup
}
boost::shared_ptr< WModuleLoader > WModuleFactory::getModuleLoader()
{
return WModuleFactory::getModuleFactory()->m_moduleLoader;
}
void WModuleFactory::load()
{
// load modules
......@@ -61,7 +66,7 @@ void WModuleFactory::load()
PrototypeSharedContainerType::WriteTicket l = m_prototypes.getWriteTicket();
// Load the dynamic modules here:
m_moduleLoader.load( l );
m_moduleLoader->load( l );
// initialize every module in the set
std::set< std::string > names; // helper to find duplicates
......
......@@ -37,8 +37,6 @@
#include "WModule.h"
#include "WModuleLoader.h"
/**
* Class able to create a new copy of an arbitrary module. It uses the Factory and Prototype design pattern.
*/
......@@ -92,6 +90,13 @@ public:
*/
static boost::shared_ptr< WModuleFactory > getModuleFactory();
/**
* Returns instance of the module loader.
*
* \return the running module loader.
*/
static boost::shared_ptr< WModuleLoader > getModuleLoader();
/**
* Searches a prototype by name. It returns the prototype, or a NULL pointer if it is not found. The difference to
* getPrototypeByName() is, that an unavailable prototype does not throw an exception. This is nice for checking whether a
......@@ -212,7 +217,7 @@ private:
/**
* Loader class managing dynamically loaded modules in OpenWalnut.
*/
WModuleLoader m_moduleLoader;
WModuleLoader::SPtr m_moduleLoader;
/**
* Singleton instance of WModuleFactory.
......
......@@ -130,13 +130,11 @@ void WModuleLoader::load( WSharedAssociativeContainer< std::set< boost::shared_p
// get instantiation function
if( l->existsFunction( W_LOADABLE_REGISTERARBITRARY_SYMBOL ) )
{
W_LOADABLE_REGISTERARBITRARY_SIGNATURE arbitraryRegister;
l->fetchFunction< W_LOADABLE_REGISTERARBITRARY_SIGNATURE >( W_LOADABLE_REGISTERARBITRARY_SYMBOL, arbitraryRegister );
isLoadableArbitrary = true;
// store this temporarily. This is called later, after OW was completely initialized
// put together the right path and call function
arbitraryRegister( WPathHelper::getModuleResourcePath( i->path().parent_path(), libBaseName ) );
m_arbitraryRegisterLibs.push_back( PostponedLoad( l, WPathHelper::getModuleResourcePath( i->path().parent_path(), libBaseName ) ) );
}
// lib gets closed if l looses focus
......@@ -184,6 +182,18 @@ void WModuleLoader::load( WSharedAssociativeContainer< std::set< boost::shared_p
}
}
void WModuleLoader::initializeExtensions()
{
typedef std::vector< PostponedLoad > Vec;
for( Vec::const_iterator iter = m_arbitraryRegisterLibs.begin(); iter != m_arbitraryRegisterLibs.end(); ++iter )
{
wlog::debug( "WModuleLoader" ) << "Initializing extensions of \"" << ( *iter ).m_lib->getLibraryName() << "\"";
W_LOADABLE_REGISTERARBITRARY_SIGNATURE arbitraryRegister;
( *iter ).m_lib->fetchFunction< W_LOADABLE_REGISTERARBITRARY_SIGNATURE >( W_LOADABLE_REGISTERARBITRARY_SYMBOL, arbitraryRegister );
arbitraryRegister( ( *iter ).m_path );
}
}
std::string WModuleLoader::getModulePrefix()
{
// all module file names need to have this prefix:
......
......@@ -43,6 +43,16 @@
class WModuleLoader
{
public:
/**
* Shared pointer abbreviation.
*/
typedef boost::shared_ptr< WModuleLoader > SPtr;
/**
* Const pointer abbreviation.
*/
typedef boost::shared_ptr< const WModuleLoader > ConstSPtr;
/**
* Constructor. It does not load any files. Use load to do this.
*
......@@ -68,6 +78,12 @@ public:
*/
static std::string getModulePrefix();
/**
* The loader also stores information on which library provides the arbitrary registration mechanism. This cannot be called during load, as
* OW is not completely initialized at this point. So we do this here. Call this after startup, before project loading.
*/
void initializeExtensions();
private:
/**
* All the loaded shared libraries. Get freed on destruction. So do NOT free this instance while the libs are used.
......@@ -84,6 +100,34 @@ private:
*/
void load( WSharedAssociativeContainer< std::set< boost::shared_ptr< WModule > > >::WriteTicket ticket, boost::filesystem::path dir,
unsigned int level = 0 );
/**
* Helper to store information on a lib which gets initialized later. This basically is used for the arbitrary registration feature.
*/
struct PostponedLoad
{
PostponedLoad( boost::shared_ptr< WSharedLib > lib, boost::filesystem::path path ):
m_lib( lib ),
m_path( path )
{
}
/**
* The library. Need to keep this to avoid freeing the lib beforehand.
*/
boost::shared_ptr< WSharedLib > m_lib;
/**
* The path of the resources.
*/
boost::filesystem::path m_path;
};
/**
* The libs which need to be initialized when OW is loaded completely.
*/
std::vector< PostponedLoad > m_arbitraryRegisterLibs;
};
#endif // WMODULELOADER_H
......@@ -213,11 +213,12 @@ int WQt4Gui::run()
// startup graphics engine
m_ge = WGraphicsEngine::getGraphicsEngine();
m_ge->subscribeSignal( GE_STARTUPCOMPLETE, boost::bind( &WQt4Gui::deferredLoad, this ) );
// and startup kernel
m_kernel = boost::shared_ptr< WKernel >( WKernel::instance( m_ge, shared_from_this() ) );
m_kernel->run();
m_kernel->subscribeSignal( WKernel::KERNEL_STARTUPCOMPLETE, boost::bind( &WQt4Gui::deferredLoad, this ) );
t_ModuleErrorSignalHandlerType func = boost::bind( &WQt4Gui::moduleError, this, _1, _2 );
m_kernel->getRootContainer()->addDefaultNotifier( WM_ERROR, func );
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment