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