LCOV - code coverage report
Current view: top level - libreoffice/sal/rtl/source - unload.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 78 161 48.4 %
Date: 2012-12-17 Functions: 13 22 59.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <string.h>
      21             : 
      22             : #include <rtl/unload.h>
      23             : #include <rtl/alloc.h>
      24             : #include <rtl/ustring.hxx>
      25             : #include <rtl/instance.hxx>
      26             : #include <osl/mutex.hxx>
      27             : #include <boost/unordered_map.hpp>
      28             : #include "rtl/allocator.hxx"
      29             : 
      30             : #include <functional>
      31             : #include <list>
      32             : #include <deque>
      33             : 
      34             : using osl::MutexGuard;
      35             : 
      36             : //----------------------------------------------------------------------------
      37             : 
      38             : #ifndef DISABLE_DYNLOADING
      39             : 
      40             : static void rtl_notifyUnloadingListeners();
      41             : 
      42           0 : static sal_Bool isEqualTimeValue ( const TimeValue* time1,  const TimeValue* time2)
      43             : {
      44           0 :     if( time1->Seconds == time2->Seconds &&
      45             :         time1->Nanosec == time2->Nanosec)
      46           0 :         return sal_True;
      47             :     else
      48           0 :         return sal_False;
      49             : }
      50             : 
      51           0 : static sal_Bool isGreaterTimeValue(  const TimeValue* time1,  const TimeValue* time2)
      52             : {
      53           0 :     sal_Bool retval= sal_False;
      54           0 :     if ( time1->Seconds > time2->Seconds)
      55           0 :         retval= sal_True;
      56           0 :     else if ( time1->Seconds == time2->Seconds)
      57             :     {
      58           0 :         if( time1->Nanosec > time2->Nanosec)
      59           0 :             retval= sal_True;
      60             :     }
      61           0 :     return retval;
      62             : }
      63             : 
      64           0 : static sal_Bool isGreaterEqualTimeValue( const TimeValue* time1, const TimeValue* time2)
      65             : {
      66           0 :     if( isEqualTimeValue( time1, time2) )
      67           0 :         return sal_True;
      68           0 :     else if( isGreaterTimeValue( time1, time2))
      69           0 :         return sal_True;
      70             :     else
      71           0 :         return sal_False;
      72             : }
      73             : 
      74           0 : static void addTimeValue( const TimeValue* value1, const TimeValue* value2, TimeValue* result)
      75             : {
      76             :     sal_uInt64 sum;
      77           0 :     result->Nanosec=0;
      78           0 :     result->Seconds=0;
      79             : 
      80           0 :     sum= value1->Nanosec + value2->Nanosec;
      81           0 :     if( sum >= 1000000000 )
      82             :     {
      83           0 :         result->Seconds=1;
      84           0 :         sum -= 1000000000;
      85             :     }
      86           0 :     result->Nanosec= (sal_uInt32)sum;
      87           0 :     result->Seconds += value1->Seconds + value2->Seconds;
      88           0 : }
      89             : 
      90             : 
      91           0 : static sal_Bool hasEnoughTimePassed( const TimeValue* unusedSince, const TimeValue* timespan)
      92             : {
      93           0 :     sal_Bool retval= sal_False;
      94             :     TimeValue currentTime;
      95           0 :     if( osl_getSystemTime( &currentTime))
      96             :     {
      97             :         TimeValue addedTime;
      98           0 :         addTimeValue( unusedSince, timespan, &addedTime);
      99           0 :         if( isGreaterEqualTimeValue( &currentTime, &addedTime))
     100           0 :             retval= sal_True;
     101             :     }
     102             : 
     103           0 :     return retval;
     104             : }
     105             : 
     106             : namespace
     107             : {
     108             :     class theUnloadingMutex : public rtl::Static<osl::Mutex, theUnloadingMutex>{};
     109             : }
     110             : 
     111       17442 : static osl::Mutex& getUnloadingMutex()
     112             : {
     113       17442 :     return theUnloadingMutex::get();
     114             : }
     115             : 
     116             : #endif
     117             : 
     118       96746 : extern "C" void rtl_moduleCount_acquire(rtl_ModuleCount * that )
     119             : {
     120             : #ifdef DISABLE_DYNLOADING
     121             :     (void) that;
     122             : #else
     123       96746 :     rtl_StandardModuleCount* pMod= (rtl_StandardModuleCount*)that;
     124       96746 :     osl_atomic_increment( &pMod->counter);
     125             : #endif
     126       96746 : }
     127             : 
     128       95118 : extern "C" void rtl_moduleCount_release( rtl_ModuleCount * that )
     129             : {
     130             : #ifdef DISABLE_DYNLOADING
     131             :     (void) that;
     132             : #else
     133       95118 :     rtl_StandardModuleCount* pMod= (rtl_StandardModuleCount*)that;
     134             :     OSL_ENSURE( pMod->counter >0 , "library counter incorrect" );
     135       95118 :     osl_atomic_decrement( &pMod->counter);
     136       95118 :     if( pMod->counter == 0)
     137             :     {
     138        2055 :         MutexGuard guard( getUnloadingMutex());
     139             : 
     140        2055 :         if( sal_False == osl_getSystemTime( &pMod->unusedSince) )
     141             :         {
     142             :             // set the time to 0 if we could not get the time
     143           0 :             pMod->unusedSince.Seconds= 0;
     144           0 :             pMod->unusedSince.Nanosec= 0;
     145        2055 :         }
     146             :     }
     147             : #endif
     148       95118 : }
     149             : 
     150             : #ifndef DISABLE_DYNLOADING
     151             : 
     152             : struct hashModule
     153             : {
     154       15065 :     size_t operator()( const oslModule& rkey) const
     155             :     {
     156       15065 :         return (size_t)rkey;
     157             :     }
     158             : };
     159             : 
     160             : typedef boost::unordered_map<
     161             :     oslModule,
     162             :     std::pair<sal_uInt32, component_canUnloadFunc>,
     163             :     hashModule,
     164             :     std::equal_to<oslModule>,
     165             :     rtl::Allocator<oslModule>
     166             : > ModuleMap;
     167             : 
     168             : typedef ModuleMap::iterator Mod_IT;
     169             : 
     170       14801 : static ModuleMap& getModuleMap()
     171             : {
     172             :     static ModuleMap * g_pMap= NULL;
     173       14801 :     if (!g_pMap)
     174             :     {
     175         114 :         MutexGuard guard( getUnloadingMutex() );
     176         114 :         if (!g_pMap)
     177             :         {
     178         114 :             static ModuleMap g_aModuleMap;
     179         114 :             g_pMap= &g_aModuleMap;
     180         114 :         }
     181             :     }
     182       14801 :     return *g_pMap;
     183             : }
     184             : 
     185             : #endif
     186             : 
     187           0 : extern "C" sal_Bool rtl_moduleCount_canUnload( rtl_StandardModuleCount * that, TimeValue * libUnused)
     188             : {
     189             : #ifdef DISABLE_DYNLOADING
     190             :     (void) that;
     191             :     (void) libUnused;
     192             :     return sal_False;
     193             : #else
     194           0 :     if (that->counter == 0)
     195             :     {
     196           0 :         MutexGuard guard( getUnloadingMutex());
     197           0 :         if (libUnused && (that->counter == 0))
     198             :         {
     199           0 :             memcpy(libUnused, &that->unusedSince, sizeof(TimeValue));
     200           0 :         }
     201             :     }
     202           0 :     return (that->counter == 0);
     203             : #endif
     204             : }
     205             : 
     206             : 
     207       14801 : extern "C" sal_Bool SAL_CALL rtl_registerModuleForUnloading( oslModule module)
     208             : {
     209             : #ifdef DISABLE_DYNLOADING
     210             :     (void) module;
     211             :     return sal_False;
     212             : #else
     213       14801 :     MutexGuard guard( getUnloadingMutex());
     214       14801 :     ModuleMap& moduleMap= getModuleMap();
     215       14801 :     sal_Bool ret= sal_True;
     216             : 
     217             :     // If the module has been registered before, then find it and increment
     218             :     // its reference cout
     219       14801 :     Mod_IT it= moduleMap.find( module);
     220       14801 :     if( it != moduleMap.end())
     221             :     {
     222             :         //module already registered, increment ref count
     223        9938 :         it->second.first++;
     224             :     }
     225             :     else
     226             :     {
     227             :         // Test if the module supports unloading (exports component_canUnload)
     228        4863 :         rtl::OUString name(RTL_CONSTASCII_USTRINGPARAM( COMPONENT_CANUNLOAD));
     229             :         component_canUnloadFunc pFunc=
     230        4863 :             (component_canUnloadFunc)osl_getFunctionSymbol( module, name.pData);
     231        4863 :         if (pFunc)
     232             :         {
     233             :             //register module for the first time, set ref count to 1
     234         378 :             moduleMap[module]= std::make_pair((sal_uInt32)1, pFunc);
     235             :         }
     236             :         else
     237        4485 :             ret= sal_False;
     238             :     }
     239       14801 :     return ret;
     240             : #endif
     241             : }
     242             : 
     243           0 : extern "C" void SAL_CALL rtl_unregisterModuleForUnloading( oslModule module)
     244             : {
     245             : #ifdef DISABLE_DYNLOADING
     246             :     (void) module;
     247             : #else
     248           0 :     MutexGuard guard( getUnloadingMutex());
     249             : 
     250           0 :     ModuleMap& moduleMap= getModuleMap();
     251           0 :     Mod_IT it= moduleMap.find( module);
     252           0 :     if( it != moduleMap.end() )
     253             :     {
     254             :         // The module is registered, decrement ref count.
     255           0 :         it->second.first --;
     256             : 
     257             :         // If the refcount == 0 then remove the module from the map
     258           0 :         if( it->second.first == 0)
     259           0 :             moduleMap.erase( it);
     260           0 :     }
     261             : #endif
     262           0 : }
     263             : 
     264           0 : extern "C" void SAL_CALL rtl_unloadUnusedModules( TimeValue* libUnused)
     265             : {
     266             : #ifdef DISABLE_DYNLOADING
     267             :     (void) libUnused;
     268             : #else
     269           0 :     MutexGuard guard( getUnloadingMutex());
     270             : 
     271             :     typedef std::list< oslModule, rtl::Allocator<oslModule> > list_type;
     272           0 :     list_type unloadedModulesList;
     273             : 
     274           0 :     ModuleMap& moduleMap= getModuleMap();
     275           0 :     Mod_IT it_e= moduleMap.end();
     276             : 
     277             :     // notify all listeners
     278           0 :     rtl_notifyUnloadingListeners();
     279             : 
     280             :     // prepare default TimeValue if argumetn is NULL
     281           0 :     TimeValue nullTime={0,0};
     282           0 :     TimeValue* pLibUnused= libUnused? libUnused : &nullTime;
     283             : 
     284           0 :     Mod_IT it= moduleMap.begin();
     285           0 :     for (; it != it_e; ++it)
     286             :     {
     287             :         //can the module be unloaded?
     288           0 :         component_canUnloadFunc func= it->second.second;
     289           0 :         TimeValue unusedSince= {0, 0};
     290             : 
     291           0 :         if( func( &unusedSince) )
     292             :         {
     293             :             // module can be unloaded if it has not been used at least for the time
     294             :             // specified by the argument libUnused
     295           0 :             if( hasEnoughTimePassed( &unusedSince, pLibUnused))
     296             :             {
     297             :                 // get the reference count and unload the module as many times
     298           0 :                 sal_uInt32 refCount= it->second.first;
     299             : 
     300           0 :                 for ( sal_uInt32 i=0; i < refCount; i++)
     301           0 :                     osl_unloadModule( it->first);
     302             : 
     303             :                 // mark the module for later removal
     304           0 :                 unloadedModulesList.push_front( it->first);
     305             :             }
     306             :         }
     307             :     }
     308             : 
     309             :     // remove all entries containing invalid (unloaded) modules
     310           0 :     list_type::const_iterator un_it= unloadedModulesList.begin();
     311           0 :     for (; un_it != unloadedModulesList.end(); ++un_it)
     312             :     {
     313           0 :         moduleMap.erase( *un_it);
     314           0 :     }
     315             : #endif
     316           0 : }
     317             : 
     318             : #ifndef DISABLE_DYNLOADING
     319             : 
     320             : // ==============================================================================
     321             : // Unloading Listener Administration
     322             : //===============================================================================
     323             : struct hashListener
     324             : {
     325         244 :     size_t operator()( const sal_Int32& rkey) const
     326             :     {
     327         244 :         return (size_t)rkey;
     328             :     }
     329             : };
     330             : 
     331             : typedef boost::unordered_map<
     332             :     sal_Int32,
     333             :     std::pair<rtl_unloadingListenerFunc, void*>,
     334             :     hashListener,
     335             :     std::equal_to<sal_Int32>,
     336             :     rtl::Allocator<sal_Int32>
     337             : > ListenerMap;
     338             : 
     339             : typedef ListenerMap::iterator Lis_IT;
     340             : 
     341         244 : static ListenerMap& getListenerMap()
     342             : {
     343             :     static ListenerMap * g_pListeners= NULL;
     344         244 :     if (!g_pListeners)
     345             :     {
     346         114 :         MutexGuard guard( getUnloadingMutex() );
     347         114 :         if (!g_pListeners)
     348             :         {
     349         114 :             static ListenerMap g_aListenerMap;
     350         114 :             g_pListeners= &g_aListenerMap;
     351         114 :         }
     352             :     }
     353         244 :     return *g_pListeners;
     354             : }
     355             : 
     356             : 
     357             : // This queue contains cookies which have been passed out by rtl_addUnloadingListener and
     358             : // which have been regainded by rtl_removeUnloadingListener. When rtl_addUnloadingListener
     359             : // is called then a cookie has to be returned. First we look into the set if there is one
     360             : // availabe. Otherwise a new cookie will be provided.
     361             : // not a new value is returned.
     362             : 
     363             : typedef std::deque<
     364             :     sal_Int32,
     365             :     rtl::Allocator<sal_Int32>
     366             : > queue_type;
     367             : 
     368         244 : static queue_type& getCookieQueue()
     369             : {
     370             :     static queue_type * g_pCookies= NULL;
     371         244 :     if (!g_pCookies)
     372             :     {
     373         114 :         MutexGuard guard( getUnloadingMutex() );
     374         114 :         if (!g_pCookies)
     375             :         {
     376         114 :             static queue_type g_aCookieQueue;
     377         114 :             g_pCookies= &g_aCookieQueue;
     378         114 :         }
     379             :     }
     380         244 :     return *g_pCookies;
     381             : }
     382             : 
     383         122 : static sal_Int32 getCookie()
     384             : {
     385             :     static sal_Int32 cookieValue= 1;
     386             : 
     387             :     sal_Int32 retval;
     388         122 :     queue_type& regainedCookies= getCookieQueue();
     389         122 :     if( regainedCookies.empty() )
     390         114 :         retval= cookieValue++;
     391             :     else
     392             :     {
     393           8 :         retval= regainedCookies.front();
     394           8 :         regainedCookies.pop_front();
     395             :     }
     396         122 :     return retval;
     397             : }
     398             : 
     399         122 : static inline void recycleCookie( sal_Int32 i)
     400             : {
     401         122 :     getCookieQueue().push_back(i);
     402         122 : }
     403             : 
     404             : 
     405             : #endif
     406             : 
     407             : // calling the function twice with the same arguments will return tow different cookies.
     408             : // The listener will then notified twice.
     409             : 
     410             : extern "C"
     411         122 : sal_Int32 SAL_CALL rtl_addUnloadingListener( rtl_unloadingListenerFunc callback, void* _this)
     412             : {
     413             : #ifdef DISABLE_DYNLOADING
     414             :     (void) callback;
     415             :     (void) _this;
     416             :     return 0;
     417             : #else
     418         122 :     MutexGuard guard( getUnloadingMutex());
     419             : 
     420         122 :     sal_Int32 cookie= getCookie();
     421         122 :     ListenerMap& listenerMap= getListenerMap();
     422         122 :     listenerMap[ cookie]= std::make_pair( callback, _this);
     423         122 :     return cookie;
     424             : #endif
     425             : }
     426             : 
     427             : 
     428             : extern "C"
     429         122 : void SAL_CALL rtl_removeUnloadingListener( sal_Int32 cookie )
     430             : {
     431             : #ifdef DISABLE_DYNLOADING
     432             :     (void) cookie;
     433             : #else
     434         122 :     MutexGuard guard( getUnloadingMutex());
     435             : 
     436         122 :     ListenerMap& listenerMap= getListenerMap();
     437         122 :     size_t removedElements= listenerMap.erase( cookie);
     438         122 :     if( removedElements )
     439         122 :         recycleCookie( cookie);
     440             : #endif
     441         122 : }
     442             : 
     443             : #ifndef DISABLE_DYNLOADING
     444             : 
     445           0 : static void rtl_notifyUnloadingListeners()
     446             : {
     447           0 :     ListenerMap& listenerMap= getListenerMap();
     448           0 :     for( Lis_IT it= listenerMap.begin(); it != listenerMap.end(); ++it)
     449             :     {
     450           0 :         rtl_unloadingListenerFunc callbackFunc= it->second.first;
     451           0 :         callbackFunc( it->second.second);
     452             :     }
     453           0 : }
     454             : 
     455             : #endif
     456             : 
     457             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10