1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: unload.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sal.hxx"
33 #include <rtl/unload.h>
34 #include <rtl/alloc.h>
35 #include <rtl/ustring.hxx>
36 #include <osl/mutex.hxx>
38 #include "rtl/allocator.hxx"
44 using osl::MutexGuard
;
46 //----------------------------------------------------------------------------
48 static void rtl_notifyUnloadingListeners();
50 static sal_Bool
isEqualTimeValue ( const TimeValue
* time1
, const TimeValue
* time2
)
52 if( time1
->Seconds
== time2
->Seconds
&&
53 time1
->Nanosec
== time2
->Nanosec
)
59 static sal_Bool
isGreaterTimeValue( const TimeValue
* time1
, const TimeValue
* time2
)
61 sal_Bool retval
= sal_False
;
62 if ( time1
->Seconds
> time2
->Seconds
)
64 else if ( time1
->Seconds
== time2
->Seconds
)
66 if( time1
->Nanosec
> time2
->Nanosec
)
72 static sal_Bool
isGreaterEqualTimeValue( const TimeValue
* time1
, const TimeValue
* time2
)
74 if( isEqualTimeValue( time1
, time2
) )
76 else if( isGreaterTimeValue( time1
, time2
))
82 static void addTimeValue( const TimeValue
* value1
, const TimeValue
* value2
, TimeValue
* result
)
88 sum
= value1
->Nanosec
+ value2
->Nanosec
;
89 if( sum
>= 1000000000 )
94 result
->Nanosec
= (sal_uInt32
)sum
;
95 result
->Seconds
+= value1
->Seconds
+ value2
->Seconds
;
99 static sal_Bool
hasEnoughTimePassed( const TimeValue
* unusedSince
, const TimeValue
* timespan
)
101 sal_Bool retval
= sal_False
;
102 TimeValue currentTime
;
103 if( osl_getSystemTime( ¤tTime
))
106 addTimeValue( unusedSince
, timespan
, &addedTime
);
107 if( isGreaterEqualTimeValue( ¤tTime
, &addedTime
))
114 static osl::Mutex
* getUnloadingMutex()
116 static osl::Mutex
* g_pMutex
= NULL
;
119 MutexGuard
guard( osl::Mutex::getGlobalMutex() );
122 static osl::Mutex g_aMutex
;
129 extern "C" void rtl_moduleCount_acquire(rtl_ModuleCount
* that
)
131 rtl_StandardModuleCount
* pMod
= (rtl_StandardModuleCount
*)that
;
132 osl_incrementInterlockedCount( &pMod
->counter
);
135 extern "C" void rtl_moduleCount_release( rtl_ModuleCount
* that
)
137 rtl_StandardModuleCount
* pMod
= (rtl_StandardModuleCount
*)that
;
138 OSL_ENSURE( pMod
->counter
>0 , "library counter incorrect" );
139 osl_decrementInterlockedCount( &pMod
->counter
);
140 if( pMod
->counter
== 0)
142 MutexGuard
guard( getUnloadingMutex());
144 if( sal_False
== osl_getSystemTime( &pMod
->unusedSince
) )
146 // set the time to 0 if we could not get the time
147 pMod
->unusedSince
.Seconds
= 0;
148 pMod
->unusedSince
.Nanosec
= 0;
156 size_t operator()( const oslModule
& rkey
) const
162 typedef std::hash_map
<
164 std::pair
<sal_uInt32
, component_canUnloadFunc
>,
166 std::equal_to
<oslModule
>,
167 rtl::Allocator
<oslModule
>
170 typedef ModuleMap::iterator Mod_IT
;
172 static ModuleMap
& getModuleMap()
174 static ModuleMap
* g_pMap
= NULL
;
177 MutexGuard
guard( getUnloadingMutex() );
180 static ModuleMap g_aModuleMap
;
181 g_pMap
= &g_aModuleMap
;
187 extern "C" sal_Bool
rtl_moduleCount_canUnload( rtl_StandardModuleCount
* that
, TimeValue
* libUnused
)
189 if (that
->counter
== 0)
191 MutexGuard
guard( getUnloadingMutex());
192 if (libUnused
&& (that
->counter
== 0))
194 rtl_copyMemory(libUnused
, &that
->unusedSince
, sizeof(TimeValue
));
197 return (that
->counter
== 0);
201 extern "C" sal_Bool SAL_CALL
rtl_registerModuleForUnloading( oslModule module
)
203 MutexGuard
guard( getUnloadingMutex());
204 ModuleMap
& moduleMap
= getModuleMap();
205 sal_Bool ret
= sal_True
;
207 // If the module has been registered before, then find it and increment
208 // its reference cout
209 Mod_IT it
= moduleMap
.find( module
);
210 if( it
!= moduleMap
.end())
212 //module already registered, increment ref count
217 // Test if the module supports unloading (exports component_canUnload)
218 rtl::OUString
name(RTL_CONSTASCII_USTRINGPARAM( COMPONENT_CANUNLOAD
));
219 component_canUnloadFunc pFunc
=
220 (component_canUnloadFunc
)osl_getFunctionSymbol( module
, name
.pData
);
223 //register module for the first time, set ref count to 1
224 moduleMap
[module
]= std::make_pair((sal_uInt32
)1, pFunc
);
232 extern "C" void SAL_CALL
rtl_unregisterModuleForUnloading( oslModule module
)
234 MutexGuard
guard( getUnloadingMutex());
236 ModuleMap
& moduleMap
= getModuleMap();
237 Mod_IT it
= moduleMap
.find( module
);
238 if( it
!= moduleMap
.end() )
240 // The module is registered, decrement ref count.
243 // If the refcount == 0 then remove the module from the map
244 if( it
->second
.first
== 0)
245 moduleMap
.erase( it
);
249 extern "C" void SAL_CALL
rtl_unloadUnusedModules( TimeValue
* libUnused
)
251 MutexGuard
guard( getUnloadingMutex());
253 typedef std::list
< oslModule
, rtl::Allocator
<oslModule
> > list_type
;
254 list_type unloadedModulesList
;
256 ModuleMap
& moduleMap
= getModuleMap();
257 Mod_IT it_e
= moduleMap
.end();
259 // notify all listeners
260 rtl_notifyUnloadingListeners();
262 // prepare default TimeValue if argumetn is NULL
263 TimeValue nullTime
={0,0};
264 TimeValue
* pLibUnused
= libUnused
? libUnused
: &nullTime
;
266 Mod_IT it
= moduleMap
.begin();
267 for (; it
!= it_e
; ++it
)
269 //can the module be unloaded?
270 component_canUnloadFunc func
= it
->second
.second
;
271 TimeValue unusedSince
= {0, 0};
273 if( func( &unusedSince
) )
275 // module can be unloaded if it has not been used at least for the time
276 // specified by the argument libUnused
277 if( hasEnoughTimePassed( &unusedSince
, pLibUnused
))
279 // get the reference count and unload the module as many times
280 sal_uInt32 refCount
= it
->second
.first
;
282 for ( sal_uInt32 i
=0; i
< refCount
; i
++)
283 osl_unloadModule( it
->first
);
285 // mark the module for later removal
286 unloadedModulesList
.push_front( it
->first
);
291 // remove all entries containing invalid (unloaded) modules
292 list_type::const_iterator un_it
= unloadedModulesList
.begin();
293 for (; un_it
!= unloadedModulesList
.end(); ++un_it
)
295 moduleMap
.erase( *un_it
);
300 // ==============================================================================
301 // Unloading Listener Administration
302 //===============================================================================
305 size_t operator()( const sal_Int32
& rkey
) const
311 typedef std::hash_map
<
313 std::pair
<rtl_unloadingListenerFunc
, void*>,
315 std::equal_to
<sal_Int32
>,
316 rtl::Allocator
<sal_Int32
>
319 typedef ListenerMap::iterator Lis_IT
;
321 static ListenerMap
& getListenerMap()
323 static ListenerMap
* g_pListeners
= NULL
;
326 MutexGuard
guard( getUnloadingMutex() );
329 static ListenerMap g_aListenerMap
;
330 g_pListeners
= &g_aListenerMap
;
333 return *g_pListeners
;
337 // This queue contains cookies which have been passed out by rtl_addUnloadingListener and
338 // which have been regainded by rtl_removeUnloadingListener. When rtl_addUnloadingListener
339 // is called then a cookie has to be returned. First we look into the set if there is one
340 // availabe. Otherwise a new cookie will be provided.
341 // not a new value is returned.
345 rtl::Allocator
<sal_Int32
>
348 static queue_type
& getCookieQueue()
350 static queue_type
* g_pCookies
= NULL
;
353 MutexGuard
guard( getUnloadingMutex() );
356 static queue_type g_aCookieQueue
;
357 g_pCookies
= &g_aCookieQueue
;
363 static sal_Int32
getCookie()
365 static sal_Int32 cookieValue
= 1;
368 queue_type
& regainedCookies
= getCookieQueue();
369 if( regainedCookies
.empty() )
370 retval
= cookieValue
++;
373 retval
= regainedCookies
.front();
374 regainedCookies
.pop_front();
379 static inline void recycleCookie( sal_Int32 i
)
381 getCookieQueue().push_back(i
);
385 // calling the function twice with the same arguments will return tow different cookies.
386 // The listener will then notified twice.
389 sal_Int32 SAL_CALL
rtl_addUnloadingListener( rtl_unloadingListenerFunc callback
, void* _this
)
391 MutexGuard
guard( getUnloadingMutex());
393 sal_Int32 cookie
= getCookie();
394 ListenerMap
& listenerMap
= getListenerMap();
395 listenerMap
[ cookie
]= std::make_pair( callback
, _this
);
401 void SAL_CALL
rtl_removeUnloadingListener( sal_Int32 cookie
)
403 MutexGuard
guard( getUnloadingMutex());
405 ListenerMap
& listenerMap
= getListenerMap();
406 size_t removedElements
= listenerMap
.erase( cookie
);
407 if( removedElements
)
408 recycleCookie( cookie
);
412 static void rtl_notifyUnloadingListeners()
414 ListenerMap
& listenerMap
= getListenerMap();
415 for( Lis_IT it
= listenerMap
.begin(); it
!= listenerMap
.end(); ++it
)
417 rtl_unloadingListenerFunc callbackFunc
= it
->second
.first
;
418 callbackFunc( it
->second
.second
);