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 <cppuhelper/weakagg.hxx>
25 #include <cppuhelper/exc_hlp.hxx>
26 #include <cppuhelper/queryinterface.hxx>
28 #include <com/sun/star/lang/DisposedException.hpp>
35 using namespace com::sun::star::uno
;
40 // due to static Reflection destruction from usr, there must be a mutex leak (#73272#)
41 // this is used to lock all instances of OWeakConnectionPoint and OWeakRefListener as well as OWeakObject::m_pWeakConnectionPoint
42 static std::mutex
* gpWeakMutex
= new std::mutex
;
45 //-- OWeakConnectionPoint ----------------------------------------------------
47 class OWeakConnectionPoint
: public XAdapter
51 Hold the weak object without an acquire (only the pointer).
53 explicit OWeakConnectionPoint( OWeakObject
* pObj
)
59 OWeakConnectionPoint(const OWeakConnectionPoint
&) = delete;
60 const OWeakConnectionPoint
& operator=(const OWeakConnectionPoint
&) = delete;
63 Any SAL_CALL
queryInterface( const Type
& rType
) override
;
64 void SAL_CALL
acquire() noexcept override
;
65 void SAL_CALL
release() noexcept override
;
68 css::uno::Reference
< css::uno::XInterface
> SAL_CALL
queryAdapted() override
;
69 void SAL_CALL
addReference( const css::uno::Reference
< css::uno::XReference
>& xRef
) override
;
70 void SAL_CALL
removeReference( const css::uno::Reference
< css::uno::XReference
>& xRef
) override
;
72 /// Called from the weak object if the reference count goes to zero.
74 /// @throws css::uno::RuntimeException
78 virtual ~OWeakConnectionPoint() {}
80 /// The reference counter.
81 oslInterlockedCount m_aRefCount
;
83 OWeakObject
* m_pObject
;
84 /// The container to hold the weak references
85 std::vector
<Reference
<XReference
>> m_aReferences
;
89 Any SAL_CALL
OWeakConnectionPoint::queryInterface( const Type
& rType
)
91 return ::cppu::queryInterface(
92 rType
, static_cast< XAdapter
* >( this ), static_cast< XInterface
* >( this ) );
96 void SAL_CALL
OWeakConnectionPoint::acquire() noexcept
99 // catch things early which have been deleted and then re-acquired
100 assert(m_aRefCount
!= -1);
102 osl_atomic_increment( &m_aRefCount
);
106 void SAL_CALL
OWeakConnectionPoint::release() noexcept
108 if (! osl_atomic_decrement( &m_aRefCount
))
117 void OWeakConnectionPoint::dispose()
119 std::vector
<Reference
<XReference
>> aCopy
;
120 { // only hold the mutex while we access the field
121 std::scoped_lock
aGuard(*cppu::gpWeakMutex
);
122 // OWeakObject is not the only owner of this, so clear m_pObject
123 // so that queryAdapted() won't use it now that it's dead
125 // other code is going to call removeReference while we are doing this, so we need a
126 // copy, but since we are disposing and going away, we can just take the original data
127 aCopy
.swap(m_aReferences
);
130 for (const Reference
<XReference
> & i
: aCopy
)
136 catch (css::lang::DisposedException
&) {}
137 catch (RuntimeException
&)
139 ex
= cppu::getCaughtException();
144 cppu::throwException(ex
);
149 Reference
< XInterface
> SAL_CALL
OWeakConnectionPoint::queryAdapted()
151 Reference
< XInterface
> ret
;
154 std::scoped_lock
guard(*gpWeakMutex
);
159 oslInterlockedCount n
= osl_atomic_increment( &m_pObject
->m_refCount
);
163 // Another thread wait in the dispose method at the guard
164 osl_atomic_decrement( &m_pObject
->m_refCount
);
170 // The reference is incremented. The object cannot be destroyed.
171 // Release the guard at the earliest point.
172 // WeakObject has a (XInterface *) cast operator
174 osl_atomic_decrement( &m_pObject
->m_refCount
);
180 void SAL_CALL
OWeakConnectionPoint::addReference(const Reference
< XReference
>& rRef
)
182 std::scoped_lock
aGuard(*gpWeakMutex
);
183 m_aReferences
.push_back( rRef
);
187 void SAL_CALL
OWeakConnectionPoint::removeReference(const Reference
< XReference
>& rRef
)
189 std::scoped_lock
aGuard(*gpWeakMutex
);
190 // Search from end because the thing that last added a ref is most likely to be the
191 // first to remove a ref.
192 // It's not really valid to compare the pointer directly, but it's faster.
193 auto it
= std::find_if(m_aReferences
.rbegin(), m_aReferences
.rend(),
194 [&rRef
](const Reference
<XReference
>& rxRef
) { return rxRef
.get() == rRef
.get(); });
195 if (it
!= m_aReferences
.rend()) {
196 m_aReferences
.erase( it
.base()-1 );
199 // interface not found, use the correct compare method
200 it
= std::find(m_aReferences
.rbegin(), m_aReferences
.rend(), rRef
);
201 if ( it
!= m_aReferences
.rend() )
202 m_aReferences
.erase( it
.base()-1 );
206 //-- OWeakObject -------------------------------------------------------
209 Any SAL_CALL
OWeakObject::queryInterface( const Type
& rType
)
211 return ::cppu::queryInterface(
213 static_cast< XWeak
* >( this ), static_cast< XInterface
* >( this ) );
217 void SAL_CALL
OWeakObject::acquire() noexcept
219 osl_atomic_increment( &m_refCount
);
223 void SAL_CALL
OWeakObject::release() noexcept
225 if (osl_atomic_decrement( &m_refCount
) == 0) {
226 // notify/clear all weak-refs before object's dtor is executed
227 // (which may check weak-refs to this object):
228 disposeWeakConnectionPoint();
234 void OWeakObject::disposeWeakConnectionPoint()
236 OSL_PRECOND( m_refCount
== 0, "OWeakObject::disposeWeakConnectionPoint: only to be called with a ref count of 0!" );
237 if (m_pWeakConnectionPoint
!= nullptr) {
238 OWeakConnectionPoint
* const p
= m_pWeakConnectionPoint
;
239 m_pWeakConnectionPoint
= nullptr;
243 catch (RuntimeException
const& exc
) {
244 SAL_WARN( "cppuhelper", exc
);
250 OWeakObject::~OWeakObject() COVERITY_NOEXCEPT_FALSE
255 Reference
< XAdapter
> SAL_CALL
OWeakObject::queryAdapter()
257 if (!m_pWeakConnectionPoint
)
259 // only acquire mutex if member is not created
260 std::scoped_lock
aGuard( *gpWeakMutex
);
261 if( !m_pWeakConnectionPoint
)
263 OWeakConnectionPoint
* p
= new OWeakConnectionPoint(this);
265 m_pWeakConnectionPoint
= p
;
269 return m_pWeakConnectionPoint
;
273 //-- OWeakAggObject ----------------------------------------------------
275 OWeakAggObject::~OWeakAggObject()
280 void OWeakAggObject::acquire() noexcept
282 Reference
<XInterface
> x( xDelegator
);
286 OWeakObject::acquire();
290 void OWeakAggObject::release() noexcept
292 Reference
<XInterface
> x( xDelegator
);
296 OWeakObject::release();
300 Any
OWeakAggObject::queryInterface( const Type
& rType
)
302 Reference
< XInterface
> x( xDelegator
); // harden ref
303 return (x
.is() ? x
->queryInterface( rType
) : queryAggregation( rType
));
307 Any
OWeakAggObject::queryAggregation( const Type
& rType
)
309 return ::cppu::queryInterface(
311 static_cast< XInterface
* >( static_cast< OWeakObject
* >( this ) ),
312 static_cast< XAggregation
* >( this ),
313 static_cast< XWeak
* >( this ) );
317 void OWeakAggObject::setDelegator( const Reference
<XInterface
> & rDelegator
)
319 xDelegator
= rDelegator
;
324 namespace com::sun::star::uno
328 //-- OWeakRefListener -----------------------------------------------------
330 class OWeakRefListener final
: public XReference
333 explicit OWeakRefListener(const Reference
< XInterface
>& xInt
);
334 explicit OWeakRefListener(const Reference
< XWeak
>& xInt
);
335 virtual ~OWeakRefListener();
338 OWeakRefListener(const OWeakRefListener
&) = delete;
339 const OWeakRefListener
& operator=(const OWeakRefListener
&) = delete;
342 Any SAL_CALL
queryInterface( const Type
& rType
) override
;
343 void SAL_CALL
acquire() noexcept override
;
344 void SAL_CALL
release() noexcept override
;
347 void SAL_CALL
dispose() override
;
349 /// The reference counter.
350 oslInterlockedCount m_aRefCount
;
351 /// The connection point of the weak object, guarded by getWeakMutex()
352 Reference
< XAdapter
> m_XWeakConnectionPoint
;
355 OWeakRefListener::OWeakRefListener(const Reference
< XInterface
>& xInt
)
360 Reference
< XWeak
> xWeak( Reference
< XWeak
>::query( xInt
) );
364 m_XWeakConnectionPoint
= xWeak
->queryAdapter();
366 if (m_XWeakConnectionPoint
.is())
368 m_XWeakConnectionPoint
->addReference(static_cast<XReference
*>(this));
372 catch (RuntimeException
&) { OSL_ASSERT( false ); } // assert here, but no unexpected()
373 osl_atomic_decrement( &m_aRefCount
);
376 OWeakRefListener::OWeakRefListener(const Reference
< XWeak
>& xWeak
)
379 m_XWeakConnectionPoint
= xWeak
->queryAdapter();
381 if (m_XWeakConnectionPoint
.is())
383 m_XWeakConnectionPoint
->addReference(static_cast<XReference
*>(this));
385 osl_atomic_decrement( &m_aRefCount
);
388 OWeakRefListener::~OWeakRefListener()
392 if (m_XWeakConnectionPoint
.is())
394 acquire(); // don't die again
395 m_XWeakConnectionPoint
->removeReference(static_cast<XReference
*>(this));
398 catch (RuntimeException
&) { OSL_ASSERT( false ); } // assert here, but no unexpected()
402 Any SAL_CALL
OWeakRefListener::queryInterface( const Type
& rType
)
404 return ::cppu::queryInterface(
405 rType
, static_cast< XReference
* >( this ), static_cast< XInterface
* >( this ) );
409 void SAL_CALL
OWeakRefListener::acquire() noexcept
411 osl_atomic_increment( &m_aRefCount
);
415 void SAL_CALL
OWeakRefListener::release() noexcept
417 if( ! osl_atomic_decrement( &m_aRefCount
) )
421 void SAL_CALL
OWeakRefListener::dispose()
423 Reference
< XAdapter
> xAdp
;
425 std::scoped_lock
guard(*cppu::gpWeakMutex
);
426 if( m_XWeakConnectionPoint
.is() )
428 xAdp
= m_XWeakConnectionPoint
;
429 m_XWeakConnectionPoint
.clear();
434 xAdp
->removeReference(static_cast<XReference
*>(this));
438 //-- WeakReferenceHelper ----------------------------------------------------------
440 WeakReferenceHelper::WeakReferenceHelper(const Reference
< XInterface
>& xInt
)
445 m_pImpl
= new OWeakRefListener(xInt
);
450 WeakReferenceHelper::WeakReferenceHelper(const Reference
< XWeak
>& xWeak
)
455 m_pImpl
= new OWeakRefListener(xWeak
);
460 WeakReferenceHelper::WeakReferenceHelper(const WeakReferenceHelper
& rWeakRef
)
463 Reference
< XInterface
> xInt( rWeakRef
.get() );
466 m_pImpl
= new OWeakRefListener(xInt
);
471 void WeakReferenceHelper::clear()
482 catch (RuntimeException
&) { OSL_ASSERT( false ); } // assert here, but no unexpected()
485 WeakReferenceHelper
& WeakReferenceHelper::operator=(const WeakReferenceHelper
& rWeakRef
)
487 if (this == &rWeakRef
)
491 Reference
< XInterface
> xInt( rWeakRef
.get() );
492 return operator = ( xInt
);
495 WeakReferenceHelper
& WeakReferenceHelper::operator =(
496 WeakReferenceHelper
&& other
)
499 std::swap(m_pImpl
, other
.m_pImpl
);
503 WeakReferenceHelper
& SAL_CALL
504 WeakReferenceHelper::operator= (const Reference
< XInterface
> & xInt
)
511 m_pImpl
= new OWeakRefListener(xInt
);
515 catch (RuntimeException
&) { OSL_ASSERT( false ); } // assert here, but no unexpected()
519 WeakReferenceHelper
&
520 WeakReferenceHelper::operator= (const Reference
< XWeak
> & xWeak
)
525 m_pImpl
= new OWeakRefListener(xWeak
);
531 WeakReferenceHelper::~WeakReferenceHelper()
536 Reference
< XInterface
> WeakReferenceHelper::get() const
540 Reference
< XAdapter
> xAdp
;
542 // must lock to access m_XWeakConnectionPoint
543 std::scoped_lock
guard(*cppu::gpWeakMutex
);
544 if( m_pImpl
&& m_pImpl
->m_XWeakConnectionPoint
.is() )
545 xAdp
= m_pImpl
->m_XWeakConnectionPoint
;
549 return xAdp
->queryAdapted();
551 catch (RuntimeException
&)
554 } // assert here, but no unexpected()
556 return Reference
< XInterface
>();
561 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */