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 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_chart2.hxx" 26 #include "LifeTime.hxx" 27 #include "macros.hxx" 28 #include <osl/diagnose.h> 29 30 #include <com/sun/star/util/XModifyListener.hpp> 31 #include <com/sun/star/util/XCloseListener.hpp> 32 33 using namespace ::com::sun::star; 34 35 namespace apphelper 36 { 37 //-------------------------- 38 39 LifeTimeManager::LifeTimeManager( lang::XComponent* pComponent, sal_Bool bLongLastingCallsCancelable ) 40 : m_aListenerContainer( m_aAccessMutex ) 41 , m_pComponent(pComponent) 42 , m_bLongLastingCallsCancelable(bLongLastingCallsCancelable) 43 { 44 impl_init(); 45 } 46 47 void LifeTimeManager::impl_init() 48 { 49 m_bDisposed = sal_False; 50 m_bInDispose = sal_False; 51 m_nAccessCount = 0; 52 m_nLongLastingCallCount = 0; 53 m_aNoAccessCountCondition.set(); 54 m_aNoLongLastingCallCountCondition.set(); 55 } 56 57 LifeTimeManager::~LifeTimeManager() 58 { 59 } 60 61 bool LifeTimeManager::impl_isDisposed( bool bAssert ) 62 { 63 if( m_bDisposed || m_bInDispose ) 64 { 65 if( bAssert ) 66 { 67 OSL_ENSURE( sal_False, "This component is already disposed " ); 68 (void)(bAssert); 69 } 70 return sal_True; 71 } 72 return sal_False; 73 } 74 sal_Bool LifeTimeManager 75 ::impl_canStartApiCall() 76 { 77 if( impl_isDisposed() ) 78 return sal_False; //behave passive if already disposed 79 80 //mutex is acquired 81 return sal_True; 82 } 83 84 void LifeTimeManager 85 ::impl_registerApiCall(sal_Bool bLongLastingCall) 86 { 87 //only allowed if not disposed 88 //do not acquire the mutex here because it will be acquired already 89 m_nAccessCount++; 90 if(m_nAccessCount==1) 91 //@todo? is it ok to wake some threads here while we have acquired the mutex? 92 m_aNoAccessCountCondition.reset(); 93 94 if(bLongLastingCall) 95 m_nLongLastingCallCount++; 96 if(m_nLongLastingCallCount==1) 97 m_aNoLongLastingCallCountCondition.reset(); 98 } 99 void LifeTimeManager 100 ::impl_unregisterApiCall(sal_Bool bLongLastingCall) 101 { 102 //Mutex needs to be acquired exactly ones 103 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull() 104 105 OSL_ENSURE( m_nAccessCount>0, "access count mismatch" ); 106 m_nAccessCount--; 107 if(bLongLastingCall) 108 m_nLongLastingCallCount--; 109 if( m_nLongLastingCallCount==0 ) 110 { 111 m_aNoLongLastingCallCountCondition.set(); 112 } 113 if( m_nAccessCount== 0) 114 { 115 m_aNoAccessCountCondition.set(); 116 impl_apiCallCountReachedNull(); 117 118 } 119 } 120 121 sal_Bool LifeTimeManager 122 ::dispose() throw(uno::RuntimeException) 123 { 124 //hold no mutex 125 { 126 osl::Guard< osl::Mutex > aGuard( m_aAccessMutex ); 127 128 if( m_bDisposed || m_bInDispose ) 129 { 130 OSL_TRACE( "This component is already disposed " ); 131 return sal_False; //behave passive if already disposed 132 } 133 134 m_bInDispose = true; 135 //adding any listener is not allowed anymore 136 //new calls will not be accepted 137 //still running calls have the freedom to finish their work without crash 138 } 139 //no mutex is acquired 140 141 //--do the disposing of listeners after calling this method 142 { 143 uno::Reference< lang::XComponent > xComponent = 144 uno::Reference< lang::XComponent >(m_pComponent);; 145 if(xComponent.is()) 146 { 147 // notify XCLoseListeners 148 lang::EventObject aEvent( xComponent ); 149 m_aListenerContainer.disposeAndClear( aEvent ); 150 } 151 } 152 153 //no mutex is acquired 154 { 155 osl::ClearableGuard< osl::Mutex > aGuard( m_aAccessMutex ); 156 OSL_ENSURE( !m_bDisposed, "dispose was called already" ); 157 m_bDisposed = sal_True; 158 aGuard.clear(); 159 } 160 //no mutex is acquired 161 162 //wait until all still running calls have finished 163 //the accessCount cannot grow anymore, because all calls will return after checking m_bDisposed 164 m_aNoAccessCountCondition.wait(); 165 166 //we are the only ones working on our data now 167 168 return sal_True; 169 //--release all resources and references after calling this method successful 170 } 171 172 //----------------------------------------------------------------- 173 174 CloseableLifeTimeManager::CloseableLifeTimeManager( ::com::sun::star::util::XCloseable* pCloseable 175 , ::com::sun::star::lang::XComponent* pComponent 176 , sal_Bool bLongLastingCallsCancelable ) 177 : LifeTimeManager( pComponent, bLongLastingCallsCancelable ) 178 , m_pCloseable(pCloseable) 179 { 180 impl_init(); 181 } 182 183 CloseableLifeTimeManager::~CloseableLifeTimeManager() 184 { 185 } 186 187 bool CloseableLifeTimeManager::impl_isDisposedOrClosed( bool bAssert ) 188 { 189 if( impl_isDisposed( bAssert ) ) 190 return sal_True; 191 192 if( m_bClosed ) 193 { 194 if( bAssert ) 195 { 196 OSL_ENSURE( sal_False, "This object is already closed" ); 197 (void)(bAssert);//avoid warnings 198 } 199 return sal_True; 200 } 201 return sal_False; 202 } 203 204 sal_Bool CloseableLifeTimeManager 205 ::g_close_startTryClose(sal_Bool bDeliverOwnership) 206 throw ( uno::Exception ) 207 { 208 //no mutex is allowed to be acquired 209 { 210 osl::ResettableGuard< osl::Mutex > aGuard( m_aAccessMutex ); 211 if( impl_isDisposedOrClosed(false) ) 212 return sal_False; 213 214 //Mutex needs to be acquired exactly ones; will be released inbetween 215 if( !impl_canStartApiCall() ) 216 return sal_False; 217 //mutex is acquired 218 219 //not closed already -> we try to close again 220 m_bInTryClose = sal_True; 221 m_aEndTryClosingCondition.reset(); 222 223 impl_registerApiCall(sal_False); 224 } 225 226 //------------------------------------------------ 227 //no mutex is acquired 228 229 //only remove listener calls will be worked on until end of tryclose 230 //all other new calls will wait till end of try close // @todo? is that really ok 231 232 //?? still running calls have the freedom to finish their work without crash 233 234 try 235 { 236 uno::Reference< util::XCloseable > xCloseable = 237 uno::Reference< util::XCloseable >(m_pCloseable);; 238 if(xCloseable.is()) 239 { 240 //--call queryClosing on all registered close listeners 241 ::cppu::OInterfaceContainerHelper* pIC = m_aListenerContainer.getContainer( 242 ::getCppuType((const uno::Reference< util::XCloseListener >*)0) );; 243 if( pIC ) 244 { 245 //lang::EventObject aEvent( static_cast< util::XCloseable*>(xCloseable) ); 246 lang::EventObject aEvent( xCloseable ); 247 ::cppu::OInterfaceIteratorHelper aIt( *pIC ); 248 while( aIt.hasMoreElements() ) 249 { 250 uno::Reference< util::XCloseListener > xCloseListener( aIt.next(), uno::UNO_QUERY ); 251 if(xCloseListener.is()) 252 xCloseListener->queryClosing( aEvent, bDeliverOwnership ); 253 } 254 } 255 } 256 } 257 catch( uno::Exception& ex ) 258 { 259 //no mutex is acquired 260 g_close_endTryClose(bDeliverOwnership, sal_False); 261 (void)(ex); 262 throw; 263 } 264 return sal_True; 265 } 266 267 void CloseableLifeTimeManager 268 ::g_close_endTryClose(sal_Bool bDeliverOwnership, sal_Bool /* bMyVeto */ ) 269 { 270 //this method is called, if the try to close was not successful 271 osl::Guard< osl::Mutex > aGuard( m_aAccessMutex ); 272 impl_setOwnership( bDeliverOwnership, sal_False ); 273 274 m_bInTryClose = sal_False; 275 m_aEndTryClosingCondition.set(); 276 277 //Mutex needs to be acquired exactly ones 278 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull() 279 impl_unregisterApiCall(sal_False); 280 } 281 282 sal_Bool CloseableLifeTimeManager 283 ::g_close_isNeedToCancelLongLastingCalls( sal_Bool bDeliverOwnership, util::CloseVetoException& ex ) 284 throw ( util::CloseVetoException ) 285 { 286 //this method is called when no closelistener has had a veto during queryclosing 287 //the method returns false, if nothing stands against closing anymore 288 //it returns true, if some longlasting calls are running, which might be cancelled 289 //it throws the given exception, if long calls are running but not cancelable 290 291 osl::Guard< osl::Mutex > aGuard( m_aAccessMutex ); 292 //this count cannot grow after try of close has started, because we wait in all those methods for end of try closing 293 if( !m_nLongLastingCallCount ) 294 return sal_False; 295 296 if(m_bLongLastingCallsCancelable) 297 return sal_True; 298 299 impl_setOwnership( bDeliverOwnership, sal_True ); 300 301 m_bInTryClose = sal_False; 302 m_aEndTryClosingCondition.set(); 303 304 //Mutex needs to be acquired exactly ones 305 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull() 306 impl_unregisterApiCall(sal_False); 307 308 throw ex; 309 } 310 311 void CloseableLifeTimeManager 312 ::g_close_endTryClose_doClose() 313 { 314 //this method is called, if the try to close was successful 315 osl::ResettableGuard< osl::Mutex > aGuard( m_aAccessMutex ); 316 317 m_bInTryClose = sal_False; 318 m_aEndTryClosingCondition.set(); 319 320 //Mutex needs to be acquired exactly ones 321 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull() 322 impl_unregisterApiCall(sal_False); 323 impl_doClose(); 324 } 325 326 void CloseableLifeTimeManager 327 ::impl_setOwnership( sal_Bool bDeliverOwnership, sal_Bool bMyVeto ) 328 { 329 m_bOwnership = bDeliverOwnership && bMyVeto; 330 m_bOwnershipIsWellKnown = sal_True; 331 } 332 sal_Bool CloseableLifeTimeManager 333 ::impl_shouldCloseAtNextChance() 334 { 335 return m_bOwnership; 336 } 337 338 void CloseableLifeTimeManager 339 ::impl_apiCallCountReachedNull() 340 { 341 //Mutex needs to be acquired exactly ones 342 //mutex will be released inbetween in impl_doClose() 343 if( m_pCloseable && impl_shouldCloseAtNextChance() ) 344 impl_doClose(); 345 } 346 347 void CloseableLifeTimeManager 348 ::impl_doClose() 349 { 350 //Mutex needs to be acquired exactly ones before calling impl_doClose() 351 352 if(m_bClosed) 353 return; //behave as passive as possible, if disposed or closed already 354 if( m_bDisposed || m_bInDispose ) 355 return; //behave as passive as possible, if disposed or closed already 356 357 //-------- 358 m_bClosed = sal_True; 359 360 NegativeGuard< osl::Mutex > aNegativeGuard( m_aAccessMutex ); 361 //mutex is not acquired, mutex will be reacquired at the end of this method automatically 362 363 uno::Reference< util::XCloseable > xCloseable=NULL; 364 try 365 { 366 xCloseable = uno::Reference< util::XCloseable >(m_pCloseable);; 367 if(xCloseable.is()) 368 { 369 //--call notifyClosing on all registered close listeners 370 ::cppu::OInterfaceContainerHelper* pIC = m_aListenerContainer.getContainer( 371 ::getCppuType((const uno::Reference< util::XCloseListener >*)0) );; 372 if( pIC ) 373 { 374 //lang::EventObject aEvent( static_cast< util::XCloseable*>(xCloseable) ); 375 lang::EventObject aEvent( xCloseable ); 376 ::cppu::OInterfaceIteratorHelper aIt( *pIC ); 377 while( aIt.hasMoreElements() ) 378 { 379 uno::Reference< util::XCloseListener > xListener( aIt.next(), uno::UNO_QUERY ); 380 if( xListener.is() ) 381 xListener->notifyClosing( aEvent ); 382 } 383 } 384 } 385 } 386 catch( uno::Exception& ex ) 387 { 388 ASSERT_EXCEPTION( ex ); 389 } 390 391 if(xCloseable.is()) 392 { 393 uno::Reference< lang::XComponent > xComponent = 394 uno::Reference< lang::XComponent >( xCloseable, uno::UNO_QUERY ); 395 if(xComponent.is()) 396 { 397 OSL_ENSURE( m_bClosed, "a not closed component will be disposed " ); 398 xComponent->dispose(); 399 } 400 } 401 //mutex will be reacquired in destructor of aNegativeGuard 402 } 403 404 sal_Bool CloseableLifeTimeManager 405 ::g_addCloseListener( const uno::Reference< util::XCloseListener > & xListener ) 406 throw(uno::RuntimeException) 407 { 408 osl::Guard< osl::Mutex > aGuard( m_aAccessMutex ); 409 //Mutex needs to be acquired exactly ones; will be released inbetween 410 if( !impl_canStartApiCall() ) 411 return sal_False; 412 //mutex is acquired 413 414 m_aListenerContainer.addInterface( ::getCppuType((const uno::Reference< util::XCloseListener >*)0),xListener ); 415 m_bOwnership = sal_False; 416 return sal_True; 417 } 418 419 sal_Bool CloseableLifeTimeManager 420 ::impl_canStartApiCall() 421 { 422 //Mutex needs to be acquired exactly ones before calling this method 423 //the mutex will be released inbetween and reacquired 424 425 if( impl_isDisposed() ) 426 return sal_False; //behave passive if already disposed 427 if( m_bClosed ) 428 return sal_False; //behave passive if closing is already done 429 430 //during try-close most calls need to wait for the decision 431 while( m_bInTryClose ) 432 { 433 //if someone tries to close this object at the moment 434 //we need to wait for his end because the result of the preceding call 435 //is relevant for our behaviour here 436 437 m_aAccessMutex.release(); 438 m_aEndTryClosingCondition.wait(); //@todo??? this may block??? try closing 439 m_aAccessMutex.acquire(); 440 if( m_bDisposed || m_bInDispose || m_bClosed ) 441 return sal_False; //return if closed already 442 } 443 //mutex is acquired 444 return sal_True; 445 } 446 447 //-------------------------- 448 449 sal_Bool LifeTimeGuard 450 ::startApiCall(sal_Bool bLongLastingCall) 451 { 452 //Mutex needs to be acquired exactly ones; will be released inbetween 453 //mutex is requiered due to constructor of LifeTimeGuard 454 455 OSL_ENSURE( !m_bCallRegistered, "this method is only allowed ones" ); 456 if(m_bCallRegistered) 457 return sal_False; 458 459 //Mutex needs to be acquired exactly ones; will be released inbetween 460 if( !m_rManager.impl_canStartApiCall() ) 461 return sal_False; 462 //mutex is acquired 463 464 m_bCallRegistered = sal_True; 465 m_bLongLastingCallRegistered = bLongLastingCall; 466 m_rManager.impl_registerApiCall(bLongLastingCall); 467 return sal_True; 468 } 469 470 LifeTimeGuard::~LifeTimeGuard() 471 { 472 try 473 { 474 //do acquire the mutex if it was cleared before 475 osl::MutexGuard g(m_rManager.m_aAccessMutex); 476 if(m_bCallRegistered) 477 { 478 //Mutex needs to be acquired exactly ones 479 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull() 480 m_rManager.impl_unregisterApiCall(m_bLongLastingCallRegistered); 481 } 482 } 483 catch( uno::Exception& ex ) 484 { 485 //@todo ? allow a uno::RuntimeException from dispose to travel through?? 486 ex.Context.is(); //to avoid compilation warnings 487 } 488 } 489 490 /* 491 the XCloseable::close method has to be implemented in the following way: 492 ::close 493 { 494 //hold no mutex 495 496 if( !m_aLifeTimeManager.g_close_startTryClose( bDeliverOwnership ) ) 497 return; 498 //no mutex is acquired 499 500 // At the end of this method may we must dispose ourself ... 501 // and may nobody from outside hold a reference to us ... 502 // then it's a good idea to do that by ourself. 503 uno::Reference< uno::XInterface > xSelfHold( static_cast< ::cppu::OWeakObject* >(this) ); 504 505 //the listeners have had no veto 506 //check wether we self can close 507 { 508 util::CloseVetoException aVetoException = util::CloseVetoException( 509 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 510 "the model itself could not be closed" ) ) 511 , static_cast< ::cppu::OWeakObject* >(this)); 512 513 if( m_aLifeTimeManager.g_close_isNeedToCancelLongLastingCalls( bDeliverOwnership, aVetoException ) ) 514 { 515 ////you can empty this block, if you never start longlasting calls or 516 ////if your longlasting calls are per default not cancelable (check how you have constructed your LifeTimeManager) 517 518 sal_Bool bLongLastingCallsAreCanceled = sal_False; 519 try 520 { 521 //try to cancel running longlasting calls 522 //// @todo 523 } 524 catch( uno::Exception& ex ) 525 { 526 //// @todo 527 //do not throw anything here!! (without endTryClose) 528 } 529 //if not successful canceled 530 if(!bLongLastingCallsAreCanceled) 531 { 532 m_aLifeTimeManager.g_close_endTryClose( bDeliverOwnership, sal_True ); 533 throw aVetoException; 534 } 535 } 536 537 } 538 m_aLifeTimeManager.g_close_endTryClose_doClose(); 539 } 540 */ 541 542 }//end namespace apphelper 543