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>
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>
32 using namespace com::sun::star::uno
;
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;
44 s_pMutex
= new Mutex();
49 //-- OWeakConnectionPoint ----------------------------------------------------
51 class OWeakConnectionPoint
: public XAdapter
55 Hold the weak object without an acquire (only the pointer).
57 explicit OWeakConnectionPoint( OWeakObject
* pObj
)
63 OWeakConnectionPoint(const OWeakConnectionPoint
&) = delete;
64 const OWeakConnectionPoint
& operator=(const OWeakConnectionPoint
&) = delete;
67 Any SAL_CALL
queryInterface( const Type
& rType
) override
;
68 void SAL_CALL
acquire() throw() override
;
69 void SAL_CALL
release() throw() override
;
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.
78 /// @throws css::uno::RuntimeException
82 virtual ~OWeakConnectionPoint() {}
84 /// The reference counter.
85 oslInterlockedCount m_aRefCount
;
87 OWeakObject
* m_pObject
;
88 /// The container to hold the weak references
89 std::vector
<Reference
<XReference
>> m_aReferences
;
93 Any SAL_CALL
OWeakConnectionPoint::queryInterface( const Type
& rType
)
95 return ::cppu::queryInterface(
96 rType
, static_cast< XAdapter
* >( this ), static_cast< XInterface
* >( this ) );
100 void SAL_CALL
OWeakConnectionPoint::acquire() throw()
102 osl_atomic_increment( &m_aRefCount
);
106 void SAL_CALL
OWeakConnectionPoint::release() throw()
108 if (! osl_atomic_decrement( &m_aRefCount
))
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
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
);
125 for (const Reference
<XReference
> & i
: aCopy
)
131 catch (css::lang::DisposedException
&) {}
132 catch (RuntimeException
&)
134 ex
= cppu::getCaughtException();
139 cppu::throwException(ex
);
144 Reference
< XInterface
> SAL_CALL
OWeakConnectionPoint::queryAdapted()
146 Reference
< XInterface
> ret
;
148 ClearableMutexGuard
guard(getWeakMutex());
152 oslInterlockedCount n
= osl_atomic_increment( &m_pObject
->m_refCount
);
156 // The reference is incremented. The object cannot be destroyed.
157 // Release the guard at the earliest point.
159 // WeakObject has a (XInterface *) cast operator
161 osl_atomic_decrement( &m_pObject
->m_refCount
);
164 // Another thread wait in the dispose method at the guard
165 osl_atomic_decrement( &m_pObject
->m_refCount
);
172 void SAL_CALL
OWeakConnectionPoint::addReference(const Reference
< XReference
>& rRef
)
174 MutexGuard
aGuard(getWeakMutex());
175 m_aReferences
.push_back( rRef
);
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 );
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 -------------------------------------------------------
202 // Accidentally occurs in msvc mapfile = > had to be outlined.
203 OWeakObject::OWeakObject()
205 m_pWeakConnectionPoint( nullptr )
211 Any SAL_CALL
OWeakObject::queryInterface( const Type
& rType
)
213 return ::cppu::queryInterface(
215 static_cast< XWeak
* >( this ), static_cast< XInterface
* >( this ) );
219 void SAL_CALL
OWeakObject::acquire() throw()
221 osl_atomic_increment( &m_refCount
);
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();
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;
245 catch (RuntimeException
const& exc
) {
246 SAL_WARN( "cppuhelper", exc
);
252 OWeakObject::~OWeakObject() COVERITY_NOEXCEPT_FALSE
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);
267 m_pWeakConnectionPoint
= p
;
271 return m_pWeakConnectionPoint
;
275 //-- OWeakAggObject ----------------------------------------------------
277 OWeakAggObject::~OWeakAggObject()
282 void OWeakAggObject::acquire() throw()
284 Reference
<XInterface
> x( xDelegator
);
288 OWeakObject::acquire();
292 void OWeakAggObject::release() throw()
294 Reference
<XInterface
> x( xDelegator
);
298 OWeakObject::release();
302 Any
OWeakAggObject::queryInterface( const Type
& rType
)
304 Reference
< XInterface
> x( xDelegator
); // harden ref
305 return (x
.is() ? x
->queryInterface( rType
) : queryAggregation( rType
));
309 Any
OWeakAggObject::queryAggregation( const Type
& rType
)
311 return ::cppu::queryInterface(
313 static_cast< XInterface
* >( static_cast< OWeakObject
* >( this ) ),
314 static_cast< XAggregation
* >( this ),
315 static_cast< XWeak
* >( this ) );
319 void OWeakAggObject::setDelegator( const Reference
<XInterface
> & rDelegator
)
321 xDelegator
= rDelegator
;
340 //-- OWeakRefListener -----------------------------------------------------
342 class OWeakRefListener
: public XReference
345 explicit OWeakRefListener(const Reference
< XInterface
>& xInt
);
346 virtual ~OWeakRefListener();
349 OWeakRefListener(const OWeakRefListener
&) = delete;
350 const OWeakRefListener
& operator=(const OWeakRefListener
&) = delete;
353 Any SAL_CALL
queryInterface( const Type
& rType
) override
;
354 void SAL_CALL
acquire() throw() override
;
355 void SAL_CALL
release() throw() override
;
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
)
371 Reference
< XWeak
> xWeak( Reference
< XWeak
>::query( xInt
) );
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()
401 Any SAL_CALL
OWeakRefListener::queryInterface( const Type
& rType
)
403 return ::cppu::queryInterface(
404 rType
, static_cast< XReference
* >( this ), static_cast< XInterface
* >( this ) );
408 void SAL_CALL
OWeakRefListener::acquire() throw()
410 osl_atomic_increment( &m_aRefCount
);
414 void SAL_CALL
OWeakRefListener::release() throw()
416 if( ! osl_atomic_decrement( &m_aRefCount
) )
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();
433 xAdp
->removeReference(static_cast<XReference
*>(this));
437 //-- WeakReferenceHelper ----------------------------------------------------------
439 WeakReferenceHelper::WeakReferenceHelper(const Reference
< XInterface
>& xInt
)
444 m_pImpl
= new OWeakRefListener(xInt
);
449 WeakReferenceHelper::WeakReferenceHelper(const WeakReferenceHelper
& rWeakRef
)
452 Reference
< XInterface
> xInt( rWeakRef
.get() );
455 m_pImpl
= new OWeakRefListener(xInt
);
460 void WeakReferenceHelper::clear()
471 catch (RuntimeException
&) { OSL_ASSERT( false ); } // assert here, but no unexpected()
474 WeakReferenceHelper
& WeakReferenceHelper::operator=(const WeakReferenceHelper
& rWeakRef
)
476 if (this == &rWeakRef
)
480 Reference
< XInterface
> xInt( rWeakRef
.get() );
481 return operator = ( xInt
);
484 WeakReferenceHelper
& WeakReferenceHelper::operator =(
485 WeakReferenceHelper
&& other
)
488 std::swap(m_pImpl
, other
.m_pImpl
);
492 WeakReferenceHelper
& SAL_CALL
493 WeakReferenceHelper::operator= (const Reference
< XInterface
> & xInt
)
500 m_pImpl
= new OWeakRefListener(xInt
);
504 catch (RuntimeException
&) { OSL_ASSERT( false ); } // assert here, but no unexpected()
508 WeakReferenceHelper::~WeakReferenceHelper()
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
;
526 return xAdp
->queryAdapted();
528 catch (RuntimeException
&)
531 } // assert here, but no unexpected()
533 return Reference
< XInterface
>();
541 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */