nss: makefile bitrot: no need for android spcial case anymore
[LibreOffice.git] / cppuhelper / source / weak.cxx
bloba11e52bbbb7842a547e478425a0041dc74c7399b
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>
21 #include <sal/log.hxx>
23 #include <osl/diagnose.h>
24 #include <osl/mutex.hxx>
25 #include <cppuhelper/weakagg.hxx>
26 #include <cppuhelper/exc_hlp.hxx>
27 #include <cppuhelper/queryinterface.hxx>
29 #include <com/sun/star/lang/DisposedException.hpp>
31 #include <algorithm>
32 #include <vector>
34 using namespace osl;
35 using namespace com::sun::star::uno;
37 /** */ //for docpp
38 namespace cppu
41 // due to static Reflection destruction from usr, there must be a mutex leak (#73272#)
42 // this is used to lock all instances of OWeakConnectionPoint and OWeakRefListener as well as OWeakObject::m_pWeakConnectionPoint
43 static Mutex & getWeakMutex()
45 static Mutex * s_pMutex = new Mutex();
46 return *s_pMutex;
50 //-- OWeakConnectionPoint ----------------------------------------------------
52 class OWeakConnectionPoint: public XAdapter
54 public:
55 /**
56 Hold the weak object without an acquire (only the pointer).
58 explicit OWeakConnectionPoint( OWeakObject* pObj )
59 : m_aRefCount( 0 )
60 , m_pObject(pObj)
63 // noncopyable
64 OWeakConnectionPoint(const OWeakConnectionPoint&) = delete;
65 const OWeakConnectionPoint& operator=(const OWeakConnectionPoint&) = delete;
67 // XInterface
68 Any SAL_CALL queryInterface( const Type & rType ) override;
69 void SAL_CALL acquire() throw() override;
70 void SAL_CALL release() throw() override;
72 // XAdapter
73 css::uno::Reference< css::uno::XInterface > SAL_CALL queryAdapted() override;
74 void SAL_CALL addReference( const css::uno::Reference< css::uno::XReference >& xRef ) override;
75 void SAL_CALL removeReference( const css::uno::Reference< css::uno::XReference >& xRef ) override;
77 /// Called from the weak object if the reference count goes to zero.
78 ///
79 /// @throws css::uno::RuntimeException
80 void dispose();
82 private:
83 virtual ~OWeakConnectionPoint() {}
85 /// The reference counter.
86 oslInterlockedCount m_aRefCount;
87 /// The weak object
88 OWeakObject* m_pObject;
89 /// The container to hold the weak references
90 std::vector<Reference<XReference>> m_aReferences;
93 // XInterface
94 Any SAL_CALL OWeakConnectionPoint::queryInterface( const Type & rType )
96 return ::cppu::queryInterface(
97 rType, static_cast< XAdapter * >( this ), static_cast< XInterface * >( this ) );
100 // XInterface
101 void SAL_CALL OWeakConnectionPoint::acquire() throw()
103 osl_atomic_increment( &m_aRefCount );
106 // XInterface
107 void SAL_CALL OWeakConnectionPoint::release() throw()
109 if (! osl_atomic_decrement( &m_aRefCount ))
110 delete this;
113 void OWeakConnectionPoint::dispose()
115 std::vector<Reference<XReference>> aCopy;
116 { // only hold the mutex while we access the field
117 MutexGuard aGuard(getWeakMutex());
118 // OWeakObject is not the only owner of this, so clear m_pObject
119 // so that queryAdapted() won't use it now that it's dead
120 m_pObject = nullptr;
121 // other code is going to call removeReference while we are doing this, so we need a
122 // copy, but since we are disposing and going away, we can just take the original data
123 aCopy.swap(m_aReferences);
125 Any ex;
126 for (const Reference<XReference> & i : aCopy )
130 i->dispose();
132 catch (css::lang::DisposedException &) {}
133 catch (RuntimeException &)
135 ex = cppu::getCaughtException();
138 if (ex.hasValue())
140 cppu::throwException(ex);
144 // XInterface
145 Reference< XInterface > SAL_CALL OWeakConnectionPoint::queryAdapted()
147 Reference< XInterface > ret;
149 ClearableMutexGuard guard(getWeakMutex());
151 if (m_pObject)
153 oslInterlockedCount n = osl_atomic_increment( &m_pObject->m_refCount );
155 if (n > 1)
157 // The reference is incremented. The object cannot be destroyed.
158 // Release the guard at the earliest point.
159 guard.clear();
160 // WeakObject has a (XInterface *) cast operator
161 ret = *m_pObject;
162 osl_atomic_decrement( &m_pObject->m_refCount );
164 else
165 // Another thread wait in the dispose method at the guard
166 osl_atomic_decrement( &m_pObject->m_refCount );
169 return ret;
172 // XInterface
173 void SAL_CALL OWeakConnectionPoint::addReference(const Reference< XReference >& rRef)
175 MutexGuard aGuard(getWeakMutex());
176 m_aReferences.push_back( rRef );
179 // XInterface
180 void SAL_CALL OWeakConnectionPoint::removeReference(const Reference< XReference >& rRef)
182 MutexGuard aGuard(getWeakMutex());
183 // Search from end because the thing that last added a ref is most likely to be the
184 // first to remove a ref.
185 // It's not really valid to compare the pointer directly, but it's faster.
186 auto it = std::find_if(m_aReferences.rbegin(), m_aReferences.rend(),
187 [&rRef](const Reference<XReference>& rxRef) { return rxRef.get() == rRef.get(); });
188 if (it != m_aReferences.rend()) {
189 m_aReferences.erase( it.base()-1 );
190 return;
192 // interface not found, use the correct compare method
193 it = std::find(m_aReferences.rbegin(), m_aReferences.rend(), rRef);
194 if ( it != m_aReferences.rend() )
195 m_aReferences.erase( it.base()-1 );
199 //-- OWeakObject -------------------------------------------------------
202 #ifdef _MSC_VER
203 // Accidentally occurs in msvc mapfile = > had to be outlined.
204 OWeakObject::OWeakObject()
205 : m_refCount( 0 ),
206 m_pWeakConnectionPoint( nullptr )
209 #endif
211 // XInterface
212 Any SAL_CALL OWeakObject::queryInterface( const Type & rType )
214 return ::cppu::queryInterface(
215 rType,
216 static_cast< XWeak * >( this ), static_cast< XInterface * >( this ) );
219 // XInterface
220 void SAL_CALL OWeakObject::acquire() throw()
222 osl_atomic_increment( &m_refCount );
225 // XInterface
226 void SAL_CALL OWeakObject::release() throw()
228 if (osl_atomic_decrement( &m_refCount ) == 0) {
229 // notify/clear all weak-refs before object's dtor is executed
230 // (which may check weak-refs to this object):
231 disposeWeakConnectionPoint();
232 // destroy object:
233 delete this;
237 void OWeakObject::disposeWeakConnectionPoint()
239 OSL_PRECOND( m_refCount == 0, "OWeakObject::disposeWeakConnectionPoint: only to be called with a ref count of 0!" );
240 if (m_pWeakConnectionPoint != nullptr) {
241 OWeakConnectionPoint * const p = m_pWeakConnectionPoint;
242 m_pWeakConnectionPoint = nullptr;
243 try {
244 p->dispose();
246 catch (RuntimeException const& exc) {
247 SAL_WARN( "cppuhelper", exc );
249 p->release();
253 OWeakObject::~OWeakObject() COVERITY_NOEXCEPT_FALSE
257 // XWeak
258 Reference< XAdapter > SAL_CALL OWeakObject::queryAdapter()
260 if (!m_pWeakConnectionPoint)
262 // only acquire mutex if member is not created
263 MutexGuard aGuard( getWeakMutex() );
264 if( !m_pWeakConnectionPoint )
266 OWeakConnectionPoint * p = new OWeakConnectionPoint(this);
267 p->acquire();
268 m_pWeakConnectionPoint = p;
272 return m_pWeakConnectionPoint;
276 //-- OWeakAggObject ----------------------------------------------------
278 OWeakAggObject::~OWeakAggObject()
282 // XInterface
283 void OWeakAggObject::acquire() throw()
285 Reference<XInterface > x( xDelegator );
286 if (x.is())
287 x->acquire();
288 else
289 OWeakObject::acquire();
292 // XInterface
293 void OWeakAggObject::release() throw()
295 Reference<XInterface > x( xDelegator );
296 if (x.is())
297 x->release();
298 else
299 OWeakObject::release();
302 // XInterface
303 Any OWeakAggObject::queryInterface( const Type & rType )
305 Reference< XInterface > x( xDelegator ); // harden ref
306 return (x.is() ? x->queryInterface( rType ) : queryAggregation( rType ));
309 // XAggregation
310 Any OWeakAggObject::queryAggregation( const Type & rType )
312 return ::cppu::queryInterface(
313 rType,
314 static_cast< XInterface * >( static_cast< OWeakObject * >( this ) ),
315 static_cast< XAggregation * >( this ),
316 static_cast< XWeak * >( this ) );
319 // XAggregation
320 void OWeakAggObject::setDelegator( const Reference<XInterface > & rDelegator )
322 xDelegator = rDelegator;
327 /** */ //for docpp
328 namespace com::sun::star::uno
332 //-- OWeakRefListener -----------------------------------------------------
334 class OWeakRefListener final : public XReference
336 public:
337 explicit OWeakRefListener(const Reference< XInterface >& xInt);
338 virtual ~OWeakRefListener();
340 // noncopyable
341 OWeakRefListener(const OWeakRefListener&) = delete;
342 const OWeakRefListener& operator=(const OWeakRefListener&) = delete;
344 // XInterface
345 Any SAL_CALL queryInterface( const Type & rType ) override;
346 void SAL_CALL acquire() throw() override;
347 void SAL_CALL release() throw() override;
349 // XReference
350 void SAL_CALL dispose() override;
352 /// The reference counter.
353 oslInterlockedCount m_aRefCount;
354 /// The connection point of the weak object, guarded by getWeakMutex()
355 Reference< XAdapter > m_XWeakConnectionPoint;
358 OWeakRefListener::OWeakRefListener(const Reference< XInterface >& xInt)
359 : m_aRefCount( 1 )
363 Reference< XWeak > xWeak( Reference< XWeak >::query( xInt ) );
365 if (xWeak.is())
367 m_XWeakConnectionPoint = xWeak->queryAdapter();
369 if (m_XWeakConnectionPoint.is())
371 m_XWeakConnectionPoint->addReference(static_cast<XReference*>(this));
375 catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected()
376 osl_atomic_decrement( &m_aRefCount );
379 OWeakRefListener::~OWeakRefListener()
383 if (m_XWeakConnectionPoint.is())
385 acquire(); // don't die again
386 m_XWeakConnectionPoint->removeReference(static_cast<XReference*>(this));
389 catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected()
392 // XInterface
393 Any SAL_CALL OWeakRefListener::queryInterface( const Type & rType )
395 return ::cppu::queryInterface(
396 rType, static_cast< XReference * >( this ), static_cast< XInterface * >( this ) );
399 // XInterface
400 void SAL_CALL OWeakRefListener::acquire() throw()
402 osl_atomic_increment( &m_aRefCount );
405 // XInterface
406 void SAL_CALL OWeakRefListener::release() throw()
408 if( ! osl_atomic_decrement( &m_aRefCount ) )
409 delete this;
412 void SAL_CALL OWeakRefListener::dispose()
414 Reference< XAdapter > xAdp;
416 MutexGuard guard(cppu::getWeakMutex());
417 if( m_XWeakConnectionPoint.is() )
419 xAdp = m_XWeakConnectionPoint;
420 m_XWeakConnectionPoint.clear();
424 if( xAdp.is() )
425 xAdp->removeReference(static_cast<XReference*>(this));
429 //-- WeakReferenceHelper ----------------------------------------------------------
431 WeakReferenceHelper::WeakReferenceHelper(const Reference< XInterface >& xInt)
432 : m_pImpl( nullptr )
434 if (xInt.is())
436 m_pImpl = new OWeakRefListener(xInt);
437 m_pImpl->acquire();
441 WeakReferenceHelper::WeakReferenceHelper(const WeakReferenceHelper& rWeakRef)
442 : m_pImpl( nullptr )
444 Reference< XInterface > xInt( rWeakRef.get() );
445 if (xInt.is())
447 m_pImpl = new OWeakRefListener(xInt);
448 m_pImpl->acquire();
452 void WeakReferenceHelper::clear()
456 if (m_pImpl)
458 m_pImpl->dispose();
459 m_pImpl->release();
460 m_pImpl = nullptr;
463 catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected()
466 WeakReferenceHelper& WeakReferenceHelper::operator=(const WeakReferenceHelper& rWeakRef)
468 if (this == &rWeakRef)
470 return *this;
472 Reference< XInterface > xInt( rWeakRef.get() );
473 return operator = ( xInt );
476 WeakReferenceHelper & WeakReferenceHelper::operator =(
477 WeakReferenceHelper && other)
479 clear();
480 std::swap(m_pImpl, other.m_pImpl);
481 return *this;
484 WeakReferenceHelper & SAL_CALL
485 WeakReferenceHelper::operator= (const Reference< XInterface > & xInt)
489 clear();
490 if (xInt.is())
492 m_pImpl = new OWeakRefListener(xInt);
493 m_pImpl->acquire();
496 catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected()
497 return *this;
500 WeakReferenceHelper::~WeakReferenceHelper()
502 clear();
505 Reference< XInterface > WeakReferenceHelper::get() const
509 Reference< XAdapter > xAdp;
511 // must lock to access m_XWeakConnectionPoint
512 MutexGuard guard(cppu::getWeakMutex());
513 if( m_pImpl && m_pImpl->m_XWeakConnectionPoint.is() )
514 xAdp = m_pImpl->m_XWeakConnectionPoint;
517 if (xAdp.is())
518 return xAdp->queryAdapted();
520 catch (RuntimeException &)
522 OSL_ASSERT( false );
523 } // assert here, but no unexpected()
525 return Reference< XInterface >();
530 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */