xref: /AOO41X/main/chart2/source/tools/LifeTime.cxx (revision cde9e8dc2218e857da4894ecba5c903312256674)
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 
LifeTimeManager(lang::XComponent * pComponent,sal_Bool bLongLastingCallsCancelable)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 
impl_init()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 
~LifeTimeManager()57 LifeTimeManager::~LifeTimeManager()
58 {
59 }
60 
impl_isDisposed(bool bAssert)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
impl_canStartApiCall()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
impl_registerApiCall(sal_Bool bLongLastingCall)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
impl_unregisterApiCall(sal_Bool bLongLastingCall)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
dispose()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 
CloseableLifeTimeManager(::com::sun::star::util::XCloseable * pCloseable,::com::sun::star::lang::XComponent * pComponent,sal_Bool bLongLastingCallsCancelable)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 
~CloseableLifeTimeManager()183 CloseableLifeTimeManager::~CloseableLifeTimeManager()
184 {
185 }
186 
impl_isDisposedOrClosed(bool bAssert)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
g_close_startTryClose(sal_Bool bDeliverOwnership)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
g_close_endTryClose(sal_Bool bDeliverOwnership,sal_Bool)268 ::g_close_endTryClose(sal_Bool bDeliverOwnership, sal_Bool /* bMyVeto */ )
269 {
270     //this method is called, if the try to close was not successfull
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
g_close_isNeedToCancelLongLastingCalls(sal_Bool bDeliverOwnership,util::CloseVetoException & ex)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
g_close_endTryClose_doClose()312 ::g_close_endTryClose_doClose()
313 {
314     //this method is called, if the try to close was successfull
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
impl_setOwnership(sal_Bool bDeliverOwnership,sal_Bool bMyVeto)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
impl_shouldCloseAtNextChance()333 ::impl_shouldCloseAtNextChance()
334 {
335     return m_bOwnership;
336 }
337 
338     void CloseableLifeTimeManager
impl_apiCallCountReachedNull()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
impl_doClose()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
g_addCloseListener(const uno::Reference<util::XCloseListener> & xListener)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
impl_canStartApiCall()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
startApiCall(sal_Bool bLongLastingCall)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 
~LifeTimeGuard()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