RE: [boost] RE: Re: DLL library (Was: Re: additional boost libraries?)

Vladimir Prus wrote:
Reece Dunn wrote:
I also wonder if it makes sense to sumbit just "dll" library, or some additional plugin support need to be developed first.
What sort of plugin support are you looking for? Do you mean something like COM/CORBA support or wrapper, e.g. something that can target both (and others like them) in one implementation?
I'm not CORBA expert, but I think it's entirely different beast. To use CORBA object you use stub generated from IDL, how it's related to plugins? While there are some ways to find object dynamically, it's different mechanism from shared libraries, isn't it?
I am not sure how CORBA works. COM generally uses a different mechanism to load COM objects via CoCreateInstance, although DirectX exposes creation functions that circumvent this. I was thinking about being able to use COM/CORBA as a platform for object lifetime and dll lifetime management (as well as things like interface extension, etc.).
I though more about at least some kind of map<string, BasePlugin*> which is updated automatically when you load new DLLs.
So the dll implements some function: __declspec(dllexport) BasePlugin * GetMyPlugin(); so you can do something like: void load_plugins( map< string, BasePlugin * > & pi ) { for( map< string, BasePlugin * >::iterator i = pi.begin(); i != pi.end(); ++i ) { boost::dll plugin(( *i ).first ); ( *i ).second = plugin.import< ... >( "GetMyPlugin" ); } } It is possible to keep the DLL in memory until all instances of a class (or set of classes) by incrementing/decrementing a global object count variable on construction/deconstruction as is done when using COM. You then check this variable in the DllCanUnload function. You may need some reference counting mechanism to keep the plugin alive, but this is not necessary if you load all plugins on startup and release them at the end of the run. It should be possible to implement these facilities in a library, e.g.: class object_counter { private: static int objectCount = 0; public: inline int get_object_count(){ return( objectCount ); } public: inline object_counter(){ ++objectCount; } // make MT aware inline ~object_counter(){ --objectCount; } // make MT aware }; class reference_counter { private: int refCount; public: inline void add_ref(){ ++refCount; } // make MT aware inline void dec_ref() { if( --refCount == 0 ) // make MT aware { delete this; } } public: inline reference_counter( int rc ): refCount( rc ){} inline ~reference_counter(){} }; allowing: class plugin: public object_counter, public reference_counter, public BasePlugin { // ... }; __declspec(dllexport) BOOL DllCanUnload() { return( object_counter::get_object_count() == 0 ); } I'm not sure what the Linux equivalent would be. Regards, Reece _________________________________________________________________ Want to block unwanted pop-ups? Download the free MSN Toolbar now! http://toolbar.msn.co.uk/

Reece Dunn wrote:
I'm not CORBA expert, but I think it's entirely different beast. To use CORBA object you use stub generated from IDL, how it's related to plugins? While there are some ways to find object dynamically, it's different mechanism from shared libraries, isn't it?
I am not sure how CORBA works. COM generally uses a different mechanism to load COM objects via CoCreateInstance, although DirectX exposes creation functions that circumvent this. I was thinking about being able to use COM/CORBA as a platform for object lifetime and dll lifetime management (as well as things like interface extension, etc.).
I know next to nothing about COM, so can't on this idea. In all cases, I think it's a bit beyond the scope.
I though more about at least some kind of map<string, BasePlugin*> which is updated automatically when you load new DLLs.
So the dll implements some function:
__declspec(dllexport) BasePlugin * GetMyPlugin();
so you can do something like:
void load_plugins( map< string, BasePlugin * > & pi ) { for( map< string, BasePlugin * >::iterator i = pi.begin(); i != pi.end(); ++i ) { boost::dll plugin(( *i ).first ); ( *i ).second = plugin.import< ... >( "GetMyPlugin" ); } }
I haven't said the whole truth ;-) They key of the map is some string name of plugin, which is not related to its library name. The idea is that you can write this: plugin_map<string, Codegen*> codegens; for(unsigned i = 0; i < libraries.size(); ++i) codegens.load(libraries[i]); (where 'libraries' is a vector of libraries filenames). And after that: codegens["i386"]->run(........)
It is possible to keep the DLL in memory until all instances of a class (or set of classes) by incrementing/decrementing a global object count variable on construction/deconstruction as is done when using COM. You then check this variable in the DllCanUnload function.
Yes, I though about it yesterday and decided that some reference counting is needed. It's probably necessary in more ways: dll my_dll("whatever"); plugin_map<string, Codegen*> codegens; codegens.add(my_dll); .... heavy hacking ... my_dll.reload(); It seems that desire to reload all DLL is valid. In this case, you'd need to also update 'codegens' because new version of DLL might have changed the list of exported plugins. So, "dll" class should somehow track all plugin_maps which depend on it. Or emit boost::signal when it's reloaded.
You may need some reference counting mechanism to keep the plugin alive, but this is not necessary if you load all plugins on startup and release them at the end of the run.
This is the simplest approach, but I still thinking about reloading use case. For example, you have GUI application with plugins. You change some of plugins and want the reloaded them without restarting the GUI. Possible? Yes. Critical? Probably not. Can we implement this with little effort?
It should be possible to implement these facilities in a library, e.g.:
class object_counter { private: static int objectCount = 0; public: inline int get_object_count(){ return( objectCount ); } public: inline object_counter(){ ++objectCount; } // make MT aware inline ~object_counter(){ --objectCount; } // make MT aware };
class reference_counter { private: int refCount; public: inline void add_ref(){ ++refCount; } // make MT aware inline void dec_ref() { if( --refCount == 0 ) // make MT aware { delete this; } } public: inline reference_counter( int rc ): refCount( rc ){} inline ~reference_counter(){} };
allowing:
class plugin: public object_counter, public reference_counter, public BasePlugin { // ... };
__declspec(dllexport) BOOL DllCanUnload() { return( object_counter::get_object_count() == 0 ); }
Do you mean that reference counting should be done by DLL itself? Why not: template<class T> class plugin_ptr { public: // operator-> and friends private: T* m_ptr; shared_ptr<dll_handle> m_dll; } So, 'dll' won't be deleted until all plugins which use it are dead. - Volodya

On Tuesday 27 July 2004 07:21, Vladimir Prus wrote:
Do you mean that reference counting should be done by DLL itself? Why not:
template<class T> class plugin_ptr { public: // operator-> and friends private: T* m_ptr; shared_ptr<dll_handle> m_dll; }
So, 'dll' won't be deleted until all plugins which use it are dead.
The way we do that at my company is that all objects returned by a plugin are held my a shared_ptr which has a custom deleter which decrements a ref count on the library itself. Ben ---

Ben Young wrote:
On Tuesday 27 July 2004 07:21, Vladimir Prus wrote:
Do you mean that reference counting should be done by DLL itself? Why not:
template<class T> class plugin_ptr { public: // operator-> and friends private: T* m_ptr; shared_ptr<dll_handle> m_dll; }
So, 'dll' won't be deleted until all plugins which use it are dead.
The way we do that at my company is that all objects returned by a plugin are held my a shared_ptr which has a custom deleter which decrements a ref count on the library itself.
Something like void* h = dlopen(......) ; boost::shared_ptr<Plugin> p( ...... dlsym(.....), bind(dlclose, h)) ? That's interesting, but is raises two questions: - What if you get two plugins from the same dll? - If dll can be reloaded, then, as I mention in another email, we'd need to notify all 'plugin_map' instances when dll is reloaded, so dll_handle must be a bit more smart. What I'm thinking about now is: class dll_handle : boost::noncopyable { public: // Opens the specified library. If it's already opened, returns // pointer to an existing dll_handle. shared_ptr<dll_handle> get(const std::string& name); void* operator[](const std::string& symbol_name); private: dll_handle(const std::string& name); }; class dll { public: dll(const std::string& name); // default copy-ctor is OK template<.......> .... call(.......); template<......> .... import(.......); private: boost::shared_ptr<dll_handle> m_handle; }; class plugin_ptr { public: // Minimum set of smart_ptr methods private: // Just to keep the DLL in memory when plugin is in memory shared_ptr<dll_handle> m_handle; }; class plugin_map { public: ... interface to be yet defined ... }; - Volodya

Hi boosters, I developed a fairly simple prototype of a dll loader which mangles functions names automatically. But there are limitiations: you cannot call function which have template class parameters or return value, e.g. void test(std::string const &str) will not work. I do not get the mangling scheme used to decorate such a type, maybe someone knows a good source where I can look that up?! For class mangling I use the string returned by type_info::name(), but that seems very hacky. Microsoft Visual C++ does not always return correct strings (e.g. typeid(int &).name() returns "int"). Sorry that I attached the source code to that mail as I know that only a few will look at it, but I don't have a homepage handy to upload it there. - nico
Vladimir Prus wrote:
Reece Dunn wrote:
I also wonder if it makes sense to sumbit just "dll" library, or some additional plugin support need to be developed first.
What sort of plugin support are you looking for? Do you mean something like COM/CORBA support or wrapper, e.g. something that can target both (and others like them) in one implementation?
I'm not CORBA expert, but I think it's entirely different beast. To use CORBA object you use stub generated from IDL, how it's related to plugins? While there are some ways to find object dynamically, it's different mechanism from shared libraries, isn't it?
I am not sure how CORBA works. COM generally uses a different mechanism to load COM objects via CoCreateInstance, although DirectX exposes creation functions that circumvent this. I was thinking about being able to use COM/CORBA as a platform for object lifetime and dll lifetime management (as well as things like interface extension, etc.).
I though more about at least some kind of map<string, BasePlugin*> which is updated automatically when you load new DLLs.
So the dll implements some function:
__declspec(dllexport) BasePlugin * GetMyPlugin();
so you can do something like:
void load_plugins( map< string, BasePlugin * > & pi ) { for( map< string, BasePlugin * >::iterator i = pi.begin(); i != pi.end(); ++i ) { boost::dll plugin(( *i ).first ); ( *i ).second = plugin.import< ... >( "GetMyPlugin" ); } }
It is possible to keep the DLL in memory until all instances of a class (or set of classes) by incrementing/decrementing a global object count variable on construction/deconstruction as is done when using COM. You then check this variable in the DllCanUnload function.
You may need some reference counting mechanism to keep the plugin alive, but this is not necessary if you load all plugins on startup and release them at the end of the run.
It should be possible to implement these facilities in a library, e.g.:
class object_counter { private: static int objectCount = 0; public: inline int get_object_count(){ return( objectCount ); } public: inline object_counter(){ ++objectCount; } // make MT aware inline ~object_counter(){ --objectCount; } // make MT aware };
class reference_counter { private: int refCount; public: inline void add_ref(){ ++refCount; } // make MT aware inline void dec_ref() { if( --refCount == 0 ) // make MT aware { delete this; } } public: inline reference_counter( int rc ): refCount( rc ){} inline ~reference_counter(){} };
allowing:
class plugin: public object_counter, public reference_counter, public BasePlugin { // ... };
__declspec(dllexport) BOOL DllCanUnload() { return( object_counter::get_object_count() == 0 ); }
I'm not sure what the Linux equivalent would be.
Regards, Reece
_________________________________________________________________ Want to block unwanted pop-ups? Download the free MSN Toolbar now! http://toolbar.msn.co.uk/
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
***************************************************************************** ** ** ** WARNING: This email contains an attachment of a very suspicious type. ** ** You are urged NOT to open this attachment unless you are absolutely ** ** sure it is legitmate. Opening this attachment may cause irreparable ** ** damage to your computer and your files. If you have any questions ** ** about the validity of this message, PLEASE SEEK HELP BEFORE OPENING IT. ** ** ** ** This warning was added by the IU Computer Science Dept. mail scanner. ** *****************************************************************************

I developed a fairly simple prototype of a dll loader which mangles functions names automatically. But there are limitiations: you cannot call function which have template class parameters or return value, e.g. void test(std::string const &str) will not work. I do not get the mangling scheme used to decorate such a type, maybe someone knows a good source where I can look that up?! For class mangling I use the string returned by type_info::name(), but that seems very hacky. Microsoft Visual C++ does not always return correct strings (e.g. typeid(int &).name() returns "int").
Actually I think more compilers return "human readable" names from this that return mangled names - gcc is the only compiler I know of that does this. And of course nearly every C++ compiler uses it's own incompatible name mangling scheme as well... John.

I don't really understand, MSVC also returns human readable strings from type_info::name(), this string is then parsed by a boost::spirit parser and is split up to have the ability to mangle it correctly. But as I said I have problems in mangling template parameters, I don't get the algorithm which is used to mangle that. Maybe someday I have much inspiration and get behind the scheme ;-) . (the corrosponding symbol for std::string is "V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@", I don't know where the 2 comes from...) What I meant to say is that the type_info string does not always represent the type you've given in typeid(...), e.g. typeid(int const &).name() returns "int", which is wrong (typeid(int const *) instead returns "int *", somewhat strange). The loader currently only works for MSVC and WIN32, but if gcc returns mangled names from typeid the loading should be much easier to implement for gcc compilers. nico
I developed a fairly simple prototype of a dll loader which mangles functions names automatically. But there are limitiations: you cannot call function which have template class parameters or return value, e.g. void test(std::string const &str) will not work. I do not get the mangling scheme used to decorate such a type, maybe someone knows a good source where I can look that up?! For class mangling I use the string returned by type_info::name(), but that seems very hacky. Microsoft Visual C++ does not always return correct strings (e.g. typeid(int &).name() returns "int").
Actually I think more compilers return "human readable" names from this that return mangled names - gcc is the only compiler I know of that does this. And of course nearly every C++ compiler uses it's own incompatible name mangling scheme as well...
John.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
participants (5)
-
Ben Young
-
Florian Grafenberg
-
John Maddock
-
Reece Dunn
-
Vladimir Prus