From b98617b3c86863fe5b4e3d9a96519707ae8cf58c Mon Sep 17 00:00:00 2001 From: Matúš Kukan Date: Wed, 10 Apr 2013 18:20:06 +0200 Subject: API CHANGE: remove some of useless rtl/unload.h functionality Change-Id: If32923e35ef97f42d5203975362e5c76948ff327 Signed-off-by: Stephan Bergmann --- sal/inc/rtl/unload.h | 197 -------------------------- sal/osl/all/compat.cxx | 28 ++++ sal/rtl/unload.cxx | 364 +------------------------------------------------ 3 files changed, 29 insertions(+), 560 deletions(-) diff --git a/sal/inc/rtl/unload.h b/sal/inc/rtl/unload.h index 9de17b4b97d9..0bbc414e792d 100644 --- a/sal/inc/rtl/unload.h +++ b/sal/inc/rtl/unload.h @@ -27,79 +27,6 @@ #include "sal/saldllapi.h" #include "sal/types.h" -/** @file -The API enables an effective way of unloading libraries in a centralized way. -The mechanism ensures that used libraries are not unloaded. This prevents -crashes if library code is being used after unloading the library. -The unloading mechanism currently only works with libraries which contain -UNO services. A library cannot be unloaded if one of the following conditions -apply - - - -Notification Mechanism -The API provides a notification mechanism. Clients can use it to do clean up, -such as releasing cached references, in order to allow modules to be unloaded. -As long as someone holds a reference to an object whose housing module -supports unloading the module cannot be unloaded.

- -Because of the inherent danger of crashing the application by using this API -all instances which control threads should be registered listeners. On -notification they have to ensure that their threads assume a safe state, that -is, they run outside of modules which could be unloaded and do not jump -back into module code as a result of a finished function call. In other words, -there must not be an address of the module on the thread's stack. -

-Since current operating systems lack APIs in respect to controlling the -position of threads within libraries, it would be a major effort to comply with -that recommendation. The best and most efficient way of handling the unloading -scenario is to let all threads, except for the main thread, die in case of a -notification. -

-Use this API with great care because it might crash the application. See the -respective documentation (Library Unloading) on the udk.openoffice.org web site. -*/ - - -/** -A library which supports unloading has to implement and export a function -called component_canUnload.

-If the function returns sal_True then the module can be safely unloaded. -That is the case when there are no external references to code within the -library. In case a module houses UNO components then the function must return -sal_False after the first factory has been handed out. The function then -continues to return sal_False as long as there is at least one object (factory -or service instance) which originated from the module.

- -Libraries which not only contain UNO components (or none at all) have to -provide a means to control whether they can be unloaded or not, e.g. However, -there is no concept yet.

- -The argument pTime is an optional out-parameter. If the return value is -sal_True then pTime reflects a point in time since -when the module could have -been unloaded. Since that time the function would have continually returned -sal_True up to the present. The value of pTime is -important for the decision -as to a module will be unloaded. When someone initiates the unloading of -modules by calling rtl_unloadUnusedModules then the caller can specify a time -span with the effect that only those modules are unloaded which are unused at -least for that amount of time. If component_canUnload does not -fill in pTime -then the module is unloaded immediately.

- -component_canUnload is implicitly called by rtl_unloadUnusedModules -. There is no need to call the function directly. -*/ -#define COMPONENT_CANUNLOAD "component_canUnload" -typedef sal_Bool (SAL_CALL * component_canUnloadFunc)( TimeValue* pTime); - - /** C-interface for a module reference counting */ #ifdef __cplusplus @@ -107,130 +34,6 @@ extern "C" { #endif -/** -By registering a module, one declares that a module supports the -unloading mechanism. One registers a module by calling this function.

- -A module can only be unloaded from memory when it has been registered -as many times as it has been loaded. The reason is that a library can -be "loaded" several times by osl_loadModule -within the same process. The -function will then return the same module handle because the library will -effectively only be loaded once. To remove the library from memory it is -necessary to call osl_unloadModule as often as -osl_loadModule was called. The -function rtl_unloadUnusedModules calls osl_unloadModule -for a module as many -times as it was registered. If, for example, a module has been registered one -time less then osl_loadModule has been called and the module can be unloaded -then it needs a call to rtl_unloadUnusedModules and an explicit call to -osl_unloadModule to remove the module from memory.

