merge the formfield patch from ooo-build
[ooovba.git] / sal / rtl / source / unload.cxx
blob56f73293063fb1647ecdde162850a6e66fcc86d7
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: unload.cxx,v $
10 * $Revision: 1.12 $
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>
37 #include <hash_map>
38 #include "rtl/allocator.hxx"
40 #include <functional>
41 #include <list>
42 #include <deque>
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)
54 return sal_True;
55 else
56 return sal_False;
59 static sal_Bool isGreaterTimeValue( const TimeValue* time1, const TimeValue* time2)
61 sal_Bool retval= sal_False;
62 if ( time1->Seconds > time2->Seconds)
63 retval= sal_True;
64 else if ( time1->Seconds == time2->Seconds)
66 if( time1->Nanosec > time2->Nanosec)
67 retval= sal_True;
69 return retval;
72 static sal_Bool isGreaterEqualTimeValue( const TimeValue* time1, const TimeValue* time2)
74 if( isEqualTimeValue( time1, time2) )
75 return sal_True;
76 else if( isGreaterTimeValue( time1, time2))
77 return sal_True;
78 else
79 return sal_False;
82 static void addTimeValue( const TimeValue* value1, const TimeValue* value2, TimeValue* result)
84 sal_uInt64 sum;
85 result->Nanosec=0;
86 result->Seconds=0;
88 sum= value1->Nanosec + value2->Nanosec;
89 if( sum >= 1000000000 )
91 result->Seconds=1;
92 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( &currentTime))
105 TimeValue addedTime;
106 addTimeValue( unusedSince, timespan, &addedTime);
107 if( isGreaterEqualTimeValue( &currentTime, &addedTime))
108 retval= sal_True;
111 return retval;
114 static osl::Mutex* getUnloadingMutex()
116 static osl::Mutex * g_pMutex= NULL;
117 if (!g_pMutex)
119 MutexGuard guard( osl::Mutex::getGlobalMutex() );
120 if (!g_pMutex)
122 static osl::Mutex g_aMutex;
123 g_pMutex= &g_aMutex;
126 return g_pMutex;
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;
154 struct hashModule
156 size_t operator()( const oslModule& rkey) const
158 return (size_t)rkey;
162 typedef std::hash_map<
163 oslModule,
164 std::pair<sal_uInt32, component_canUnloadFunc>,
165 hashModule,
166 std::equal_to<oslModule>,
167 rtl::Allocator<oslModule>
168 > ModuleMap;
170 typedef ModuleMap::iterator Mod_IT;
172 static ModuleMap& getModuleMap()
174 static ModuleMap * g_pMap= NULL;
175 if (!g_pMap)
177 MutexGuard guard( getUnloadingMutex() );
178 if (!g_pMap)
180 static ModuleMap g_aModuleMap;
181 g_pMap= &g_aModuleMap;
184 return *g_pMap;
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
213 it->second.first++;
215 else
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);
221 if (pFunc)
223 //register module for the first time, set ref count to 1
224 moduleMap[module]= std::make_pair((sal_uInt32)1, pFunc);
226 else
227 ret= sal_False;
229 return ret;
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.
241 it->second.first --;
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 //===============================================================================
303 struct hashListener
305 size_t operator()( const sal_Int32& rkey) const
307 return (size_t)rkey;
311 typedef std::hash_map<
312 sal_Int32,
313 std::pair<rtl_unloadingListenerFunc, void*>,
314 hashListener,
315 std::equal_to<sal_Int32>,
316 rtl::Allocator<sal_Int32>
317 > ListenerMap;
319 typedef ListenerMap::iterator Lis_IT;
321 static ListenerMap& getListenerMap()
323 static ListenerMap * g_pListeners= NULL;
324 if (!g_pListeners)
326 MutexGuard guard( getUnloadingMutex() );
327 if (!g_pListeners)
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.
343 typedef std::deque<
344 sal_Int32,
345 rtl::Allocator<sal_Int32>
346 > queue_type;
348 static queue_type& getCookieQueue()
350 static queue_type * g_pCookies= NULL;
351 if (!g_pCookies)
353 MutexGuard guard( getUnloadingMutex() );
354 if (!g_pCookies)
356 static queue_type g_aCookieQueue;
357 g_pCookies= &g_aCookieQueue;
360 return *g_pCookies;
363 static sal_Int32 getCookie()
365 static sal_Int32 cookieValue= 1;
367 sal_Int32 retval;
368 queue_type& regainedCookies= getCookieQueue();
369 if( regainedCookies.empty() )
370 retval= cookieValue++;
371 else
373 retval= regainedCookies.front();
374 regainedCookies.pop_front();
376 return retval;
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.
388 extern "C"
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);
396 return cookie;
400 extern "C"
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);