1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sal.hxx"
30 #include <rtl/unload.h>
31 #include <rtl/alloc.h>
32 #include <rtl/ustring.hxx>
33 #include <osl/mutex.hxx>
35 #include "rtl/allocator.hxx"
41 using osl::MutexGuard
;
43 //----------------------------------------------------------------------------
45 static void rtl_notifyUnloadingListeners();
47 static sal_Bool
isEqualTimeValue ( const TimeValue
* time1
, const TimeValue
* time2
)
49 if( time1
->Seconds
== time2
->Seconds
&&
50 time1
->Nanosec
== time2
->Nanosec
)
56 static sal_Bool
isGreaterTimeValue( const TimeValue
* time1
, const TimeValue
* time2
)
58 sal_Bool retval
= sal_False
;
59 if ( time1
->Seconds
> time2
->Seconds
)
61 else if ( time1
->Seconds
== time2
->Seconds
)
63 if( time1
->Nanosec
> time2
->Nanosec
)
69 static sal_Bool
isGreaterEqualTimeValue( const TimeValue
* time1
, const TimeValue
* time2
)
71 if( isEqualTimeValue( time1
, time2
) )
73 else if( isGreaterTimeValue( time1
, time2
))
79 static void addTimeValue( const TimeValue
* value1
, const TimeValue
* value2
, TimeValue
* result
)
85 sum
= value1
->Nanosec
+ value2
->Nanosec
;
86 if( sum
>= 1000000000 )
91 result
->Nanosec
= (sal_uInt32
)sum
;
92 result
->Seconds
+= value1
->Seconds
+ value2
->Seconds
;
96 static sal_Bool
hasEnoughTimePassed( const TimeValue
* unusedSince
, const TimeValue
* timespan
)
98 sal_Bool retval
= sal_False
;
99 TimeValue currentTime
;
100 if( osl_getSystemTime( ¤tTime
))
103 addTimeValue( unusedSince
, timespan
, &addedTime
);
104 if( isGreaterEqualTimeValue( ¤tTime
, &addedTime
))
111 static osl::Mutex
* getUnloadingMutex()
113 static osl::Mutex
* g_pMutex
= NULL
;
116 MutexGuard
guard( osl::Mutex::getGlobalMutex() );
119 static osl::Mutex g_aMutex
;
126 extern "C" void rtl_moduleCount_acquire(rtl_ModuleCount
* that
)
128 rtl_StandardModuleCount
* pMod
= (rtl_StandardModuleCount
*)that
;
129 osl_incrementInterlockedCount( &pMod
->counter
);
132 extern "C" void rtl_moduleCount_release( rtl_ModuleCount
* that
)
134 rtl_StandardModuleCount
* pMod
= (rtl_StandardModuleCount
*)that
;
135 OSL_ENSURE( pMod
->counter
>0 , "library counter incorrect" );
136 osl_decrementInterlockedCount( &pMod
->counter
);
137 if( pMod
->counter
== 0)
139 MutexGuard
guard( getUnloadingMutex());
141 if( sal_False
== osl_getSystemTime( &pMod
->unusedSince
) )
143 // set the time to 0 if we could not get the time
144 pMod
->unusedSince
.Seconds
= 0;
145 pMod
->unusedSince
.Nanosec
= 0;
153 size_t operator()( const oslModule
& rkey
) const
159 typedef std::hash_map
<
161 std::pair
<sal_uInt32
, component_canUnloadFunc
>,
163 std::equal_to
<oslModule
>,
164 rtl::Allocator
<oslModule
>
167 typedef ModuleMap::iterator Mod_IT
;
169 static ModuleMap
& getModuleMap()
171 static ModuleMap
* g_pMap
= NULL
;
174 MutexGuard
guard( getUnloadingMutex() );
177 static ModuleMap g_aModuleMap
;
178 g_pMap
= &g_aModuleMap
;
184 extern "C" sal_Bool
rtl_moduleCount_canUnload( rtl_StandardModuleCount
* that
, TimeValue
* libUnused
)
186 if (that
->counter
== 0)
188 MutexGuard
guard( getUnloadingMutex());
189 if (libUnused
&& (that
->counter
== 0))
191 rtl_copyMemory(libUnused
, &that
->unusedSince
, sizeof(TimeValue
));
194 return (that
->counter
== 0);
198 extern "C" sal_Bool SAL_CALL
rtl_registerModuleForUnloading( oslModule module
)
200 MutexGuard
guard( getUnloadingMutex());
201 ModuleMap
& moduleMap
= getModuleMap();
202 sal_Bool ret
= sal_True
;
204 // If the module has been registered before, then find it and increment
205 // its reference cout
206 Mod_IT it
= moduleMap
.find( module
);
207 if( it
!= moduleMap
.end())
209 //module already registered, increment ref count
214 // Test if the module supports unloading (exports component_canUnload)
215 rtl::OUString
name(RTL_CONSTASCII_USTRINGPARAM( COMPONENT_CANUNLOAD
));
216 component_canUnloadFunc pFunc
=
217 (component_canUnloadFunc
)osl_getFunctionSymbol( module
, name
.pData
);
220 //register module for the first time, set ref count to 1
221 moduleMap
[module
]= std::make_pair((sal_uInt32
)1, pFunc
);
229 extern "C" void SAL_CALL
rtl_unregisterModuleForUnloading( oslModule module
)
231 MutexGuard
guard( getUnloadingMutex());
233 ModuleMap
& moduleMap
= getModuleMap();
234 Mod_IT it
= moduleMap
.find( module
);
235 if( it
!= moduleMap
.end() )
237 // The module is registered, decrement ref count.
240 // If the refcount == 0 then remove the module from the map
241 if( it
->second
.first
== 0)
242 moduleMap
.erase( it
);
246 extern "C" void SAL_CALL
rtl_unloadUnusedModules( TimeValue
* libUnused
)
248 MutexGuard
guard( getUnloadingMutex());
250 typedef std::list
< oslModule
, rtl::Allocator
<oslModule
> > list_type
;
251 list_type unloadedModulesList
;
253 ModuleMap
& moduleMap
= getModuleMap();
254 Mod_IT it_e
= moduleMap
.end();
256 // notify all listeners
257 rtl_notifyUnloadingListeners();
259 // prepare default TimeValue if argumetn is NULL
260 TimeValue nullTime
={0,0};
261 TimeValue
* pLibUnused
= libUnused
? libUnused
: &nullTime
;
263 Mod_IT it
= moduleMap
.begin();
264 for (; it
!= it_e
; ++it
)
266 //can the module be unloaded?
267 component_canUnloadFunc func
= it
->second
.second
;
268 TimeValue unusedSince
= {0, 0};
270 if( func( &unusedSince
) )
272 // module can be unloaded if it has not been used at least for the time
273 // specified by the argument libUnused
274 if( hasEnoughTimePassed( &unusedSince
, pLibUnused
))
276 // get the reference count and unload the module as many times
277 sal_uInt32 refCount
= it
->second
.first
;
279 for ( sal_uInt32 i
=0; i
< refCount
; i
++)
280 osl_unloadModule( it
->first
);
282 // mark the module for later removal
283 unloadedModulesList
.push_front( it
->first
);
288 // remove all entries containing invalid (unloaded) modules
289 list_type::const_iterator un_it
= unloadedModulesList
.begin();
290 for (; un_it
!= unloadedModulesList
.end(); ++un_it
)
292 moduleMap
.erase( *un_it
);
297 // ==============================================================================
298 // Unloading Listener Administration
299 //===============================================================================
302 size_t operator()( const sal_Int32
& rkey
) const
308 typedef std::hash_map
<
310 std::pair
<rtl_unloadingListenerFunc
, void*>,
312 std::equal_to
<sal_Int32
>,
313 rtl::Allocator
<sal_Int32
>
316 typedef ListenerMap::iterator Lis_IT
;
318 static ListenerMap
& getListenerMap()
320 static ListenerMap
* g_pListeners
= NULL
;
323 MutexGuard
guard( getUnloadingMutex() );
326 static ListenerMap g_aListenerMap
;
327 g_pListeners
= &g_aListenerMap
;
330 return *g_pListeners
;
334 // This queue contains cookies which have been passed out by rtl_addUnloadingListener and
335 // which have been regainded by rtl_removeUnloadingListener. When rtl_addUnloadingListener
336 // is called then a cookie has to be returned. First we look into the set if there is one
337 // availabe. Otherwise a new cookie will be provided.
338 // not a new value is returned.
342 rtl::Allocator
<sal_Int32
>
345 static queue_type
& getCookieQueue()
347 static queue_type
* g_pCookies
= NULL
;
350 MutexGuard
guard( getUnloadingMutex() );
353 static queue_type g_aCookieQueue
;
354 g_pCookies
= &g_aCookieQueue
;
360 static sal_Int32
getCookie()
362 static sal_Int32 cookieValue
= 1;
365 queue_type
& regainedCookies
= getCookieQueue();
366 if( regainedCookies
.empty() )
367 retval
= cookieValue
++;
370 retval
= regainedCookies
.front();
371 regainedCookies
.pop_front();
376 static inline void recycleCookie( sal_Int32 i
)
378 getCookieQueue().push_back(i
);
382 // calling the function twice with the same arguments will return tow different cookies.
383 // The listener will then notified twice.
386 sal_Int32 SAL_CALL
rtl_addUnloadingListener( rtl_unloadingListenerFunc callback
, void* _this
)
388 MutexGuard
guard( getUnloadingMutex());
390 sal_Int32 cookie
= getCookie();
391 ListenerMap
& listenerMap
= getListenerMap();
392 listenerMap
[ cookie
]= std::make_pair( callback
, _this
);
398 void SAL_CALL
rtl_removeUnloadingListener( sal_Int32 cookie
)
400 MutexGuard
guard( getUnloadingMutex());
402 ListenerMap
& listenerMap
= getListenerMap();
403 size_t removedElements
= listenerMap
.erase( cookie
);
404 if( removedElements
)
405 recycleCookie( cookie
);
409 static void rtl_notifyUnloadingListeners()
411 ListenerMap
& listenerMap
= getListenerMap();
412 for( Lis_IT it
= listenerMap
.begin(); it
!= listenerMap
.end(); ++it
)
414 rtl_unloadingListenerFunc callbackFunc
= it
->second
.first
;
415 callbackFunc( it
->second
.second
);