Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / cppuhelper / source / weak.cxx
blobfb2ccfdfe5d77fc2b044a601fbc0773e3e4dcfa1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <osl/mutex.hxx>
23 #include <cppuhelper/weakagg.hxx>
24 #include <cppuhelper/interfacecontainer.hxx>
25 #include <cppuhelper/exc_hlp.hxx>
26 #include <cppuhelper/queryinterface.hxx>
28 #include <algorithm>
29 #include <utility>
31 using namespace osl;
32 using namespace com::sun::star::uno;
34 /** */ //for docpp
35 namespace cppu
38 // due to static Reflection destruction from usr, there must be a mutex leak (#73272#)
39 // this is used to lock all instances of OWeakConnectionPoint and OWeakRefListener as well as OWeakObject::m_pWeakConnectionPoint
40 inline static Mutex & getWeakMutex()
42 static Mutex * s_pMutex = nullptr;
43 if (! s_pMutex)
44 s_pMutex = new Mutex();
45 return *s_pMutex;
49 //-- OWeakConnectionPoint ----------------------------------------------------
51 class OWeakConnectionPoint: public XAdapter
53 public:
54 /**
55 Hold the weak object without an acquire (only the pointer).
57 explicit OWeakConnectionPoint( OWeakObject* pObj )
58 : m_aRefCount( 0 )
59 , m_pObject(pObj)
62 // noncopyable
63 OWeakConnectionPoint(const OWeakConnectionPoint&) = delete;
64 const OWeakConnectionPoint& operator=(const OWeakConnectionPoint&) = delete;
66 // XInterface
67 Any SAL_CALL queryInterface( const Type & rType ) override;
68 void SAL_CALL acquire() throw() override;
69 void SAL_CALL release() throw() override;
71 // XAdapter
72 css::uno::Reference< css::uno::XInterface > SAL_CALL queryAdapted() override;
73 void SAL_CALL addReference( const css::uno::Reference< css::uno::XReference >& xRef ) override;
74 void SAL_CALL removeReference( const css::uno::Reference< css::uno::XReference >& xRef ) override;
76 /// Called from the weak object if the reference count goes to zero.
77 ///
78 /// @throws css::uno::RuntimeException
79 void dispose();
81 private:
82 virtual ~OWeakConnectionPoint() {}
84 /// The reference counter.
85 oslInterlockedCount m_aRefCount;
86 /// The weak object
87 OWeakObject* m_pObject;
88 /// The container to hold the weak references
89 std::vector<Reference<XReference>> m_aReferences;
92 // XInterface
93 Any SAL_CALL OWeakConnectionPoint::queryInterface( const Type & rType )
95 return ::cppu::queryInterface(
96 rType, static_cast< XAdapter * >( this ), static_cast< XInterface * >( this ) );
99 // XInterface
100 void SAL_CALL OWeakConnectionPoint::acquire() throw()
102 osl_atomic_increment( &m_aRefCount );
105 // XInterface
106 void SAL_CALL OWeakConnectionPoint::release() throw()
108 if (! osl_atomic_decrement( &m_aRefCount ))
109 delete this;
112 void OWeakConnectionPoint::dispose()
114 std::vector<Reference<XReference>> aCopy;
115 { // only hold the mutex while we access the field
116 MutexGuard aGuard(getWeakMutex());
117 // OWeakObject is not the only owner of this, so clear m_pObject
118 // so that queryAdapted() won't use it now that it's dead
119 m_pObject = nullptr;
120 // other code is going to call removeReference while we are doing this, so we need a
121 // copy, but since we are disposing and going away, we can just take the original data
122 aCopy.swap(m_aReferences);
124 Any ex;
125 for (const Reference<XReference> & i : aCopy )
129 i->dispose();
131 catch (css::lang::DisposedException &) {}
132 catch (RuntimeException &)
134 ex = cppu::getCaughtException();
137 if (ex.hasValue())
139 cppu::throwException(ex);
143 // XInterface
144 Reference< XInterface > SAL_CALL OWeakConnectionPoint::queryAdapted()
146 Reference< XInterface > ret;
148 ClearableMutexGuard guard(getWeakMutex());
150 if (m_pObject)
152 oslInterlockedCount n = osl_atomic_increment( &m_pObject->m_refCount );
154 if (n > 1)
156 // The reference is incremented. The object cannot be destroyed.
157 // Release the guard at the earliest point.
158 guard.clear();
159 // WeakObject has a (XInterface *) cast operator
160 ret = *m_pObject;
161 osl_atomic_decrement( &m_pObject->m_refCount );
163 else
164 // Another thread wait in the dispose method at the guard
165 osl_atomic_decrement( &m_pObject->m_refCount );
168 return ret;
171 // XInterface
172 void SAL_CALL OWeakConnectionPoint::addReference(const Reference< XReference >& rRef)
174 MutexGuard aGuard(getWeakMutex());
175 m_aReferences.push_back( rRef );
178 // XInterface
179 void SAL_CALL OWeakConnectionPoint::removeReference(const Reference< XReference >& rRef)
181 MutexGuard aGuard(getWeakMutex());
182 // Search from end because the thing that last added a ref is most likely to be the
183 // first to remove a ref.
184 // It's not really valid to compare the pointer directly, but it's faster.
185 for (auto it = m_aReferences.rbegin(); it != m_aReferences.rend(); ++it) {
186 if (it->get() == rRef.get()) {
187 m_aReferences.erase( it.base()-1 );
188 return;
191 // interface not found, use the correct compare method
192 auto it = std::find(m_aReferences.rbegin(), m_aReferences.rend(), rRef);
193 if ( it != m_aReferences.rend() )
194 m_aReferences.erase( it.base()-1 );
198 //-- OWeakObject -------------------------------------------------------
201 #ifdef _MSC_VER
202 // Accidentally occurs in msvc mapfile = > had to be outlined.
203 OWeakObject::OWeakObject()
204 : m_refCount( 0 ),
205 m_pWeakConnectionPoint( nullptr )
208 #endif
210 // XInterface
211 Any SAL_CALL OWeakObject::queryInterface( const Type & rType )
213 return ::cppu::queryInterface(
214 rType,
215 static_cast< XWeak * >( this ), static_cast< XInterface * >( this ) );
218 // XInterface
219 void SAL_CALL OWeakObject::acquire() throw()
221 osl_atomic_increment( &m_refCount );
224 // XInterface
225 void SAL_CALL OWeakObject::release() throw()
227 if (osl_atomic_decrement( &m_refCount ) == 0) {
228 // notify/clear all weak-refs before object's dtor is executed
229 // (which may check weak-refs to this object):
230 disposeWeakConnectionPoint();
231 // destroy object:
232 delete this;
236 void OWeakObject::disposeWeakConnectionPoint()
238 OSL_PRECOND( m_refCount == 0, "OWeakObject::disposeWeakConnectionPoint: only to be called with a ref count of 0!" );
239 if (m_pWeakConnectionPoint != nullptr) {
240 OWeakConnectionPoint * const p = m_pWeakConnectionPoint;
241 m_pWeakConnectionPoint = nullptr;
242 try {
243 p->dispose();
245 catch (RuntimeException const& exc) {
246 SAL_WARN( "cppuhelper", exc );
248 p->release();
252 OWeakObject::~OWeakObject() COVERITY_NOEXCEPT_FALSE
256 // XWeak
257 Reference< XAdapter > SAL_CALL OWeakObject::queryAdapter()
259 if (!m_pWeakConnectionPoint)
261 // only acquire mutex if member is not created
262 MutexGuard aGuard( getWeakMutex() );
263 if( !m_pWeakConnectionPoint )
265 OWeakConnectionPoint * p = new OWeakConnectionPoint(this);
266 p->acquire();
267 m_pWeakConnectionPoint = p;
271 return m_pWeakConnectionPoint;
275 //-- OWeakAggObject ----------------------------------------------------
277 OWeakAggObject::~OWeakAggObject()
281 // XInterface
282 void OWeakAggObject::acquire() throw()
284 Reference<XInterface > x( xDelegator );
285 if (x.is())
286 x->acquire();
287 else
288 OWeakObject::acquire();
291 // XInterface
292 void OWeakAggObject::release() throw()
294 Reference<XInterface > x( xDelegator );
295 if (x.is())
296 x->release();
297 else
298 OWeakObject::release();
301 // XInterface
302 Any OWeakAggObject::queryInterface( const Type & rType )
304 Reference< XInterface > x( xDelegator ); // harden ref
305 return (x.is() ? x->queryInterface( rType ) : queryAggregation( rType ));
308 // XAggregation
309 Any OWeakAggObject::queryAggregation( const Type & rType )
311 return ::cppu::queryInterface(
312 rType,
313 static_cast< XInterface * >( static_cast< OWeakObject * >( this ) ),
314 static_cast< XAggregation * >( this ),
315 static_cast< XWeak * >( this ) );
318 // XAggregation
319 void OWeakAggObject::setDelegator( const Reference<XInterface > & rDelegator )
321 xDelegator = rDelegator;
326 /** */ //for docpp
327 namespace com
329 /** */ //for docpp
330 namespace sun
332 /** */ //for docpp
333 namespace star
335 /** */ //for docpp
336 namespace uno
340 //-- OWeakRefListener -----------------------------------------------------
342 class OWeakRefListener: public XReference
344 public:
345 explicit OWeakRefListener(const Reference< XInterface >& xInt);
346 virtual ~OWeakRefListener();
348 // noncopyable
349 OWeakRefListener(const OWeakRefListener&) = delete;
350 const OWeakRefListener& operator=(const OWeakRefListener&) = delete;
352 // XInterface
353 Any SAL_CALL queryInterface( const Type & rType ) override;
354 void SAL_CALL acquire() throw() override;
355 void SAL_CALL release() throw() override;
357 // XReference
358 void SAL_CALL dispose() override;
360 /// The reference counter.
361 oslInterlockedCount m_aRefCount;
362 /// The connection point of the weak object, guarded by getWeakMutex()
363 Reference< XAdapter > m_XWeakConnectionPoint;
366 OWeakRefListener::OWeakRefListener(const Reference< XInterface >& xInt)
367 : m_aRefCount( 1 )
371 Reference< XWeak > xWeak( Reference< XWeak >::query( xInt ) );
373 if (xWeak.is())
375 m_XWeakConnectionPoint = xWeak->queryAdapter();
377 if (m_XWeakConnectionPoint.is())
379 m_XWeakConnectionPoint->addReference(static_cast<XReference*>(this));
383 catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected()
384 osl_atomic_decrement( &m_aRefCount );
387 OWeakRefListener::~OWeakRefListener()
391 if (m_XWeakConnectionPoint.is())
393 acquire(); // don't die again
394 m_XWeakConnectionPoint->removeReference(static_cast<XReference*>(this));
397 catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected()
400 // XInterface
401 Any SAL_CALL OWeakRefListener::queryInterface( const Type & rType )
403 return ::cppu::queryInterface(
404 rType, static_cast< XReference * >( this ), static_cast< XInterface * >( this ) );
407 // XInterface
408 void SAL_CALL OWeakRefListener::acquire() throw()
410 osl_atomic_increment( &m_aRefCount );
413 // XInterface
414 void SAL_CALL OWeakRefListener::release() throw()
416 if( ! osl_atomic_decrement( &m_aRefCount ) )
417 delete this;
420 void SAL_CALL OWeakRefListener::dispose()
422 Reference< XAdapter > xAdp;
424 MutexGuard guard(cppu::getWeakMutex());
425 if( m_XWeakConnectionPoint.is() )
427 xAdp = m_XWeakConnectionPoint;
428 m_XWeakConnectionPoint.clear();
432 if( xAdp.is() )
433 xAdp->removeReference(static_cast<XReference*>(this));
437 //-- WeakReferenceHelper ----------------------------------------------------------
439 WeakReferenceHelper::WeakReferenceHelper(const Reference< XInterface >& xInt)
440 : m_pImpl( nullptr )
442 if (xInt.is())
444 m_pImpl = new OWeakRefListener(xInt);
445 m_pImpl->acquire();
449 WeakReferenceHelper::WeakReferenceHelper(const WeakReferenceHelper& rWeakRef)
450 : m_pImpl( nullptr )
452 Reference< XInterface > xInt( rWeakRef.get() );
453 if (xInt.is())
455 m_pImpl = new OWeakRefListener(xInt);
456 m_pImpl->acquire();
460 void WeakReferenceHelper::clear()
464 if (m_pImpl)
466 m_pImpl->dispose();
467 m_pImpl->release();
468 m_pImpl = nullptr;
471 catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected()
474 WeakReferenceHelper& WeakReferenceHelper::operator=(const WeakReferenceHelper& rWeakRef)
476 if (this == &rWeakRef)
478 return *this;
480 Reference< XInterface > xInt( rWeakRef.get() );
481 return operator = ( xInt );
484 WeakReferenceHelper & WeakReferenceHelper::operator =(
485 WeakReferenceHelper && other)
487 clear();
488 std::swap(m_pImpl, other.m_pImpl);
489 return *this;
492 WeakReferenceHelper & SAL_CALL
493 WeakReferenceHelper::operator= (const Reference< XInterface > & xInt)
497 clear();
498 if (xInt.is())
500 m_pImpl = new OWeakRefListener(xInt);
501 m_pImpl->acquire();
504 catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected()
505 return *this;
508 WeakReferenceHelper::~WeakReferenceHelper()
510 clear();
513 Reference< XInterface > WeakReferenceHelper::get() const
517 Reference< XAdapter > xAdp;
519 // must lock to access m_XWeakConnectionPoint
520 MutexGuard guard(cppu::getWeakMutex());
521 if( m_pImpl && m_pImpl->m_XWeakConnectionPoint.is() )
522 xAdp = m_pImpl->m_XWeakConnectionPoint;
525 if (xAdp.is())
526 return xAdp->queryAdapted();
528 catch (RuntimeException &)
530 OSL_ASSERT( false );
531 } // assert here, but no unexpected()
533 return Reference< XInterface >();
541 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */