1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
35 using namespace com::sun::star::uno
;
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();
50 //-- OWeakConnectionPoint ----------------------------------------------------
52 class OWeakConnectionPoint
: public XAdapter
56 Hold the weak object without an acquire (only the pointer).
58 explicit OWeakConnectionPoint( OWeakObject
* pObj
)
64 OWeakConnectionPoint(const OWeakConnectionPoint
&) = delete;
65 const OWeakConnectionPoint
& operator=(const OWeakConnectionPoint
&) = delete;
68 Any SAL_CALL
queryInterface( const Type
& rType
) override
;
69 void SAL_CALL
acquire() throw() override
;
70 void SAL_CALL
release() throw() override
;
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.
79 /// @throws css::uno::RuntimeException
83 virtual ~OWeakConnectionPoint() {}
85 /// The reference counter.
86 oslInterlockedCount m_aRefCount
;
88 OWeakObject
* m_pObject
;
89 /// The container to hold the weak references
90 std::vector
<Reference
<XReference
>> m_aReferences
;
94 Any SAL_CALL
OWeakConnectionPoint::queryInterface( const Type
& rType
)
96 return ::cppu::queryInterface(
97 rType
, static_cast< XAdapter
* >( this ), static_cast< XInterface
* >( this ) );
101 void SAL_CALL
OWeakConnectionPoint::acquire() throw()
103 osl_atomic_increment( &m_aRefCount
);
107 void SAL_CALL
OWeakConnectionPoint::release() throw()
109 if (! osl_atomic_decrement( &m_aRefCount
))
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
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
);
126 for (const Reference
<XReference
> & i
: aCopy
)
132 catch (css::lang::DisposedException
&) {}
133 catch (RuntimeException
&)
135 ex
= cppu::getCaughtException();
140 cppu::throwException(ex
);
145 Reference
< XInterface
> SAL_CALL
OWeakConnectionPoint::queryAdapted()
147 Reference
< XInterface
> ret
;
149 ClearableMutexGuard
guard(getWeakMutex());
153 oslInterlockedCount n
= osl_atomic_increment( &m_pObject
->m_refCount
);
157 // The reference is incremented. The object cannot be destroyed.
158 // Release the guard at the earliest point.
160 // WeakObject has a (XInterface *) cast operator
162 osl_atomic_decrement( &m_pObject
->m_refCount
);
165 // Another thread wait in the dispose method at the guard
166 osl_atomic_decrement( &m_pObject
->m_refCount
);
173 void SAL_CALL
OWeakConnectionPoint::addReference(const Reference
< XReference
>& rRef
)
175 MutexGuard
aGuard(getWeakMutex());
176 m_aReferences
.push_back( rRef
);
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 );
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 -------------------------------------------------------
203 // Accidentally occurs in msvc mapfile = > had to be outlined.
204 OWeakObject::OWeakObject()
206 m_pWeakConnectionPoint( nullptr )
212 Any SAL_CALL
OWeakObject::queryInterface( const Type
& rType
)
214 return ::cppu::queryInterface(
216 static_cast< XWeak
* >( this ), static_cast< XInterface
* >( this ) );
220 void SAL_CALL
OWeakObject::acquire() throw()
222 osl_atomic_increment( &m_refCount
);
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();
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;
246 catch (RuntimeException
const& exc
) {
247 SAL_WARN( "cppuhelper", exc
);
253 OWeakObject::~OWeakObject() COVERITY_NOEXCEPT_FALSE
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);
268 m_pWeakConnectionPoint
= p
;
272 return m_pWeakConnectionPoint
;
276 //-- OWeakAggObject ----------------------------------------------------
278 OWeakAggObject::~OWeakAggObject()
283 void OWeakAggObject::acquire() throw()
285 Reference
<XInterface
> x( xDelegator
);
289 OWeakObject::acquire();
293 void OWeakAggObject::release() throw()
295 Reference
<XInterface
> x( xDelegator
);
299 OWeakObject::release();
303 Any
OWeakAggObject::queryInterface( const Type
& rType
)
305 Reference
< XInterface
> x( xDelegator
); // harden ref
306 return (x
.is() ? x
->queryInterface( rType
) : queryAggregation( rType
));
310 Any
OWeakAggObject::queryAggregation( const Type
& rType
)
312 return ::cppu::queryInterface(
314 static_cast< XInterface
* >( static_cast< OWeakObject
* >( this ) ),
315 static_cast< XAggregation
* >( this ),
316 static_cast< XWeak
* >( this ) );
320 void OWeakAggObject::setDelegator( const Reference
<XInterface
> & rDelegator
)
322 xDelegator
= rDelegator
;
328 namespace com::sun::star::uno
332 //-- OWeakRefListener -----------------------------------------------------
334 class OWeakRefListener final
: public XReference
337 explicit OWeakRefListener(const Reference
< XInterface
>& xInt
);
338 virtual ~OWeakRefListener();
341 OWeakRefListener(const OWeakRefListener
&) = delete;
342 const OWeakRefListener
& operator=(const OWeakRefListener
&) = delete;
345 Any SAL_CALL
queryInterface( const Type
& rType
) override
;
346 void SAL_CALL
acquire() throw() override
;
347 void SAL_CALL
release() throw() override
;
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
)
363 Reference
< XWeak
> xWeak( Reference
< XWeak
>::query( xInt
) );
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()
393 Any SAL_CALL
OWeakRefListener::queryInterface( const Type
& rType
)
395 return ::cppu::queryInterface(
396 rType
, static_cast< XReference
* >( this ), static_cast< XInterface
* >( this ) );
400 void SAL_CALL
OWeakRefListener::acquire() throw()
402 osl_atomic_increment( &m_aRefCount
);
406 void SAL_CALL
OWeakRefListener::release() throw()
408 if( ! osl_atomic_decrement( &m_aRefCount
) )
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();
425 xAdp
->removeReference(static_cast<XReference
*>(this));
429 //-- WeakReferenceHelper ----------------------------------------------------------
431 WeakReferenceHelper::WeakReferenceHelper(const Reference
< XInterface
>& xInt
)
436 m_pImpl
= new OWeakRefListener(xInt
);
441 WeakReferenceHelper::WeakReferenceHelper(const WeakReferenceHelper
& rWeakRef
)
444 Reference
< XInterface
> xInt( rWeakRef
.get() );
447 m_pImpl
= new OWeakRefListener(xInt
);
452 void WeakReferenceHelper::clear()
463 catch (RuntimeException
&) { OSL_ASSERT( false ); } // assert here, but no unexpected()
466 WeakReferenceHelper
& WeakReferenceHelper::operator=(const WeakReferenceHelper
& rWeakRef
)
468 if (this == &rWeakRef
)
472 Reference
< XInterface
> xInt( rWeakRef
.get() );
473 return operator = ( xInt
);
476 WeakReferenceHelper
& WeakReferenceHelper::operator =(
477 WeakReferenceHelper
&& other
)
480 std::swap(m_pImpl
, other
.m_pImpl
);
484 WeakReferenceHelper
& SAL_CALL
485 WeakReferenceHelper::operator= (const Reference
< XInterface
> & xInt
)
492 m_pImpl
= new OWeakRefListener(xInt
);
496 catch (RuntimeException
&) { OSL_ASSERT( false ); } // assert here, but no unexpected()
500 WeakReferenceHelper::~WeakReferenceHelper()
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
;
518 return xAdp
->queryAdapted();
520 catch (RuntimeException
&)
523 } // assert here, but no unexpected()
525 return Reference
< XInterface
>();
530 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */