1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 #ifndef _RTL_UNLOAD_H_ 24 #define _RTL_UNLOAD_H_ 25 26 #include <sal/types.h> 27 #include <osl/time.h> 28 #include <osl/interlck.h> 29 #include <osl/module.h> 30 31 ///@HTML 32 /** @file 33 The API enables an effective way of unloading libraries in a centralized way. 34 The mechanism ensures that used libraries are not unloaded. This prevents 35 crashes if library code is being used after unloading the library. 36 The unloading mechanism currently only works with libraries which contain 37 UNO services. A library cannot be unloaded if one of the following conditions 38 apply 39 40 <ul> 41 <li>An instance is still referenced </li> 42 <li>A module has been loaded without registering it </li> 43 <li>The service manager has created a one instance service </li> 44 <li>A service instance has been added to an UNO context </li> 45 </ul> 46 47 <b>Notification Mechanism</b> 48 The API provides a notification mechanism. Clients can use it to do clean up, 49 such as releasing cached references, in order to allow modules to be unloaded. 50 As long as someone holds a reference to an object whose housing module 51 supports unloading the module cannot be unloaded.<p> 52 53 Because of the inherent danger of crashing the application by using this API 54 all instances which control threads should be registered listeners. On 55 notification they have to ensure that their threads assume a safe state, that 56 is, they run outside of modules which could be unloaded and do not jump 57 back into module code as a result of a finished function call. In other words, 58 there must not be an address of the module on the thread's stack. 59 <p> 60 Since current operating systems lack APIs in respect to controlling the 61 position of threads within libraries, it would be a major effort to comply with 62 that recommendation. The best and most efficient way of handling the unloading 63 scenario is to let all threads, except for the main thread, die in case of a 64 notification. 65 <p> 66 Use this API with great care because it might crash the application. See the 67 respective documentation (Library Unloading) on the udk.openoffice.org web site. 68 */ 69 70 71 /** 72 A library which supports unloading has to implement and export a function 73 called <code>component_canUnload</code>. <p> 74 If the function returns <code>sal_True</code> then the module can be safely unloaded. 75 That is the case when there are no external references to code within the 76 library. In case a module houses UNO components then the function must return 77 <code>sal_False</code> after the first factory has been handed out. The function then 78 continues to return <code>sal_False</code> as long as there is at least one object (factory 79 or service instance) which originated from the module.<p> 80 81 Libraries which not only contain UNO components (or none at all) have to 82 provide a means to control whether they can be unloaded or not, e.g. However, 83 there is no concept yet. <p> 84 85 The argument <code>pTime</code> is an optional out-parameter. If the return value is 86 <code>sal_True</code> then <code>pTime</code> reflects a point in time since 87 when the module could have 88 been unloaded. Since that time the function would have continually returned 89 <code>sal_True</code> up to the present. The value of <code>pTime</code> is 90 important for the decision 91 as to a module will be unloaded. When someone initiates the unloading of 92 modules by calling <code>rtl_unloadUnusedModules</code> then the caller can specify a time 93 span with the effect that only those modules are unloaded which are unused at 94 least for that amount of time. If <code>component_canUnload</code> does not 95 fill in <code>pTime</code> 96 then the module is unloaded immediately.<p> 97 98 <code>component_canUnload</code> is implicitly called by <code>rtl_unloadUnusedModules 99 </code>. There is no need to call the function directly. 100 */ 101 #define COMPONENT_CANUNLOAD "component_canUnload" 102 typedef sal_Bool (SAL_CALL * component_canUnloadFunc)( TimeValue* pTime); 103 104 105 /** C-interface for a module reference counting 106 */ 107 #ifdef __cplusplus 108 extern "C" 109 { 110 #endif 111 112 /** 113 By registering a module, one declares that a module supports the 114 unloading mechanism. One registers a module by calling this function.<p> 115 116 A module can only be unloaded from memory when it has been registered 117 as many times as it has been loaded. The reason is that a library can 118 be "loaded" several times by <code>osl_loadModule</code> 119 within the same process. The 120 function will then return the same module handle because the library will 121 effectively only be loaded once. To remove the library from memory it is 122 necessary to call <code>osl_unloadModule</code> as often as <code> 123 osl_loadModule</code> was called. The 124 function <code>rtl_unloadUnusedModules</code> calls <code>osl_unloadModule</code> 125 for a module as many 126 times as it was registered. If, for example, a module has been registered one 127 time less then <code>osl_loadModule</code> has been called and the module can be unloaded 128 then it needs a call to <code>rtl_unloadUnusedModules</code> and an explicit call to 129 <code>osl_unloadModule</code> to remove the module from memory. <p> 130 131 A module must be registered every time it has been loaded otherwise the 132 unloading mechanism is not effective.<p> 133 134 Before a module is registered, one has to make sure that the module is in a 135 state that prevents it from being unloaded. In other words, 136 <code>component_canUnload</code> must return <code>sal_False</code>. Assuming that 137 <code>component_canUnload</code> 138 returns <code>sal_True</code> and it is registered regardless, then a call to 139 <code>rtl_unloadUnusedModules</code> causes the module to be unloaded. This unloading can 140 be set off by a different thread and the thread which registered the module is 141 "unaware" of this. Then when the first thread tries to obtain a factory or 142 calls another function in the module, the application will crash, because the 143 module has been unloaded before. Therefore one has to ensure that the module 144 cannot be unloaded before it is registered. This is simply done by obtaining a 145 factory from the module. As long as a factory or some other object, which has 146 been created by the factory, is alive, the <code>component_canUnload</code> function will 147 return <code>sal_False</code>.<p> 148 Loading and registering have to be in this order:<br> 149 <ul> 150 <li>load a library (<code>osl_loadModule</code>)</li> 151 <li>get the <code>component_getFactory</code> function and get a factory</li> 152 <li>register the module (rtl_registerModuleForUnloading</li> 153 </ul> 154 Usually the service manager is used to obtain an instance of a service. 155 The service manager registers all modules which support the unloading mechanism. 156 When the service manager is used to get service instances than one does not 157 have to bother about registering. 158 159 @param module a module handle as is obtained by osl_loadModule 160 @return sal_True - the module could be registered for unloading, sal_False otherwise 161 */ 162 sal_Bool SAL_CALL rtl_registerModuleForUnloading( oslModule module); 163 164 /** 165 The function revokes the registration of a module. By calling the function for 166 a previously registered module one prevents the module from being unloaded by 167 this unloading mechanism. However, in order to completely unregister the module 168 it is necessary to call the function as often as the module has been registered. 169 <p> 170 <code>rtl_unloadUnusedModules</code> unregisters the modules which it unloads. Therefore 171 there is no need to call this function unless one means to prevent the unloading of a module. 172 173 @param module a module handle as is obtained by osl_loadModule 174 */ 175 void SAL_CALL rtl_unregisterModuleForUnloading( oslModule module); 176 /** 177 This function sets off the unloading mechanism. At first it notifies the 178 unloading listeners in order to give them a chance to do cleanup and get 179 their threads in a safe state. Then all registered modules are asked if they 180 can be unloaded. That is, the function calls component_canUnload on every 181 registered module. If <code>sal_True</code> is returned then <code>osl_unloadModule</code> 182 is called for the belonging module as often as it is registered. 183 <p> 184 A call to <code>osl_unloadModule</code> does not guarantee that the module is unloaded even 185 if its <code>component_canUnload</code> function returns <code>sal_True</code>. 186 <p> 187 The optional in-parameter <code>libUnused</code> specifies a period of time which a library 188 must be unused in order to qualify for being unloaded. By using this argument 189 one can counter the multithreading problem as described further above. It is in 190 the responsibility of the user of this function to provide a timespan big enough 191 to ensure that all threads are out of modules (see <code>component_canUnload</code>). 192 <p> 193 The service managers which have been created by functions such as 194 <code>createRegistryServiceFactory</code> (declared in cppuhelper/servicefactory.hxx) are 195 registered listeners and release the references to factories on notification. 196 197 198 @param libUnused span of time that a module must be unused to be unloaded. the 199 argument is optional. 200 */ 201 void SAL_CALL rtl_unloadUnusedModules( TimeValue* libUnused); 202 203 /** 204 rtl_addUnloadingListener takes an argument of this type. 205 206 @param id - The value that has been passed as second argument to rtl_addUnloadingListener 207 */ 208 typedef void (SAL_CALL *rtl_unloadingListenerFunc)(void* id); 209 /** 210 The function registered an unloading listener. The callback argument is a 211 function which is called when the unloading procedure has been initiated by a call to 212 <code>rtl_unloadUnusedLibraries</code>. The second argument is used to distinguish between different 213 listener instances and may be <code>NULL</code>. It will be passed as argument when the callback 214 function is being called. The return value identifies the registered listener and will 215 be used for removing the listener later on. If the same listener is added more then 216 once then every registration is treated as if made for a different listener. That is, 217 a different cookie is returned and the callback function will be called as many times 218 as it has been registered. 219 @param callback - a function that is called to notify listeners. 220 @param this - a value to distinguish different listener instances 221 @return identifier which is used in rtl_removeUnloadingListener 222 */ 223 sal_Int32 SAL_CALL rtl_addUnloadingListener( rtl_unloadingListenerFunc callback, void* _this); 224 225 /** 226 Listeners (the callback functions) must be unregistered before the listener code 227 becomes invalid. That is, if a module contains listener code, namely callback 228 functions of type <code>rtl_unloadingListenerFunc</code>, then those functions must not be 229 registered when <code>component_canUnload</code> returns <code>sal_True</code>. 230 231 @param cookie is an identifier as returned by <code>rtl_addUnloadingListener</code> function. 232 */ 233 void SAL_CALL rtl_removeUnloadingListener( sal_Int32 cookie ); 234 235 236 /** 237 Pointers to <code>rtl_ModuleCount</code> are passed as arguments to the default factory creator 238 functions: <code>createSingleComponentFactory</code>, <code>createSingleFactory</code>, 239 <code>createOneInstanceFactory</code>. 240 The factory implementation is calling <code>rtl_ModuleCount.acquire</code> when it is being 241 constructed and it is calling <code>rtl_ModuleCount.release</code>. The implementations of 242 <code>acquire</code> 243 and <code>release</code> should influence the return value of <code>component_canUnload</code> 244 in a way that it 245 returns <code>sal_False</code> after <code>acquire</code> has been called. That is the module will not be unloaded 246 once a default factory has been created. A call to <code>release</code> may cause 247 <code>component_canUnload</code> to return <code>sal_False</code>, but only if there are 248 no object alive which 249 originated from the module. These objects are factory instances and the service instances 250 which have been created by these factories. 251 <p> 252 It is not necessary to synchronize <code>acquire</code> and <code>release</code> as a whole. 253 Simply sychronize the 254 access to a counter variable, e.g. the <code>rtl_moduleCount_release</code> implementation: 255 <pre> 256 extern "C" void rtl_moduleCount_acquire(rtl_ModuleCount * that ) 257 { 258 rtl_StandardModuleCount* pMod= (rtl_StandardModuleCount*)that; 259 osl_incrementInterlockedCount( &pMod->counter); 260 } 261 </pre> 262 The SAL library offers functions that can be used for <code>acquire</code> and <code>release</code>. See struct 263 <code>_rtl_StandardModuleCount</code>. 264 */ 265 typedef struct _rtl_ModuleCount 266 { 267 void ( SAL_CALL * acquire ) ( struct _rtl_ModuleCount * that ); 268 void ( SAL_CALL * release ) ( struct _rtl_ModuleCount * that ); 269 }rtl_ModuleCount; 270 271 272 #define MODULE_COUNT_INIT \ 273 { {rtl_moduleCount_acquire,rtl_moduleCount_release}, rtl_moduleCount_canUnload, 0, {0, 0}} 274 275 /** 276 This struct can be used to implement the unloading mechanism. To make a UNO library 277 unloadable create one global instance of this struct in the module. To initialize it one 278 uses the MODULE_COUNT_INIT macro. 279 280 <pre>rtl_StandardModuleCount globalModuleCount= MODULE_COUNT_INIT</pre>; 281 */ 282 typedef struct _rtl_StandardModuleCount 283 { 284 rtl_ModuleCount modCnt; 285 sal_Bool ( *canUnload ) ( struct _rtl_StandardModuleCount* a, TimeValue* libUnused); 286 oslInterlockedCount counter; 287 TimeValue unusedSince; 288 } rtl_StandardModuleCount; 289 290 /** Default implementation for <code>rtl_ModuleCount.acquire</code>. Use this function along with 291 <code>rtl_StandardModuleCount</code>. 292 */ 293 void rtl_moduleCount_acquire(rtl_ModuleCount * that ); 294 /** Default implementation for <code>rtl_ModuleCount.release</code>. 295 Use this function along with 296 <code>rtl_StandardModuleCount</code>. 297 */ 298 void rtl_moduleCount_release( rtl_ModuleCount * that ); 299 300 /** Default implementation for <code>component_canUnload</code>. Use this function along with 301 <code>rtl_StandardModuleCount</code>. 302 */ 303 sal_Bool rtl_moduleCount_canUnload( rtl_StandardModuleCount * that, TimeValue* libUnused); 304 305 306 #ifdef __cplusplus 307 } 308 #endif 309 310 311 #endif 312