From: <sg...@us...> - 2003-09-28 01:35:52
|
Update of /cvsroot/libfunutil/libfunutil/lib/s11n In directory sc8-pr-cvs1:/tmp/cvs-serv3118/lib/s11n Modified Files: DLLLoader.cpp DLLLoader.h Makefile S11n.h Log Message: refinements/improvments to the classloader. Added DLLLoader_boostrap "callback" support, to run boostrapping code when opening an DLL. This allows a way around using S11N_INSTANTIATOR, and a way to dynamically add factories to the classloader from DLLs. Index: DLLLoader.cpp =================================================================== RCS file: /cvsroot/libfunutil/libfunutil/lib/s11n/DLLLoader.cpp,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- DLLLoader.cpp 27 Sep 2003 22:36:54 -0000 1.1 +++ DLLLoader.cpp 28 Sep 2003 01:35:30 -0000 1.2 @@ -8,15 +8,54 @@ #include "DLLLoader.h" #include <s11n/s11n-macros.h> // COUT/CERR + +// note: if you define DLLLOADER_DEFAULT_PATH via the command line, be sure to +// escape the quote marks. e.g.: +// DLLLoader_cpp_CPPFLAGS = -DDLLLOADER_DEFAULT_PATH=\".:$(prefix)/lib\" +#ifndef DLLLOADER_DEFAULT_PATH +# define DLLLOADER_DEFAULT_PATH "." +#endif + +#define DLLLOADER_PATH DLLLOADER_DEFAULT_PATH + namespace s11n { static void * soh_main = NULL; - unsigned long DLLLoader::inst_count = 0; + unsigned long DLLLoader_inst_count = 0; + + /** + Looks for a bootstrap function in newly-opened shared + objects, and runs it if it exists. Returns true if the + object has a registry, else false. It only runs the + registry the first time it is passed a given pointer. + */ + bool check_for_registry( void * soh ) + { + if( ! soh ) return false; + const char * funcname = "DLLLoader_bootstrap"; + typedef void (*registry)(); + typedef std::map<void *,unsigned long int> done_map; + static done_map done; + if( done[soh] ) return true; + //COUT << "check_for_registry(" << std::hex << soh << ")"<<std::endl; + done[soh] = 1; + registry reg; + reg = (registry) dlsym( soh, funcname ); + if( ! reg ) + { + //CERR << "no " << funcname << "() found in " << std::hex << soh << "" << std::endl; + return false; + } + reg(); + return true; + } + + DLLLoader::DLLLoader() { - ++inst_count; + ++DLLLoader_inst_count; this->path().addExtension( ".so" ); - this->path().addPath( "." ); + this->path().setPath( DLLLOADER_PATH ); const char * p = getenv( "S11N_PATH" ); if( ! p ) getenv( "LD_LIBRARY_PATH" ); if( p ) @@ -25,15 +64,15 @@ } if( ! soh_main ) { - soh_main = dlopen( 0, RTLD_NOW | RTLD_GLOBAL ); - //COUT << "Address of main app, from dlopen() perspective: " << std::hex << soh_main<<""<<std::endl; + soh_main = dlopen( NULL, RTLD_NOW | RTLD_GLOBAL ); + check_for_registry( soh_main ); } } DLLLoader::~DLLLoader() { - if( 0 == --inst_count ) + if( 0 == --DLLLoader_inst_count ) { dlclose( soh_main ); DLLLoader::soh_map_type & map = DLLLoader::soh_map(); @@ -41,7 +80,7 @@ DLLLoader::soh_map_type::iterator et = map.end(); for( ; it != et; ++it ) { - COUT << "Closing DLL: " << std::hex <<(*it).second<<std::endl; + //COUT << "Closing DLL: " << std::hex <<(*it).second<<std::endl; dlclose( (*it).second ); } } @@ -60,77 +99,106 @@ static DLLLoader::symbol_map_type bob; return bob; } + + DLLLoader::value_type * DLLLoader::load( const std::string & key ) const { //COUT << "load("<<key<<")"<<std::endl; - //static void * error_entry = NULL; // maintenance note: this might Cause Grief with subclasses. - // mostly untested. - // todo: add an option to force-deserialize a node, even when the types don't match. typedef ThisType::value_type CHT; - CHT *ch = this->ParentClass::load( key ); + CHT *ch = NULL; + ch = this->ParentClass::load( key ); if ( ch ) return ch; - std::string xlated = key; - std::string::size_type colon = xlated.rfind( ":" ); - if( std::string::npos != colon ) + + void * soh = 0; + std::string xlated = key; // key, translated to remove namespace part (because :: is not filesystem-friendly). + std::string path = key; + DLLLoader::soh_map_type & map = DLLLoader::soh_map(); + DLLLoader::soh_map_type::iterator it = map.find(key); + if( map.end() != it ) { - xlated = key.substr( colon + 1 ); + soh = (*it).second; + if( NULL == soh ) return NULL; } - string path = this->path().find( xlated ); - if ( path.empty() ) + else { - CERR << "Neither in-built class nor DLL found for "<<key<<" ["<<xlated<<"]"<<std::endl; - return NULL; + std::string::size_type colon = xlated.rfind( ":" ); + if( std::string::npos != colon ) + { + xlated = key.substr( colon + 1 ); + } + path = this->path().find( xlated ); + if ( path.empty() ) + { + CERR << "Neither in-built class nor DLL found for "<<key<<" ["<<xlated<<"]. path=["<<this->path()<<"]"<<std::endl; + return NULL; + } + it = map.find(path); + //COUT << "load("<<key<<" ["<<xlated<<"]) dll path="<<path<<std::endl; } - //COUT << "load("<<key<<" ["<<xlated<<"]) dll path="<<path<<std::endl; - void * soh = 0; - - DLLLoader::soh_map_type & map = DLLLoader::soh_map(); - DLLLoader::soh_map_type::iterator it = map.find(key); if( map.end() != it ) { soh = (*it).second; - //COUT << "cached entry ["<<key<<"]: " << std::hex << soh << std::endl; + //COUT << "cached entry ["<<path<<"]: " << std::hex << soh << std::endl; if( NULL == soh ) return NULL; } else { soh = dlopen( path.c_str(), RTLD_NOW | RTLD_GLOBAL ); - if( ! soh ) soh = soh_main; + if( ! soh ) + { + COUT << "error? dlerror() says: " << dlerror() << std::endl; + soh = soh_main; + } + //COUT << "key="<<key<<" ["<<xlated<<"], path=["<<path<<"], soh = " << std::hex << soh << ", dll path="<<path<<std::endl; if( ! soh ) { - map[key] = (void *)NULL; + map[path] = map[key] = (void *)NULL; return NULL; } - map[key] = soh; + map[path] = map[key] = soh; + } + + if( check_for_registry( soh ) ) + { // give parent another chance. registration may have assigned a factory. + ch = this->ParentClass::load( key ); + if( ch ) return ch; } - //COUT << "soh = " << std::hex << soh << std::endl; - const char * inst_funcname = "instantiateSerializable"; - DLLLoader::instantiator_func instantiator; + + DLLLoader::instantiator_func instantiator = 0; DLLLoader::symbol_map_type & symmap = DLLLoader::symbol_map(); DLLLoader::symbol_map_type::iterator sit = symmap.find(soh); - if( symmap.end() == sit ) + if( symmap.end() != sit ) { - if( (instantiator = (instantiator_func) dlsym( soh, inst_funcname )) ) - { - symmap[soh] = instantiator; - } - - //COUT << "instantiator = " << std::hex << instantiator << std::endl; + instantiator = (*sit).second; } else { - instantiator = (*sit).second; + //const char * inst_funcname = "instantiateSerializable"; + std::string inst_funcname = "new_" + xlated; + if( (instantiator = (instantiator_func) dlsym( soh, inst_funcname.c_str() )) ) + { + symmap[soh] = instantiator; + } + else + { + symmap[soh] = NULL; + } } + if( ! instantiator ) { - CERR << "error? dlerror() says: " <<dlerror() << std::endl; + //CERR << "error? dlerror() says: " <<dlerror() << std::endl; if( soh && (soh_main != soh) ) dlclose( soh ); - map[key] = (void *)NULL; + map[path] = map[key] = (void *)NULL; return NULL; } - ch = instantiator( key.c_str() ); + + if( NULL != instantiator ) + { + ch = instantiator( key.c_str() ); + } return ch; } Index: DLLLoader.h =================================================================== RCS file: /cvsroot/libfunutil/libfunutil/lib/s11n/DLLLoader.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- DLLLoader.h 27 Sep 2003 22:36:54 -0000 1.1 +++ DLLLoader.h 28 Sep 2003 01:35:30 -0000 1.2 @@ -39,12 +39,38 @@ This class represents my very first usage of dlopen(), and there may be bugs related to my use of dlopen()/dlclose(). + + + + Instead of using the S11N_INSTANTIATOR macro you may do the + following: + + Define an extern "C" function with this sigature: + + void DLLLoader_bootstrap(); + + If that function exists it is called when the class is loaded. + This gives the class a chance to register factories for other + names of itself or for dependent classes. + + Example: + + extern "C" { + void DLLLoader_bootstrap() + { + s11n::register_serializable_type<foo::FooClass>("FooClass"); + s11n::register_serializable_type<foo::FooClass>("foo::FooClass"); + s11n::register_serializable_type<foo::FooClass>("WonderBra"); + } + } + + This approach prohibits more than one definition in the same DLL. + */ - class DLLLoader : public s11n::ClassLoader < s11n::Serializable > + class DLLLoader : public s11n::ClassLoader < s11n::Serializable, std::string > { private: - typedef s11n::ClassLoader < s11n::Serializable > ParentClass; - static unsigned long inst_count; + typedef s11n::ClassLoader < s11n::Serializable, std::string > ParentClass; protected: typedef s11n::Serializable * (*instantiator_func)( const char * ); typedef std::map<std::string,void *> soh_map_type; Index: Makefile =================================================================== RCS file: /cvsroot/libfunutil/libfunutil/lib/s11n/Makefile,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- Makefile 27 Sep 2003 22:36:54 -0000 1.1 +++ Makefile 28 Sep 2003 01:35:30 -0000 1.2 @@ -38,10 +38,13 @@ endif +top_srcdir_absolute = $(shell cd $(top_srcdir) && pwd) +DLLLoader_cpp_CPPFLAGS = -DDLLLOADER_DEFAULT_PATH=\".:$(top_srcdir_absolute)/lib/s11n:$(prefix)/lib\" OBJECTS = $(patsubst %.cpp,%.o,$(SOURCES)) PARSER_OBJECTS = $(addprefix parsers/,flex_lexers.o funtxt.flex.o funxml.flex.o select_lexer.flex.o simplexml.flex.o) +INSTALL_PACKAGE_HEADERS_DEST = $(prefix)/include/s11n INSTALL_PACKAGE_HEADERS = $(HEADERS) STATIC_LIBS = libs11n @@ -52,10 +55,7 @@ ifeq (1,$(build_s11n_so)) SHARED_LIBS = $(STATIC_LIBS) libs11n_so_OBJECTS = $(libs11n_a_OBJECTS) -libs11n_so_VERSION = 0.1.0 -ifeq (1,$(configure_with_libreadline)) -libs11n_so_LDADD += $(LIBREADLINE_LDADD) -endif +libs11n_so_VERSION = 0.0.1 include $(toc_makesdir)/cpp_dynamic_libs.make endif # ^^^^ build shared libs? Index: S11n.h =================================================================== RCS file: /cvsroot/libfunutil/libfunutil/lib/s11n/S11n.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- S11n.h 27 Sep 2003 22:36:54 -0000 1.1 +++ S11n.h 28 Sep 2003 01:35:30 -0000 1.2 @@ -27,19 +27,31 @@ Alternately, they should have an extern "C" function with this signature: - YourClass * instantiateSerializable( const char * ); + YourClass * new_YourClass( const char * ); - The char * parameter does nothing in the default implementation, but - could be implemented to provide (e.g.) multiple key-to-class mappings, - or access to multiple loadable classes in the same object file. + The char * parameter does nothing in the default implementation, + but could be implemented to provide (e.g.) multiple key-to-class + mappings, or access to multiple loadable classes in the same object + file, or perhaps to use for proxy loading. + + YourClass must currently be a Serializable type. + + Sample usages: + + S11N_INSTANTIATOR(,GlobalNameSpaceClass); + S11N_INSTANTIATOR(my::namespace,SomeClass); + + i appologize about the weird arguments syntax, but it's the best i can + manage with C macros. */ -#define S11N_INSTANTIATOR(ClsName) extern "C" {\ - ClsName * instantiateSerializable( const char * clname ) \ +#define S11N_INSTANTIATOR(NS,ClsName) \ + extern "C" {\ + NS::ClsName * new_ ## ClsName( const char * clname ) \ { \ - /** COUT << # ClsName << " * instantiateSerializable("<<clname<<")"<<std::endl;*/ \ - return new ClsName; }\ - }; + /**COUT << # ClsName << " * instantiateSerializable("<<clname<<")"<<std::endl;*/ \ + return new NS::ClsName; \ + }}; namespace s11n |