Commit 08c2e409 authored by Sebastian Eichelbaum's avatar Sebastian Eichelbaum

[ADD] - added portable library loading and cleaned up code

parent 2aafc85f
......@@ -8,7 +8,7 @@ ADD_SUBDIRECTORY( constraints )
ADD_SUBDIRECTORY( math )
ADD_LIBRARY( common ${COMMON_SRC} ${COMMON_DATASTRUCTURES_SRC} ${COMMON_EXCEPTIONS_SRC} ${MATH_SRC} ${FIBERSIMILARITY_SRC} )
TARGET_LINK_LIBRARIES( common ${Boost_LIBRARIES} )
TARGET_LINK_LIBRARIES( common ${Boost_LIBRARIES} "dl" )
# Unit tests
......
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#include <algorithm>
#include <cassert>
#include <string>
#include "exceptions/WLibraryFetchFailed.h"
#include "exceptions/WLibraryLoadFailed.h"
#include "WSharedLib.h"
#ifdef _WIN32
#include <windows.h> // NOLINT
/**
* Simple class holding an opened library.
*/
struct WSharedLib::data
{
/**
* Path of lib.
*/
const std::string m_path;
/**
* Handle describing the loaded lib.
*/
HMODULE m_hDLL;
/**
* Constructor. Opens and loads the library.
*
* \see WSharedLib::WSharedLib for details.
*
* \param path the lib to open
*/
explicit data( const std::string& path ):
m_path( path ),
m_hDLL( LoadLibrary( path.c_str() ) )
{
if ( !m_hDLL )
{
throw WLibraryLoadFailed( "Could not load library \"" + m_path + "\" due to the error: " + errmsg() );
}
}
/**
* Destructor. Closes the previously opened library handle.
*/
~data()
{
FreeLibrary( m_hDLL );
}
/**
* Searches the lib for the specified function symbol and returns it.
*
* \param name the name of the function
*
* \return the pointer to the requested function
*
* \throw WLibraryFetchFailed thrown if the symbol could not be found.
*/
func_ptr_type findFunction( const std::string& name )
{
func_ptr_type func_ptr = reinterpret_cast< func_ptr_type >( GetProcAddress( m_hDLL, name.c_str() ) );
if ( !func_ptr )
{
throw WLibraryFetchFailed( "Could not fetch symbol \"" + name + "\"" + " due to the error: " + errmsg() );
}
return func_ptr;
}
/**
* Searches the lib for the specified function symbol and returns it.
*
* \param name the name of the function
*
* \return the pointer to the requested function
*
* \throw WLibraryFetchFailed thrown if the symbol could not be found.
*/
void* findVariable( const std::string& name )
{
return reinterpret_cast< void* >( find_func( name ) );
}
/**
* Constructs a nice looking error message for the last error occurred.
*
* \return the last error message
*/
static std::string errmsg()
{
std::string msg;
LPTSTR lpMsgBuf = 0;
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, GetLastError(), 0,
reinterpret_cast< LPTSTR >( &lpMsgBuf ), 0, 0 );
LPTSTR p = lpMsgBuf;
while ( *p )
{
msg.push_back( *p++ );
}
LocalFree( lpMsgBuf );
return msg;
}
};
#else
#include <dlfcn.h> // NOLINT
#include <pthread.h> // NOLINT
namespace
{
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
struct auto_lock
{
auto_lock()
{
pthread_mutex_lock( &mutex );
}
~auto_lock()
{
pthread_mutex_unlock( &mutex );
}
};
}
/**
* Simple class holding an opened library.
*/
struct WSharedLib::data
{
/**
* Path of lib.
*/
const std::string m_path;
/**
* Handle describing the loaded lib.
*/
void* m_dl;
/**
* Destructor. Closes the previously opened library handle.
*/
~data()
{
assert( dlclose( m_dl ) == 0 );
}
/**
* Constructor. Opens and loads the library.
*
* \see WSharedLib::WSharedLib for details.
*
* \param path the lib to open
*/
explicit data( const std::string& path )
: m_path( path ), m_dl( 0 )
{
auto_lock lock();
m_dl = dlopen( m_path.c_str(), RTLD_LAZY );
if ( !m_dl )
{
throw WLibraryLoadFailed( "Could not load library \"" + m_path + "\" due to the error: " + dlerror() );
}
}
/**
* Searches the lib for the specified function symbol and returns it.
*
* \param name the name of the function
*
* \return the pointer to the requested function
*
* \throw WLibraryFetchFailed thrown if the symbol could not be found.
*/
func_ptr_type findFunction( const std::string& name )
{
return reinterpret_cast< func_ptr_type >( findVariable( name ) );
}
/**
* Searches the lib for the specified symbol and returns it.
*
* \param name the name of the symbol to search.
*
* \return pointer to the symbol.
*
* \throw WLibraryFetchFailed thrown if the symbol could not be found.
*
*/
void* findVariable( const std::string& name )
{
auto_lock lock();
dlerror();
void* variable_ptr = dlsym( m_dl, name.c_str() );
const char *err = dlerror();
if ( err )
{
throw WLibraryFetchFailed( "Could not fetch symbol \"" + name + "\"" + " due to the error: " + err );
}
return variable_ptr;
}
};
#endif
WSharedLib::WSharedLib( boost::filesystem::path lib ):
m_data( new data( lib.native_file_string() ) )
{
}
WSharedLib::WSharedLib( const WSharedLib& rhs ):
m_data( new data( rhs.m_data->m_path ) )
{
}
WSharedLib::~WSharedLib()
{
delete m_data;
}
WSharedLib& WSharedLib::operator=( const WSharedLib& rhs )
{
WSharedLib o( rhs );
swap( *this, o );
return *this;
}
void swap( WSharedLib& lhs, WSharedLib& rhs )
{
std::swap( lhs.m_data, rhs.m_data );
}
WSharedLib::func_ptr_type WSharedLib::findFunction( const std::string& name ) const
{
return m_data->findFunction( name );
}
void* WSharedLib::findVariable( const std::string& name ) const
{
return m_data->findVariable( name );
}
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#ifndef WSHAREDLIB_H
#define WSHAREDLIB_H
#include <algorithm>
#include <string>
#include <boost/filesystem.hpp>
/**
* This class loads shared libraries and provides function pointers. This is especially useful for dynamic loading of shared libraries during
* runtime. This works on Windows, Linux and Mac OS and is based on the openbug shared_lib implementation by
* Christian Heine <heine@informatik.uni-leipzig.de>. For more details, see http://www.informatik.uni-leipzig.de/~hg/openbug .
*
* \note This class performs locking so that under any system variables of shared_lib may be used in multi-threaded environments.
* \warning Because the POSIX standard does not enforce thread safety for the functions dlopen, dlclose, dlerror, and dlsym, these should not
* be used simultaneously with variables of this class.
*/
class WSharedLib
{
public:
/**
* Constructor. Loads the specified library.
*
* \param lib the library to load. Can be a DLL,SO or DYLIB (depending on system). This can be an absolut or relative path. Otherwise
* standard library search directory may be searched.
*
* \note If the shared library is already loaded, this constructor just
* increases its reference count. This is detected even if different
* paths were used (e.g. "./somelib.so", "../libs/somelib.so").
* \throw WLibraryLoadFailed if the lib could not be loaded. Maybe because of file not found or link errors.
*/
explicit WSharedLib( boost::filesystem::path lib );
/**
* Copies this instance by increasing the reference counter of the loaded library by 1.
*
* \param rhs the other Lib.
*/
WSharedLib( const WSharedLib& rhs );
/**
* Destructor. Decreases the reference counter and unloads the library if the reference count drops to zero.
*/
virtual ~WSharedLib();
/**
* Copy assignment for shared libraries.
*
* \param rhs the one to assign
*
* \return this instance copied from the specified one.
*/
WSharedLib& operator=( const WSharedLib& rhs );
/**
* Swap to shared libraries.
*
* \param lhs the one
* \param rhs the other
*/
friend
void swap( WSharedLib& lhs, WSharedLib& rhs );
/** Search for a function in the shared library.
* \tparam FuncType a function type
* \param name the name of the function
* \param func will be set to the function pointer
*
* \throw WLibraryFetchFailed if the symbol was not found
*
* \warning type unsafe, make sure the symbol actually is of the proper type
*/
template < typename FuncType >
void fetchFunction( const std::string& name, FuncType& func ) const;
/** Search for an variable in the shared library
* \tparam PtrType a pointer type
* \param name the name of the variable
* \param variable will be set to the variable pointer
*
* \throw WLibraryFetchFailed if the symbol was not found
*
* \warning type unsafe, make sure the symbol actually is of the proper type
*/
template < typename PtrType >
void fetchVariable( const std::string& name, PtrType& variable ) const;
protected:
private:
//! neutral function pointer type
typedef void (*func_ptr_type)(void);
/**
* Find the specified function pointer in the library.
*
* \param name the symbol to search
*
* \return the pointer to the symbol as function pointer
*/
func_ptr_type findFunction( const std::string& name ) const;
/**
* Find the specified symbol in the library.
*
* \param name the symbol to search
*
* \return the pointer to the symbol as function pointer.
*/
void* findVariable( const std::string& name ) const;
//! internal data
class data;
//! internal data
data* m_data;
};
template < typename FuncType >
void WSharedLib::fetchFunction( const std::string& name, FuncType& func ) const
{
func = reinterpret_cast< FuncType >( findFunction( name ) );
}
template < typename PtrType >
void WSharedLib::fetchVariable( const std::string& name, PtrType& variable ) const
{
variable = static_cast< PtrType >( findVariable( name ) );
}
#endif // WSHAREDLIB_H
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#include <string>
#include "WLibraryFetchFailed.h"
WLibraryFetchFailed::WLibraryFetchFailed( const std::string& msg )
: WException( msg )
{
// init members
}
WLibraryFetchFailed::~WLibraryFetchFailed() throw()
{
// clean up
}
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#ifndef WLIBRARYFETCHFAILED_H
#define WLIBRARYFETCHFAILED_H
#include <string>
#include "../WException.h"
/**
* Thrown whenever a symbol could not be fetched.
*/
class WLibraryFetchFailed : public WException
{
public:
/**
* Default constructor.
* \param msg the exception message.
*/
explicit WLibraryFetchFailed( const std::string& msg = "The symbol could not be fetched." );
/**
* Destructor.
*/
virtual ~WLibraryFetchFailed() throw();
protected:
private:
};
#endif // WLIBRARYFETCHFAILED_H
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#include <string>
#include "WLibraryLoadFailed.h"
WLibraryLoadFailed::WLibraryLoadFailed( const std::string& msg )
: WException( msg )
{
// init members
}
WLibraryLoadFailed::~WLibraryLoadFailed() throw()
{
// clean up
}
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#ifndef WLIBRARYLOADFAILED_H
#define WLIBRARYLOADFAILED_H
#include <string>
#include "../WException.h"
/**
* Thrown whenever a library could not been loaded. This may be caused by a file not found error or link errors.
*/
class WLibraryLoadFailed : public WException
{
public:
/**
* Default constructor.
* \param msg the exception message.
*/
explicit WLibraryLoadFailed( const std::string& msg = "The library could not be loaded." );
/**
* Destructor.
*/
virtual ~WLibraryLoadFailed() throw();
protected:
private:
};
#endif // WLIBRARYLOADFAILED_H
......@@ -570,13 +570,15 @@ private:
};
/**
* The following macro is used by modules so the factory can aquire a prototype instance.
* The following macro is used by modules so the factory can aquire a prototype instance from a shared library using the symbol.
*/
#define W_SHARED_LIB_ENTRY( MODULECLASS ) \
extern "C" boost::shared_ptr< WModule > createModuleInstance() \
{\
return boost::shared_ptr< WModule >( new MODULECLASS );\
}\
#define W_LOADABLE_MODULE( MODULECLASS ) \
extern "C" boost::shared_ptr< WModule > WLoadModule() { return boost::shared_ptr< WModule >( new MODULECLASS ); } // NOLINT
/**
* The corresponding symbol name.
*/
#define W_LOADABLE_MODULE_SYMBOL "WLoadModule"
/**
* \defgroup modules Modules
......
......@@ -65,7 +65,8 @@ void WModuleFactory::load()
m_prototypeAccess->get().insert( boost::shared_ptr< WModule >( new WMFiberDisplay() ) );
m_prototypeAccess->get().insert( boost::shared_ptr< WModule >( new WMNavSlices() ) );
m_moduleLoader.load( m_prototypeAccess );
// Load the dynamic modules here:
m_moduleLoader.load( m_prototypeAccess );
// unlock as read lock is sufficient for the further steps
m_prototypeAccess.reset();
......@@ -78,7 +79,7 @@ void WModuleFactory::load()
for( PrototypeContainerConstIteratorType listIter = l->get().begin(); listIter != l->get().end();
++listIter )
{