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 <osl/mutex.hxx>
21 #include <cppuhelper/weakagg.hxx>
22 #include <cppuhelper/interfacecontainer.hxx>
23 #include "cppuhelper/exc_hlp.hxx"
26 using namespace com::sun::star::uno
;
32 // due to static Reflection destruction from usr, ther must be a mutex leak (#73272#)
33 inline static Mutex
& getWeakMutex() SAL_THROW(())
35 static Mutex
* s_pMutex
= 0;
37 s_pMutex
= new Mutex();
41 //------------------------------------------------------------------------
42 //-- OWeakConnectionPoint ----------------------------------------------------
43 //------------------------------------------------------------------------
44 class OWeakConnectionPoint
: public XAdapter
48 Hold the weak object without an acquire (only the pointer).
50 OWeakConnectionPoint( OWeakObject
* pObj
) SAL_THROW(())
53 , m_aReferences( getWeakMutex() )
57 Any SAL_CALL
queryInterface( const Type
& rType
) throw(::com::sun::star::uno::RuntimeException
);
58 void SAL_CALL
acquire() throw();
59 void SAL_CALL
release() throw();
62 ::com::sun::star::uno::Reference
< ::com::sun::star::uno::XInterface
> SAL_CALL
queryAdapted() throw(::com::sun::star::uno::RuntimeException
);
63 void SAL_CALL
addReference( const ::com::sun::star::uno::Reference
< ::com::sun::star::uno::XReference
>& xRef
) throw(::com::sun::star::uno::RuntimeException
);
64 void SAL_CALL
removeReference( const ::com::sun::star::uno::Reference
< ::com::sun::star::uno::XReference
>& xRef
) throw(::com::sun::star::uno::RuntimeException
);
66 /// Called from the weak object if the reference count goes to zero.
67 void SAL_CALL
dispose() throw(::com::sun::star::uno::RuntimeException
);
70 OWeakConnectionPoint(OWeakConnectionPoint
&); // not defined
71 void operator =(OWeakConnectionPoint
&); // not defined
73 virtual ~OWeakConnectionPoint() {}
75 /// The reference counter.
76 oslInterlockedCount m_aRefCount
;
78 OWeakObject
* m_pObject
;
79 /// The container to hold the weak references
80 OInterfaceContainerHelper m_aReferences
;
84 Any SAL_CALL
OWeakConnectionPoint::queryInterface( const Type
& rType
)
85 throw(com::sun::star::uno::RuntimeException
)
87 return ::cppu::queryInterface(
88 rType
, static_cast< XAdapter
* >( this ), static_cast< XInterface
* >( this ) );
92 void SAL_CALL
OWeakConnectionPoint::acquire() throw()
94 osl_atomic_increment( &m_aRefCount
);
98 void SAL_CALL
OWeakConnectionPoint::release() throw()
100 if (! osl_atomic_decrement( &m_aRefCount
))
104 void SAL_CALL
OWeakConnectionPoint::dispose() throw(::com::sun::star::uno::RuntimeException
)
107 OInterfaceIteratorHelper
aIt( m_aReferences
);
108 while( aIt
.hasMoreElements() )
112 ((XReference
*)aIt
.next())->dispose();
114 catch (com::sun::star::lang::DisposedException
&) {}
115 catch (RuntimeException
&)
117 ex
= cppu::getCaughtException();
122 cppu::throwException(ex
);
127 Reference
< XInterface
> SAL_CALL
OWeakConnectionPoint::queryAdapted() throw(::com::sun::star::uno::RuntimeException
)
129 Reference
< XInterface
> ret
;
131 ClearableMutexGuard
guard(getWeakMutex());
135 oslInterlockedCount n
= osl_atomic_increment( &m_pObject
->m_refCount
);
139 // The refence is incremented. The object cannot be destroyed.
140 // Release the guard at the earliest point.
142 // WeakObject has a (XInterface *) cast operator
144 n
= osl_atomic_decrement( &m_pObject
->m_refCount
);
147 // Another thread wait in the dispose method at the guard
148 n
= osl_atomic_decrement( &m_pObject
->m_refCount
);
155 void SAL_CALL
OWeakConnectionPoint::addReference(const Reference
< XReference
>& rRef
)
156 throw(::com::sun::star::uno::RuntimeException
)
158 m_aReferences
.addInterface( (const Reference
< XInterface
> &)rRef
);
162 void SAL_CALL
OWeakConnectionPoint::removeReference(const Reference
< XReference
>& rRef
)
163 throw(::com::sun::star::uno::RuntimeException
)
165 m_aReferences
.removeInterface( (const Reference
< XInterface
> &)rRef
);
169 //------------------------------------------------------------------------
170 //-- OWeakObject -------------------------------------------------------
171 //------------------------------------------------------------------------
174 // Accidentally occurs in msvc mapfile = > had to be outlined.
175 OWeakObject::OWeakObject() SAL_THROW(())
177 m_pWeakConnectionPoint( 0 )
183 Any SAL_CALL
OWeakObject::queryInterface( const Type
& rType
) throw(::com::sun::star::uno::RuntimeException
)
185 return ::cppu::queryInterface(
187 static_cast< XWeak
* >( this ), static_cast< XInterface
* >( this ) );
191 void SAL_CALL
OWeakObject::acquire() throw()
193 osl_atomic_increment( &m_refCount
);
197 void SAL_CALL
OWeakObject::release() throw()
199 if (osl_atomic_decrement( &m_refCount
) == 0) {
200 // notify/clear all weak-refs before object's dtor is executed
201 // (which may check weak-refs to this object):
202 disposeWeakConnectionPoint();
208 void OWeakObject::disposeWeakConnectionPoint()
210 OSL_PRECOND( m_refCount
== 0, "OWeakObject::disposeWeakConnectionPoint: only to be called with a ref count of 0!" );
211 if (m_pWeakConnectionPoint
!= 0) {
212 OWeakConnectionPoint
* const p
= m_pWeakConnectionPoint
;
213 m_pWeakConnectionPoint
= 0;
217 catch (RuntimeException
const& exc
) {
220 exc
.Message
, RTL_TEXTENCODING_ASCII_US
).getStr() );
221 static_cast<void>(exc
);
227 OWeakObject::~OWeakObject() SAL_THROW( (RuntimeException
) )
232 Reference
< XAdapter
> SAL_CALL
OWeakObject::queryAdapter()
233 throw (::com::sun::star::uno::RuntimeException
)
235 if (!m_pWeakConnectionPoint
)
237 // only acquire mutex if member is not created
238 MutexGuard
aGuard( getWeakMutex() );
239 if( !m_pWeakConnectionPoint
)
241 OWeakConnectionPoint
* p
= new OWeakConnectionPoint(this);
243 m_pWeakConnectionPoint
= p
;
247 return m_pWeakConnectionPoint
;
250 //------------------------------------------------------------------------
251 //-- OWeakAggObject ----------------------------------------------------
252 //------------------------------------------------------------------------
253 OWeakAggObject::~OWeakAggObject() SAL_THROW( (RuntimeException
) )
258 void OWeakAggObject::acquire() throw()
260 Reference
<XInterface
> x( xDelegator
);
264 OWeakObject::acquire();
268 void OWeakAggObject::release() throw()
270 Reference
<XInterface
> x( xDelegator
);
274 OWeakObject::release();
278 Any
OWeakAggObject::queryInterface( const Type
& rType
) throw(::com::sun::star::uno::RuntimeException
)
280 Reference
< XInterface
> x( xDelegator
); // harden ref
281 return (x
.is() ? x
->queryInterface( rType
) : queryAggregation( rType
));
285 Any
OWeakAggObject::queryAggregation( const Type
& rType
) throw(::com::sun::star::uno::RuntimeException
)
287 return ::cppu::queryInterface(
289 static_cast< XInterface
* >( static_cast< OWeakObject
* >( this ) ),
290 static_cast< XAggregation
* >( this ),
291 static_cast< XWeak
* >( this ) );
295 void OWeakAggObject::setDelegator( const Reference
<XInterface
> & rDelegator
) throw(::com::sun::star::uno::RuntimeException
)
297 xDelegator
= rDelegator
;
316 //------------------------------------------------------------------------
317 //-- OWeakRefListener -----------------------------------------------------
318 //------------------------------------------------------------------------
319 class OWeakRefListener
: public XReference
322 OWeakRefListener(const OWeakRefListener
& rRef
) SAL_THROW(());
323 OWeakRefListener(const Reference
< XInterface
>& xInt
) SAL_THROW(());
324 virtual ~OWeakRefListener() SAL_THROW(());
327 Any SAL_CALL
queryInterface( const Type
& rType
) throw(RuntimeException
);
328 void SAL_CALL
acquire() throw();
329 void SAL_CALL
release() throw();
332 void SAL_CALL
dispose() throw(::com::sun::star::uno::RuntimeException
);
334 /// The reference counter.
335 oslInterlockedCount m_aRefCount
;
336 /// The connection point of the weak object
337 Reference
< XAdapter
> m_XWeakConnectionPoint
;
340 OWeakRefListener
& SAL_CALL
operator=(const OWeakRefListener
& rRef
) SAL_THROW(());
343 OWeakRefListener::OWeakRefListener(const OWeakRefListener
& rRef
) SAL_THROW(())
344 : com::sun::star::uno::XReference()
349 m_XWeakConnectionPoint
= rRef
.m_XWeakConnectionPoint
;
351 if (m_XWeakConnectionPoint
.is())
353 m_XWeakConnectionPoint
->addReference((XReference
*)this);
356 catch (RuntimeException
&) { OSL_ASSERT( 0 ); } // assert here, but no unexpected()
357 osl_atomic_decrement( &m_aRefCount
);
360 OWeakRefListener::OWeakRefListener(const Reference
< XInterface
>& xInt
) SAL_THROW(())
365 Reference
< XWeak
> xWeak( Reference
< XWeak
>::query( xInt
) );
369 m_XWeakConnectionPoint
= xWeak
->queryAdapter();
371 if (m_XWeakConnectionPoint
.is())
373 m_XWeakConnectionPoint
->addReference((XReference
*)this);
377 catch (RuntimeException
&) { OSL_ASSERT( 0 ); } // assert here, but no unexpected()
378 osl_atomic_decrement( &m_aRefCount
);
381 OWeakRefListener::~OWeakRefListener() SAL_THROW(())
385 if (m_XWeakConnectionPoint
.is())
387 acquire(); // dont die again
388 m_XWeakConnectionPoint
->removeReference((XReference
*)this);
391 catch (RuntimeException
&) { OSL_ASSERT( 0 ); } // assert here, but no unexpected()
395 Any SAL_CALL
OWeakRefListener::queryInterface( const Type
& rType
) throw(RuntimeException
)
397 return ::cppu::queryInterface(
398 rType
, static_cast< XReference
* >( this ), static_cast< XInterface
* >( this ) );
402 void SAL_CALL
OWeakRefListener::acquire() throw()
404 osl_atomic_increment( &m_aRefCount
);
408 void SAL_CALL
OWeakRefListener::release() throw()
410 if( ! osl_atomic_decrement( &m_aRefCount
) )
414 void SAL_CALL
OWeakRefListener::dispose()
415 throw(::com::sun::star::uno::RuntimeException
)
417 Reference
< XAdapter
> xAdp
;
419 MutexGuard
guard(cppu::getWeakMutex());
420 if( m_XWeakConnectionPoint
.is() )
422 xAdp
= m_XWeakConnectionPoint
;
423 m_XWeakConnectionPoint
.clear();
428 xAdp
->removeReference((XReference
*)this);
431 //------------------------------------------------------------------------
432 //-- WeakReferenceHelper ----------------------------------------------------------
433 //------------------------------------------------------------------------
434 WeakReferenceHelper::WeakReferenceHelper(const Reference
< XInterface
>& xInt
) SAL_THROW(())
439 m_pImpl
= new OWeakRefListener(xInt
);
444 WeakReferenceHelper::WeakReferenceHelper(const WeakReferenceHelper
& rWeakRef
) SAL_THROW(())
447 Reference
< XInterface
> xInt( rWeakRef
.get() );
450 m_pImpl
= new OWeakRefListener(xInt
);
455 void WeakReferenceHelper::clear() SAL_THROW(())
461 if (m_pImpl
->m_XWeakConnectionPoint
.is())
463 m_pImpl
->m_XWeakConnectionPoint
->removeReference(
464 (XReference
*)m_pImpl
);
465 m_pImpl
->m_XWeakConnectionPoint
.clear();
471 catch (RuntimeException
&) { OSL_ASSERT( 0 ); } // assert here, but no unexpected()
474 WeakReferenceHelper
& WeakReferenceHelper::operator=(const WeakReferenceHelper
& rWeakRef
) SAL_THROW(())
476 if (this == &rWeakRef
)
480 Reference
< XInterface
> xInt( rWeakRef
.get() );
481 return operator = ( xInt
);
484 WeakReferenceHelper
& SAL_CALL
485 WeakReferenceHelper::operator= (const Reference
< XInterface
> & xInt
)
493 m_pImpl
= new OWeakRefListener(xInt
);
497 catch (RuntimeException
&) { OSL_ASSERT( 0 ); } // assert here, but no unexpected()
501 WeakReferenceHelper::~WeakReferenceHelper() SAL_THROW(())
506 Reference
< XInterface
> WeakReferenceHelper::get() const SAL_THROW(())
510 Reference
< XAdapter
> xAdp
;
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
&) { OSL_ASSERT( 0 ); } // assert here, but no unexpected()
522 return Reference
< XInterface
>();
530 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */