LibreOffice Module chart2 (master) 1
LifeTime.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <LifeTime.hxx>
21#include <osl/diagnose.h>
22
23#include <com/sun/star/document/XStorageChangeListener.hpp>
24#include <com/sun/star/lang/XComponent.hpp>
25#include <com/sun/star/util/CloseVetoException.hpp>
26#include <com/sun/star/util/XCloseListener.hpp>
27#include <com/sun/star/util/XCloseable.hpp>
28#include <com/sun/star/util/XModifyListener.hpp>
29#include <com/sun/star/view/XSelectionChangeListener.hpp>
31#include <sal/log.hxx>
32
33using namespace ::com::sun::star;
34
35namespace apphelper
36{
37
38LifeTimeManager::LifeTimeManager( lang::XComponent* pComponent )
39 : m_pComponent(pComponent)
40{
41 m_bDisposed = false;
42 m_bInDispose = false;
47}
48
50{
51}
52
54{
56 {
57 if( bAssert )
58 {
59 OSL_FAIL( "This component is already disposed " );
60 }
61 return true;
62 }
63 return false;
64}
65
67{
68 if( impl_isDisposed() )
69 return false; //behave passive if already disposed
70
71 //mutex is acquired
72 return true;
73}
74
75void LifeTimeManager::impl_registerApiCall(bool bLongLastingCall)
76{
77 //only allowed if not disposed
78 //do not acquire the mutex here because it will be acquired already
80 if(m_nAccessCount==1)
81 //@todo? is it ok to wake some threads here while we have acquired the mutex?
83
84 if(bLongLastingCall)
88}
89
90void LifeTimeManager::impl_unregisterApiCall(std::unique_lock<std::mutex>& rGuard, bool bLongLastingCall)
91{
92 //Mutex needs to be acquired exactly once
93 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
94
95 OSL_ENSURE( m_nAccessCount>0, "access count mismatch" );
97 if(bLongLastingCall)
100 {
102 }
103 if( m_nAccessCount== 0)
104 {
107
108 }
109}
110
112{
113 //hold no mutex
114 {
115 std::unique_lock aGuard( m_aAccessMutex );
116
118 {
119 SAL_WARN("chart2", "This component is already disposed " );
120 return false; //behave passive if already disposed
121 }
122
123 m_bInDispose = true;
124 //adding any listener is not allowed anymore
125 //new calls will not be accepted
126 //still running calls have the freedom to finish their work without crash
127
128 uno::Reference< lang::XComponent > xComponent(m_pComponent);
129 if(xComponent.is())
130 {
131 // notify XCLoseListeners
132 lang::EventObject aEvent( xComponent );
138 }
139
140 OSL_ENSURE( !m_bDisposed, "dispose was called already" );
141 m_bDisposed = true;
142 }
143 //no mutex is acquired
144
145 //wait until all still running calls have finished
146 //the accessCount cannot grow anymore, because all calls will return after checking m_bDisposed
148
149 //we are the only ones working on our data now
150
151 return true;
152 //--release all resources and references after calling this method successful
153}
154
156 , css::lang::XComponent* pComponent )
157 : LifeTimeManager( pComponent )
158 , m_pCloseable(pCloseable)
159{
160 m_bClosed = false;
161 m_bInTryClose = false;
162 m_bOwnership = false;
164}
165
167{
168}
169
171{
172 if( impl_isDisposed( bAssert ) )
173 return true;
174
175 if( m_bClosed )
176 {
177 if( bAssert )
178 {
179 OSL_FAIL( "This object is already closed" );
180 }
181 return true;
182 }
183 return false;
184}
185
187{
188 //no mutex is allowed to be acquired
189 {
190 std::unique_lock aGuard( m_aAccessMutex );
191 if( impl_isDisposedOrClosed(false) )
192 return false;
193
194 //Mutex needs to be acquired exactly once; will be released inbetween
195 if( !impl_canStartApiCall() )
196 return false;
197 //mutex is acquired
198
199 //not closed already -> we try to close again
200 m_bInTryClose = true;
202
204 }
205
206 //no mutex is acquired
207
208 //only remove listener calls will be worked on until end of tryclose
209 //all other new calls will wait till end of try close // @todo? is that really ok
210
211 //?? still running calls have the freedom to finish their work without crash
212
213 try
214 {
215 uno::Reference< util::XCloseable > xCloseable(m_pCloseable);
216 if(xCloseable.is())
217 {
218 std::unique_lock aGuard( m_aAccessMutex );
219 //--call queryClosing on all registered close listeners
220 if( m_aCloseListeners.getLength(aGuard) )
221 {
222 lang::EventObject aEvent( xCloseable );
224 [&aEvent, bDeliverOwnership](const uno::Reference<util::XCloseListener>& l)
225 {
226 l->queryClosing(aEvent, bDeliverOwnership);
227 });
228 }
229 }
230 }
231 catch( const uno::Exception& )
232 {
233 //no mutex is acquired
234 g_close_endTryClose(bDeliverOwnership);
235 throw;
236 }
237 return true;
238}
239
241{
242 //this method is called, if the try to close was not successful
243 std::unique_lock aGuard( m_aAccessMutex );
244 impl_setOwnership( bDeliverOwnership, false );
245
246 m_bInTryClose = false;
248
249 //Mutex needs to be acquired exactly once
250 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
251 impl_unregisterApiCall(aGuard, false);
252}
253
254void CloseableLifeTimeManager::g_close_isNeedToCancelLongLastingCalls( bool bDeliverOwnership, util::CloseVetoException const & ex )
255{
256 //this method is called when no closelistener has had a veto during queryclosing
257 //the method returns false, if nothing stands against closing anymore
258 //it returns true, if some longlasting calls are running, which might be cancelled
259 //it throws the given exception, if long calls are running but not cancelable
260
261 std::unique_lock aGuard( m_aAccessMutex );
262 //this count cannot grow after try of close has started, because we wait in all those methods for end of try closing
264 return;
265
266 impl_setOwnership( bDeliverOwnership, true );
267
268 m_bInTryClose = false;
270
271 //Mutex needs to be acquired exactly once
272 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
273 impl_unregisterApiCall(aGuard, false);
274
275 throw ex;
276}
277
279{
280 //this method is called, if the try to close was successful
281 std::unique_lock aGuard( m_aAccessMutex );
282
283 m_bInTryClose = false;
285
286 //Mutex needs to be acquired exactly once
287 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
288 impl_unregisterApiCall(aGuard, false);
289 impl_doClose(aGuard);
290}
291
292void CloseableLifeTimeManager::impl_setOwnership( bool bDeliverOwnership, bool bMyVeto )
293{
294 m_bOwnership = bDeliverOwnership && bMyVeto;
295}
296
297void CloseableLifeTimeManager::impl_apiCallCountReachedNull(std::unique_lock<std::mutex>& rGuard)
298{
299 //Mutex needs to be acquired exactly once
300 //mutex will be released inbetween in impl_doClose()
302 impl_doClose(rGuard);
303}
304
305void CloseableLifeTimeManager::impl_doClose(std::unique_lock<std::mutex>& rGuard)
306{
307 //Mutex needs to be acquired exactly once before calling impl_doClose()
308
309 if(m_bClosed)
310 return; //behave as passive as possible, if disposed or closed already
312 return; //behave as passive as possible, if disposed or closed already
313
314 m_bClosed = true;
315
316 uno::Reference< util::XCloseable > xCloseable;
317 xCloseable.set(m_pCloseable);
318 try
319 {
320 if(xCloseable.is())
321 {
322 //--call notifyClosing on all registered close listeners
323 if( m_aCloseListeners.getLength(rGuard) )
324 {
325 lang::EventObject aEvent( xCloseable );
326 m_aCloseListeners.notifyEach(rGuard, &util::XCloseListener::notifyClosing, aEvent);
327 }
328 }
329 }
330 catch( const uno::Exception& )
331 {
332 DBG_UNHANDLED_EXCEPTION("chart2");
333 }
334
335 rGuard.unlock();
336 if(xCloseable.is())
337 {
338 uno::Reference< lang::XComponent > xComponent( xCloseable, uno::UNO_QUERY );
339 if(xComponent.is())
340 {
341 OSL_ENSURE( m_bClosed, "a not closed component will be disposed " );
342 xComponent->dispose();
343 }
344 }
345 rGuard.lock();
346}
347
348void CloseableLifeTimeManager::g_addCloseListener( const uno::Reference< util::XCloseListener > & xListener )
349{
350 std::unique_lock aGuard( m_aAccessMutex );
351 //Mutex needs to be acquired exactly once; will be released inbetween
352 if( !impl_canStartApiCall() )
353 return;
354 //mutex is acquired
355
356 m_aCloseListeners.addInterface( aGuard, xListener );
357 m_bOwnership = false;
358}
359
361{
362 //Mutex needs to be acquired exactly once before calling this method
363 //the mutex will be released inbetween and reacquired
364
365 if( impl_isDisposed() )
366 return false; //behave passive if already disposed
367 if( m_bClosed )
368 return false; //behave passive if closing is already done
369
370 //during try-close most calls need to wait for the decision
371 while( m_bInTryClose )
372 {
373 //if someone tries to close this object at the moment
374 //we need to wait for his end because the result of the preceding call
375 //is relevant for our behaviour here
376
377 m_aAccessMutex.unlock();
378 m_aEndTryClosingCondition.wait(); //@todo??? this may block??? try closing
379 m_aAccessMutex.lock();
381 return false; //return if closed already
382 }
383 //mutex is acquired
384 return true;
385}
386
387bool LifeTimeGuard::startApiCall(bool bLongLastingCall)
388{
389 //Mutex needs to be acquired exactly once; will be released inbetween
390 //mutex is required due to constructor of LifeTimeGuard
391
392 OSL_ENSURE( !m_bCallRegistered, "this method is only allowed ones" );
394 return false;
395
396 //Mutex needs to be acquired exactly once; will be released inbetween
398 return false;
399 //mutex is acquired
400
401 m_bCallRegistered = true;
402 m_bLongLastingCallRegistered = bLongLastingCall;
403 m_rManager.impl_registerApiCall(bLongLastingCall);
404 return true;
405}
406
408{
409 try
410 {
411 //do acquire the mutex if it was cleared before
412 if (!m_guard.owns_lock())
413 m_guard.lock();
415 {
416 //Mutex needs to be acquired exactly once
417 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
419 }
420 }
421 catch( uno::Exception& ex )
422 {
423 //@todo ? allow a uno::RuntimeException from dispose to travel through??
424 ex.Context.is(); //to avoid compilation warnings
425 }
426}
427
428}//end namespace apphelper
429
430/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
AnyEventRef aEvent
::osl::Condition m_aEndTryClosingCondition
Definition: LifeTime.hxx:76
virtual bool impl_canStartApiCall() override
Definition: LifeTime.cxx:360
void impl_doClose(std::unique_lock< std::mutex > &rGuard)
Definition: LifeTime.cxx:305
void g_close_endTryClose(bool bDeliverOwnership)
Definition: LifeTime.cxx:240
void impl_setOwnership(bool bDeliverOwnership, bool bMyVeto)
Definition: LifeTime.cxx:292
void g_addCloseListener(const css::uno::Reference< css::util::XCloseListener > &xListener)
Definition: LifeTime.cxx:348
bool impl_isDisposedOrClosed(bool bAssert=true)
Definition: LifeTime.cxx:170
virtual ~CloseableLifeTimeManager() override
Definition: LifeTime.cxx:166
virtual void impl_apiCallCountReachedNull(std::unique_lock< std::mutex > &rGuard) override
Definition: LifeTime.cxx:297
void g_close_isNeedToCancelLongLastingCalls(bool bDeliverOwnership, css::util::CloseVetoException const &ex)
Definition: LifeTime.cxx:254
CloseableLifeTimeManager(css::util::XCloseable *pCloseable, css::lang::XComponent *pComponent)
Definition: LifeTime.cxx:155
css::util::XCloseable * m_pCloseable
Definition: LifeTime.hxx:74
bool g_close_startTryClose(bool bDeliverOwnership)
Definition: LifeTime.cxx:186
std::unique_lock< std::mutex > m_guard
Definition: LifeTime.hxx:186
bool startApiCall(bool bLongLastingCall=false)
Definition: LifeTime.cxx:387
LifeTimeManager & m_rManager
Definition: LifeTime.hxx:187
::comphelper::OInterfaceContainerHelper4< css::util::XModifyListener > m_aModifyListeners
Definition: LifeTime.hxx:51
::osl::Condition m_aNoLongLastingCallCountCondition
Definition: LifeTime.hxx:68
::comphelper::OInterfaceContainerHelper4< css::lang::XEventListener > m_aEventListeners
Definition: LifeTime.hxx:53
bool volatile m_bInDispose
Definition: LifeTime.hxx:67
virtual SAL_DLLPRIVATE bool impl_canStartApiCall()
Definition: LifeTime.cxx:66
bool volatile m_bDisposed
Definition: LifeTime.hxx:66
LifeTimeManager(css::lang::XComponent *pComponent)
Definition: LifeTime.cxx:38
::comphelper::OInterfaceContainerHelper4< css::view::XSelectionChangeListener > m_aSelectionChangeListeners
Definition: LifeTime.hxx:54
virtual SAL_DLLPRIVATE void impl_apiCallCountReachedNull(std::unique_lock< std::mutex > &)
Definition: LifeTime.hxx:58
bool impl_isDisposed(bool bAssert=true)
Definition: LifeTime.cxx:53
::comphelper::OInterfaceContainerHelper4< css::util::XCloseListener > m_aCloseListeners
Definition: LifeTime.hxx:50
::osl::Condition m_aNoAccessCountCondition
Definition: LifeTime.hxx:64
::comphelper::OInterfaceContainerHelper4< css::document::XStorageChangeListener > m_aStorageChangeListeners
Definition: LifeTime.hxx:52
SAL_DLLPRIVATE void impl_unregisterApiCall(std::unique_lock< std::mutex > &rGuard, bool bLongLastingCall)
Definition: LifeTime.cxx:90
sal_Int32 m_nLongLastingCallCount
Definition: LifeTime.hxx:69
css::lang::XComponent * m_pComponent
Definition: LifeTime.hxx:63
SAL_DLLPRIVATE void impl_registerApiCall(bool bLongLastingCall)
Definition: LifeTime.cxx:75
void forEach(std::unique_lock< std::mutex > &rGuard, FuncT const &func) const
sal_Int32 addInterface(std::unique_lock< std::mutex > &rGuard, const css::uno::Reference< ListenerT > &rxIFace)
void notifyEach(std::unique_lock< std::mutex > &rGuard, void(SAL_CALL ListenerT::*NotificationMethod)(const EventT &), const EventT &Event) const
void disposeAndClear(::std::unique_lock<::std::mutex > &rGuard, const css::lang::EventObject &rEvt)
sal_Int32 getLength(std::unique_lock< std::mutex > &rGuard) const
#define DBG_UNHANDLED_EXCEPTION(...)
#define SAL_WARN(area, stream)