- -A module must be registered every time it has been loaded otherwise the -unloading mechanism is not effective.

- -Before a module is registered, one has to make sure that the module is in a -state that prevents it from being unloaded. In other words, -component_canUnload must return sal_False. Assuming that -component_canUnload -returns sal_True and it is registered regardless, then a call to -rtl_unloadUnusedModules causes the module to be unloaded. This unloading can -be set off by a different thread and the thread which registered the module is -"unaware" of this. Then when the first thread tries to obtain a factory or -calls another function in the module, the application will crash, because the -module has been unloaded before. Therefore one has to ensure that the module -cannot be unloaded before it is registered. This is simply done by obtaining a -factory from the module. As long as a factory or some other object, which has -been created by the factory, is alive, the component_canUnload function will -return sal_False.

-Loading and registering have to be in this order:
-

-Usually the service manager is used to obtain an instance of a service. -The service manager registers all modules which support the unloading mechanism. -When the service manager is used to get service instances than one does not -have to bother about registering. - -@param module a module handle as is obtained by osl_loadModule -@return sal_True - the module could be registered for unloading, sal_False otherwise -*/ -SAL_DLLPUBLIC sal_Bool SAL_CALL rtl_registerModuleForUnloading( oslModule module); - -/** -The function revokes the registration of a module. By calling the function for -a previously registered module one prevents the module from being unloaded by -this unloading mechanism. However, in order to completely unregister the module -it is necessary to call the function as often as the module has been registered. -

-rtl_unloadUnusedModules unregisters the modules which it unloads. Therefore -there is no need to call this function unless one means to prevent the unloading of a module. - -@param module a module handle as is obtained by osl_loadModule -*/ -SAL_DLLPUBLIC void SAL_CALL rtl_unregisterModuleForUnloading( oslModule module); -/** -This function sets off the unloading mechanism. At first it notifies the -unloading listeners in order to give them a chance to do cleanup and get -their threads in a safe state. Then all registered modules are asked if they -can be unloaded. That is, the function calls component_canUnload on every -registered module. If sal_True is returned then osl_unloadModule -is called for the belonging module as often as it is registered. -

-A call to osl_unloadModule does not guarantee that the module is unloaded even -if its component_canUnload function returns sal_True. -

-The optional in-parameter libUnused specifies a period of time which a library -must be unused in order to qualify for being unloaded. By using this argument -one can counter the multithreading problem as described further above. It is in -the responsibility of the user of this function to provide a timespan big enough -to ensure that all threads are out of modules (see component_canUnload). -

-The service managers which have been created by functions such as -createRegistryServiceFactory (declared in cppuhelper/servicefactory.hxx) are -registered listeners and release the references to factories on notification. - - -@param libUnused span of time that a module must be unused to be unloaded. the -argument is optional. -*/ -SAL_DLLPUBLIC void SAL_CALL rtl_unloadUnusedModules( TimeValue* libUnused); - -/** -rtl_addUnloadingListener takes an argument of this type. - -@param id - The value that has been passed as second argument to rtl_addUnloadingListener -*/ -typedef void (SAL_CALL *rtl_unloadingListenerFunc)(void* id); -/** -The function registered an unloading listener. The callback argument is a -function which is called when the unloading procedure has been initiated by a call to -rtl_unloadUnusedLibraries. The second argument is used to distinguish between different -listener instances and may be NULL. It will be passed as argument when the callback -function is being called. The return value identifies the registered listener and will -be used for removing the listener later on. If the same listener is added more then -once then every registration is treated as if made for a different listener. That is, -a different cookie is returned and the callback function will be called as many times -as it has been registered. -@param callback - a function that is called to notify listeners. -@param _this - a value to distinguish different listener instances -@return identifier which is used in rtl_removeUnloadingListener -*/ -SAL_DLLPUBLIC sal_Int32 SAL_CALL rtl_addUnloadingListener( rtl_unloadingListenerFunc callback, void* _this); - -/** -Listeners (the callback functions) must be unregistered before the listener code -becomes invalid. That is, if a module contains listener code, namely callback -functions of type rtl_unloadingListenerFunc, then those functions must not be -registered when component_canUnload returns sal_True. - -@param cookie is an identifier as returned by rtl_addUnloadingListener function. -*/ -SAL_DLLPUBLIC void SAL_CALL rtl_removeUnloadingListener( sal_Int32 cookie ); - - /** Pointers to rtl_ModuleCount are passed as arguments to the default factory creator functions: createSingleComponentFactory, createSingleFactory, diff --git a/sal/osl/all/compat.cxx b/sal/osl/all/compat.cxx index f9c712982bcf..12f0da13fade 100644 --- a/sal/osl/all/compat.cxx +++ b/sal/osl/all/compat.cxx @@ -11,6 +11,8 @@ #include +#include "osl/module.h" +#include "osl/time.h" #include "sal/types.h" // Stubs for removed functionality, to be killed when we bump sal SONAME @@ -69,6 +71,32 @@ SAL_DLLPUBLIC_EXPORT void SAL_CALL rtl_zeroMemory(void *, sal_Size) { std::abort(); } +SAL_DLLPUBLIC_EXPORT sal_Bool SAL_CALL rtl_registerModuleForUnloading(oslModule) +{ + for (;;) { std::abort(); } // avoid "must return a value" warnings +} + +SAL_DLLPUBLIC_EXPORT void SAL_CALL rtl_unregisterModuleForUnloading(oslModule) +{ + std::abort(); +} + +SAL_DLLPUBLIC_EXPORT void SAL_CALL rtl_unloadUnusedModules(TimeValue *) +{ + std::abort(); +} + +typedef void (SAL_CALL *rtl_unloadingListenerFunc)(void *id); +SAL_DLLPUBLIC_EXPORT sal_Int32 SAL_CALL rtl_addUnloadingListener(rtl_unloadingListenerFunc, void *) +{ + for (;;) { std::abort(); } // avoid "must return a value" warnings +} + +SAL_DLLPUBLIC_EXPORT void SAL_CALL rtl_removeUnloadingListener(sal_Int32) +{ + std::abort(); +} + } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/rtl/unload.cxx b/sal/rtl/unload.cxx index 4d4a41496983..dd8ee23b49bc 100644 --- a/sal/rtl/unload.cxx +++ b/sal/rtl/unload.cxx @@ -17,19 +17,11 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ -#include - #include -#include + #include #include #include -#include -#include "rtl/allocator.hxx" - -#include -#include -#include using osl::MutexGuard; @@ -37,72 +29,6 @@ using osl::MutexGuard; #ifndef DISABLE_DYNLOADING -static void rtl_notifyUnloadingListeners(); - -static sal_Bool isEqualTimeValue ( const TimeValue* time1, const TimeValue* time2) -{ - if( time1->Seconds == time2->Seconds && - time1->Nanosec == time2->Nanosec) - return sal_True; - else - return sal_False; -} - -static sal_Bool isGreaterTimeValue( const TimeValue* time1, const TimeValue* time2) -{ - sal_Bool retval= sal_False; - if ( time1->Seconds > time2->Seconds) - retval= sal_True; - else if ( time1->Seconds == time2->Seconds) - { - if( time1->Nanosec > time2->Nanosec) - retval= sal_True; - } - return retval; -} - -static sal_Bool isGreaterEqualTimeValue( const TimeValue* time1, const TimeValue* time2) -{ - if( isEqualTimeValue( time1, time2) ) - return sal_True; - else if( isGreaterTimeValue( time1, time2)) - return sal_True; - else - return sal_False; -} - -static void addTimeValue( const TimeValue* value1, const TimeValue* value2, TimeValue* result) -{ - sal_uInt64 sum; - result->Nanosec=0; - result->Seconds=0; - - sum= value1->Nanosec + value2->Nanosec; - if( sum >= 1000000000 ) - { - result->Seconds=1; - sum -= 1000000000; - } - result->Nanosec= (sal_uInt32)sum; - result->Seconds += value1->Seconds + value2->Seconds; -} - - -static sal_Bool hasEnoughTimePassed( const TimeValue* unusedSince, const TimeValue* timespan) -{ - sal_Bool retval= sal_False; - TimeValue currentTime; - if( osl_getSystemTime( ¤tTime)) - { - TimeValue addedTime; - addTimeValue( unusedSince, timespan, &addedTime); - if( isGreaterEqualTimeValue( ¤tTime, &addedTime)) - retval= sal_True; - } - - return retval; -} - namespace { class theUnloadingMutex : public rtl::Static{}; @@ -147,43 +73,6 @@ extern "C" void rtl_moduleCount_release( rtl_ModuleCount * that ) #endif } -#ifndef DISABLE_DYNLOADING - -struct hashModule -{ - size_t operator()( const oslModule& rkey) const - { - return (size_t)rkey; - } -}; - -typedef boost::unordered_map< - oslModule, - std::pair, - hashModule, - std::equal_to, - rtl::Allocator -> ModuleMap; - -typedef ModuleMap::iterator Mod_IT; - -static ModuleMap& getModuleMap() -{ - static ModuleMap * g_pMap= NULL; - if (!g_pMap) - { - MutexGuard guard( getUnloadingMutex() ); - if (!g_pMap) - { - static ModuleMap g_aModuleMap; - g_pMap= &g_aModuleMap; - } - } - return *g_pMap; -} - -#endif - extern "C" sal_Bool rtl_moduleCount_canUnload( rtl_StandardModuleCount * that, TimeValue * libUnused) { #ifdef DISABLE_DYNLOADING @@ -203,255 +92,4 @@ extern "C" sal_Bool rtl_moduleCount_canUnload( rtl_StandardModuleCount * that, T #endif } - -extern "C" sal_Bool SAL_CALL rtl_registerModuleForUnloading( oslModule module) -{ -#ifdef DISABLE_DYNLOADING - (void) module; - return sal_False; -#else - MutexGuard guard( getUnloadingMutex()); - ModuleMap& moduleMap= getModuleMap(); - sal_Bool ret= sal_True; - - // If the module has been registered before, then find it and increment - // its reference cout - Mod_IT it= moduleMap.find( module); - if( it != moduleMap.end()) - { - //module already registered, increment ref count - it->second.first++; - } - else - { - // Test if the module supports unloading (exports component_canUnload) - rtl::OUString name(RTL_CONSTASCII_USTRINGPARAM( COMPONENT_CANUNLOAD)); - component_canUnloadFunc pFunc= - (component_canUnloadFunc)osl_getFunctionSymbol( module, name.pData); - if (pFunc) - { - //register module for the first time, set ref count to 1 - moduleMap[module]= std::make_pair((sal_uInt32)1, pFunc); - } - else - ret= sal_False; - } - return ret; -#endif -} - -extern "C" void SAL_CALL rtl_unregisterModuleForUnloading( oslModule module) -{ -#ifdef DISABLE_DYNLOADING - (void) module; -#else - MutexGuard guard( getUnloadingMutex()); - - ModuleMap& moduleMap= getModuleMap(); - Mod_IT it= moduleMap.find( module); - if( it != moduleMap.end() ) - { - // The module is registered, decrement ref count. - it->second.first --; - - // If the refcount == 0 then remove the module from the map - if( it->second.first == 0) - moduleMap.erase( it); - } -#endif -} - -extern "C" void SAL_CALL rtl_unloadUnusedModules( TimeValue* libUnused) -{ -#ifdef DISABLE_DYNLOADING - (void) libUnused; -#else - MutexGuard guard( getUnloadingMutex()); - - typedef std::list< oslModule, rtl::Allocator > list_type; - list_type unloadedModulesList; - - ModuleMap& moduleMap= getModuleMap(); - Mod_IT it_e= moduleMap.end(); - - // notify all listeners - rtl_notifyUnloadingListeners(); - - // prepare default TimeValue if argumetn is NULL - TimeValue nullTime={0,0}; - TimeValue* pLibUnused= libUnused? libUnused : &nullTime; - - Mod_IT it= moduleMap.begin(); - for (; it != it_e; ++it) - { - //can the module be unloaded? - component_canUnloadFunc func= it->second.second; - TimeValue unusedSince= {0, 0}; - - if( func( &unusedSince) ) - { - // module can be unloaded if it has not been used at least for the time - // specified by the argument libUnused - if( hasEnoughTimePassed( &unusedSince, pLibUnused)) - { - // get the reference count and unload the module as many times - sal_uInt32 refCount= it->second.first; - - for ( sal_uInt32 i=0; i < refCount; i++) - osl_unloadModule( it->first); - - // mark the module for later removal - unloadedModulesList.push_front( it->first); - } - } - } - - // remove all entries containing invalid (unloaded) modules - list_type::const_iterator un_it= unloadedModulesList.begin(); - for (; un_it != unloadedModulesList.end(); ++un_it) - { - moduleMap.erase( *un_it); - } -#endif -} - -#ifndef DISABLE_DYNLOADING - -// ============================================================================== -// Unloading Listener Administration -//=============================================================================== -struct hashListener -{ - size_t operator()( const sal_Int32& rkey) const - { - return (size_t)rkey; - } -}; - -typedef boost::unordered_map< - sal_Int32, - std::pair, - hashListener, - std::equal_to, - rtl::Allocator -> ListenerMap; - -typedef ListenerMap::iterator Lis_IT; - -static ListenerMap& getListenerMap() -{ - static ListenerMap * g_pListeners= NULL; - if (!g_pListeners) - { - MutexGuard guard( getUnloadingMutex() ); - if (!g_pListeners) - { - static ListenerMap g_aListenerMap; - g_pListeners= &g_aListenerMap; - } - } - return *g_pListeners; -} - - -// This queue contains cookies which have been passed out by rtl_addUnloadingListener and -// which have been regainded by rtl_removeUnloadingListener. When rtl_addUnloadingListener -// is called then a cookie has to be returned. First we look into the set if there is one -// available. Otherwise a new cookie will be provided. -// not a new value is returned. - -typedef std::deque< - sal_Int32, - rtl::Allocator -> queue_type; - -static queue_type& getCookieQueue() -{ - static queue_type * g_pCookies= NULL; - if (!g_pCookies) - { - MutexGuard guard( getUnloadingMutex() ); - if (!g_pCookies) - { - static queue_type g_aCookieQueue; - g_pCookies= &g_aCookieQueue; - } - } - return *g_pCookies; -} - -static sal_Int32 getCookie() -{ - static sal_Int32 cookieValue= 1; - - sal_Int32 retval; - queue_type& regainedCookies= getCookieQueue(); - if( regainedCookies.empty() ) - retval= cookieValue++; - else - { - retval= regainedCookies.front(); - regainedCookies.pop_front(); - } - return retval; -} - -static inline void recycleCookie( sal_Int32 i) -{ - getCookieQueue().push_back(i); -} - - -#endif - -// calling the function twice with the same arguments will return tow different cookies. -// The listener will then notified twice. - -extern "C" -sal_Int32 SAL_CALL rtl_addUnloadingListener( rtl_unloadingListenerFunc callback, void* _this) -{ -#ifdef DISABLE_DYNLOADING - (void) callback; - (void) _this; - return 0; -#else - MutexGuard guard( getUnloadingMutex()); - - sal_Int32 cookie= getCookie(); - ListenerMap& listenerMap= getListenerMap(); - listenerMap[ cookie]= std::make_pair( callback, _this); - return cookie; -#endif -} - - -extern "C" -void SAL_CALL rtl_removeUnloadingListener( sal_Int32 cookie ) -{ -#ifdef DISABLE_DYNLOADING - (void) cookie; -#else - MutexGuard guard( getUnloadingMutex()); - - ListenerMap& listenerMap= getListenerMap(); - size_t removedElements= listenerMap.erase( cookie); - if( removedElements ) - recycleCookie( cookie); -#endif -} - -#ifndef DISABLE_DYNLOADING - -static void rtl_notifyUnloadingListeners() -{ - ListenerMap& listenerMap= getListenerMap(); - for( Lis_IT it= listenerMap.begin(); it != listenerMap.end(); ++it) - { - rtl_unloadingListenerFunc callbackFunc= it->second.first; - callbackFunc( it->second.second); - } -} - -#endif - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3