xref: /trunk/main/cppuhelper/source/weak.cxx (revision cfd52e18)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_cppuhelper.hxx"
26 #include <osl/mutex.hxx>
27 #ifndef _CPPU_WEAKAGG_HXX_
28 #include <cppuhelper/weakagg.hxx>
29 #endif
30 #ifndef _CPPU_HELPER_INTERFACECONTAINER_HXX_
31 #include <cppuhelper/interfacecontainer.hxx>
32 #endif
33 #include "cppuhelper/exc_hlp.hxx"
34 
35 using namespace osl;
36 using namespace com::sun::star::uno;
37 
38 /** */ //for docpp
39 namespace cppu
40 {
41 
42 // due to static Reflection destruction from usr, ther must be a mutex leak (#73272#)
getWeakMutex()43 inline static Mutex & getWeakMutex() SAL_THROW( () )
44 {
45 	static Mutex * s_pMutex = 0;
46 	if (! s_pMutex)
47 		s_pMutex = new Mutex();
48 	return *s_pMutex;
49 }
50 
51 //------------------------------------------------------------------------
52 //-- OWeakConnectionPoint ----------------------------------------------------
53 //------------------------------------------------------------------------
54 class OWeakConnectionPoint : public XAdapter
55 {
56 public:
57 	/**
58 		Hold the weak object without an acquire (only the pointer).
59 	 */
60 	OWeakConnectionPoint( OWeakObject* pObj ) SAL_THROW( () )
61 		: m_aRefCount( 0 )
62 		, m_pObject(pObj)
63 		, m_aReferences( getWeakMutex() )
64 		{}
65 
66 	// XInterface
67 	Any SAL_CALL		queryInterface( const Type & rType ) throw(::com::sun::star::uno::RuntimeException);
68 	void SAL_CALL		acquire() throw();
69 	void SAL_CALL		release() throw();
70 
71 	// XAdapter
72     ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL queryAdapted() throw(::com::sun::star::uno::RuntimeException);
73     void SAL_CALL addReference( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XReference >& xRef ) throw(::com::sun::star::uno::RuntimeException);
74     void SAL_CALL removeReference( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XReference >& xRef ) throw(::com::sun::star::uno::RuntimeException);
75 
76 	/// Called from the weak object if the reference count goes to zero.
77 	void SAL_CALL dispose() throw(::com::sun::star::uno::RuntimeException);
78 
79 private:
80     OWeakConnectionPoint(OWeakConnectionPoint &); // not defined
81     void operator =(OWeakConnectionPoint &); // not defined
82 
~OWeakConnectionPoint()83     virtual ~OWeakConnectionPoint() {}
84 
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 	OInterfaceContainerHelper	m_aReferences;
91 };
92 
93 // XInterface
queryInterface(const Type & rType)94 Any SAL_CALL OWeakConnectionPoint::queryInterface( const Type & rType )
95 	throw(com::sun::star::uno::RuntimeException)
96 {
97 	return ::cppu::queryInterface(
98 		rType, static_cast< XAdapter * >( this ), static_cast< XInterface * >( this ) );
99 }
100 
101 // XInterface
acquire()102 void SAL_CALL OWeakConnectionPoint::acquire() throw()
103 {
104 	osl_incrementInterlockedCount( &m_aRefCount );
105 }
106 
107 // XInterface
release()108 void SAL_CALL OWeakConnectionPoint::release() throw()
109 {
110 	if (! osl_decrementInterlockedCount( &m_aRefCount ))
111 		delete this;
112 }
113 
dispose()114 void SAL_CALL OWeakConnectionPoint::dispose() throw(::com::sun::star::uno::RuntimeException)
115 {
116     Any ex;
117 	OInterfaceIteratorHelper aIt( m_aReferences );
118 	while( aIt.hasMoreElements() )
119     {
120         try
121         {
122             ((XReference *)aIt.next())->dispose();
123         }
124         catch (com::sun::star::lang::DisposedException &) {}
125         catch (RuntimeException &)
126         {
127             ex = cppu::getCaughtException();
128         }
129     }
130     if (ex.hasValue())
131     {
132         cppu::throwException(ex);
133     }
134 }
135 
136 // XInterface
queryAdapted()137 Reference< XInterface > SAL_CALL OWeakConnectionPoint::queryAdapted() throw(::com::sun::star::uno::RuntimeException)
138 {
139 	Reference< XInterface > ret;
140 
141 	ClearableMutexGuard guard(getWeakMutex());
142 
143 	if (m_pObject)
144 	{
145 		oslInterlockedCount n = osl_incrementInterlockedCount( &m_pObject->m_refCount );
146 
147 		if (n > 1)
148 		{
149 			// The refence is incremented. The object cannot be destroyed.
150 			// Release the guard at the earliest point.
151 			guard.clear();
152 			// WeakObject has a (XInterface *) cast operator
153 			ret = *m_pObject;
154 			n = osl_decrementInterlockedCount( &m_pObject->m_refCount );
155 		}
156 		else
157 			// Another thread wait in the dispose method at the guard
158 			n = osl_decrementInterlockedCount( &m_pObject->m_refCount );
159 	}
160 
161 	return ret;
162 }
163 
164 // XInterface
addReference(const Reference<XReference> & rRef)165 void SAL_CALL OWeakConnectionPoint::addReference(const Reference< XReference >& rRef)
166 	throw(::com::sun::star::uno::RuntimeException)
167 {
168 	m_aReferences.addInterface( (const Reference< XInterface > &)rRef );
169 }
170 
171 // XInterface
removeReference(const Reference<XReference> & rRef)172 void SAL_CALL OWeakConnectionPoint::removeReference(const Reference< XReference >& rRef)
173 	throw(::com::sun::star::uno::RuntimeException)
174 {
175 	m_aReferences.removeInterface( (const Reference< XInterface > &)rRef );
176 }
177 
178 
179 //------------------------------------------------------------------------
180 //-- OWeakObject -------------------------------------------------------
181 //------------------------------------------------------------------------
182 
183 #ifdef _MSC_VER
184 // Accidentally occurs in msvc mapfile = > had to be outlined.
OWeakObject()185 OWeakObject::OWeakObject() SAL_THROW( () )
186     : m_refCount( 0 ),
187       m_pWeakConnectionPoint( 0 )
188 {
189 }
190 #endif
191 
192 // XInterface
queryInterface(const Type & rType)193 Any SAL_CALL OWeakObject::queryInterface( const Type & rType ) throw(::com::sun::star::uno::RuntimeException)
194 {
195 	return ::cppu::queryInterface(
196 		rType,
197 		static_cast< XWeak * >( this ), static_cast< XInterface * >( this ) );
198 }
199 
200 // XInterface
acquire()201 void SAL_CALL OWeakObject::acquire() throw()
202 {
203 	osl_incrementInterlockedCount( &m_refCount );
204 }
205 
206 // XInterface
release()207 void SAL_CALL OWeakObject::release() throw()
208 {
209     if (osl_decrementInterlockedCount( &m_refCount ) == 0) {
210         // notify/clear all weak-refs before object's dtor is executed
211         // (which may check weak-refs to this object):
212         disposeWeakConnectionPoint();
213         // destroy object:
214         delete this;
215     }
216 }
217 
disposeWeakConnectionPoint()218 void OWeakObject::disposeWeakConnectionPoint()
219 {
220     OSL_PRECOND( m_refCount == 0, "OWeakObject::disposeWeakConnectionPoint: only to be called with a ref count of 0!" );
221     if (m_pWeakConnectionPoint != 0) {
222         OWeakConnectionPoint * const p = m_pWeakConnectionPoint;
223         m_pWeakConnectionPoint = 0;
224         try {
225             p->dispose();
226         }
227         catch (RuntimeException const& exc) {
228             OSL_ENSURE(
229                 false, OUStringToOString(
230                     exc.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
231             static_cast<void>(exc);
232         }
233         p->release();
234     }
235 }
236 
~OWeakObject()237 OWeakObject::~OWeakObject() SAL_THROW( (RuntimeException) )
238 {
239 }
240 
241 // XWeak
queryAdapter()242 Reference< XAdapter > SAL_CALL OWeakObject::queryAdapter()
243 	throw (::com::sun::star::uno::RuntimeException)
244 {
245 	if (!m_pWeakConnectionPoint)
246 	{
247 		// only acquire mutex if member is not created
248 		MutexGuard aGuard( getWeakMutex() );
249 		if( !m_pWeakConnectionPoint )
250 		{
251 			OWeakConnectionPoint * p = new OWeakConnectionPoint(this);
252 			p->acquire();
253 			m_pWeakConnectionPoint = p;
254 		}
255 	}
256 
257 	return m_pWeakConnectionPoint;
258 }
259 
260 //------------------------------------------------------------------------
261 //-- OWeakAggObject ----------------------------------------------------
262 //------------------------------------------------------------------------
~OWeakAggObject()263 OWeakAggObject::~OWeakAggObject() SAL_THROW( (RuntimeException) )
264 {
265 }
266 
267 // XInterface
acquire()268 void OWeakAggObject::acquire() throw()
269 {
270 	Reference<XInterface > x( xDelegator );
271 	if (x.is())
272 		x->acquire();
273 	else
274 		OWeakObject::acquire();
275 }
276 
277 // XInterface
release()278 void OWeakAggObject::release() throw()
279 {
280 	Reference<XInterface > x( xDelegator );
281 	if (x.is())
282 		x->release();
283 	else
284 		OWeakObject::release();
285 }
286 
287 // XInterface
queryInterface(const Type & rType)288 Any OWeakAggObject::queryInterface( const Type & rType ) throw(::com::sun::star::uno::RuntimeException)
289 {
290 	Reference< XInterface > x( xDelegator ); // harden ref
291 	return (x.is() ? x->queryInterface( rType ) : queryAggregation( rType ));
292 
293 //  	// set rOut to zero, if failed
294 //  	if( !xDelegator.queryHardRef( aUik, rOut ) )
295 //  	{
296 //  		XInterfaceRef x;
297 //  		if( !xDelegator.queryHardRef( ((XInterface*)0)->getSmartUik(), x ) )
298 //  			// reference is not valid
299 //  			queryAggregation( aUik, rOut );
300 //  	}
301 //  	return rOut.is();
302 }
303 
304 // XAggregation
queryAggregation(const Type & rType)305 Any OWeakAggObject::queryAggregation( const Type & rType ) throw(::com::sun::star::uno::RuntimeException)
306 {
307 	return ::cppu::queryInterface(
308 		rType,
309 		static_cast< XInterface * >( static_cast< OWeakObject * >( this ) ),
310 		static_cast< XAggregation * >( this ),
311 		static_cast< XWeak * >( this ) );
312 }
313 
314 // XAggregation
setDelegator(const Reference<XInterface> & rDelegator)315 void OWeakAggObject::setDelegator( const Reference<XInterface > & rDelegator ) throw(::com::sun::star::uno::RuntimeException)
316 {
317 	xDelegator = rDelegator;
318 }
319 
320 }
321 
322 /** */ //for docpp
323 namespace com
324 {
325 /** */ //for docpp
326 namespace sun
327 {
328 /** */ //for docpp
329 namespace star
330 {
331 /** */ //for docpp
332 namespace uno
333 {
334 
335 
336 //------------------------------------------------------------------------
337 //-- OWeakRefListener -----------------------------------------------------
338 //------------------------------------------------------------------------
339 class OWeakRefListener : public XReference
340 {
341 public:
342 	OWeakRefListener(const OWeakRefListener& rRef) SAL_THROW( () );
343 	OWeakRefListener(const Reference< XInterface >& xInt) SAL_THROW( () );
344 	virtual ~OWeakRefListener() SAL_THROW( () );
345 
346 	// XInterface
347     Any SAL_CALL queryInterface( const Type & rType ) throw(RuntimeException);
348     void SAL_CALL acquire() throw();
349     void SAL_CALL release() throw();
350 
351 	// XReference
352 	void SAL_CALL 	dispose() throw(::com::sun::star::uno::RuntimeException);
353 
354 	/// The reference counter.
355     oslInterlockedCount			m_aRefCount;
356 	/// The connection point of the weak object
357 	Reference< XAdapter >		m_XWeakConnectionPoint;
358 
359 private:
360 	OWeakRefListener& SAL_CALL operator=(const OWeakRefListener& rRef) SAL_THROW( () );
361 };
362 
OWeakRefListener(const OWeakRefListener & rRef)363 OWeakRefListener::OWeakRefListener(const OWeakRefListener& rRef) SAL_THROW( () )
364 	: com::sun::star::uno::XReference()
365     , m_aRefCount( 1 )
366 {
367     try
368     {
369 	m_XWeakConnectionPoint = rRef.m_XWeakConnectionPoint;
370 
371 	if (m_XWeakConnectionPoint.is())
372     {
373         m_XWeakConnectionPoint->addReference((XReference*)this);
374     }
375     }
376     catch (RuntimeException &) { OSL_ASSERT( 0 ); } // assert here, but no unexpected()
377     osl_decrementInterlockedCount( &m_aRefCount );
378 }
379 
OWeakRefListener(const Reference<XInterface> & xInt)380 OWeakRefListener::OWeakRefListener(const Reference< XInterface >& xInt) SAL_THROW( () )
381 	: m_aRefCount( 1 )
382 {
383     try
384     {
385 	Reference< XWeak > xWeak( Reference< XWeak >::query( xInt ) );
386 
387 	if (xWeak.is())
388 	{
389 		m_XWeakConnectionPoint = xWeak->queryAdapter();
390 
391 		if (m_XWeakConnectionPoint.is())
392 		{
393             m_XWeakConnectionPoint->addReference((XReference*)this);
394 		}
395 	}
396     }
397     catch (RuntimeException &) { OSL_ASSERT( 0 ); } // assert here, but no unexpected()
398     osl_decrementInterlockedCount( &m_aRefCount );
399 }
400 
~OWeakRefListener()401 OWeakRefListener::~OWeakRefListener() SAL_THROW( () )
402 {
403     try
404     {
405 	if (m_XWeakConnectionPoint.is())
406     {
407         acquire(); // don't die again
408 		m_XWeakConnectionPoint->removeReference((XReference*)this);
409     }
410     }
411     catch (RuntimeException &) { OSL_ASSERT( 0 ); } // assert here, but no unexpected()
412 }
413 
414 // XInterface
queryInterface(const Type & rType)415 Any SAL_CALL OWeakRefListener::queryInterface( const Type & rType ) throw(RuntimeException)
416 {
417 	return ::cppu::queryInterface(
418 		rType, static_cast< XReference * >( this ), static_cast< XInterface * >( this ) );
419 }
420 
421 // XInterface
acquire()422 void SAL_CALL OWeakRefListener::acquire() throw()
423 {
424 	osl_incrementInterlockedCount( &m_aRefCount );
425 }
426 
427 // XInterface
release()428 void SAL_CALL OWeakRefListener::release() throw()
429 {
430 	if( ! osl_decrementInterlockedCount( &m_aRefCount ) )
431 		delete this;
432 }
433 
dispose()434 void SAL_CALL OWeakRefListener::dispose()
435 	throw(::com::sun::star::uno::RuntimeException)
436 {
437 	Reference< XAdapter > xAdp;
438 	{
439 		MutexGuard guard(cppu::getWeakMutex());
440 		if( m_XWeakConnectionPoint.is() )
441 		{
442 			xAdp = m_XWeakConnectionPoint;
443 			m_XWeakConnectionPoint.clear();
444 		}
445 	}
446 
447 	if( xAdp.is() )
448 		xAdp->removeReference((XReference*)this);
449 }
450 
451 //------------------------------------------------------------------------
452 //-- WeakReferenceHelper ----------------------------------------------------------
453 //------------------------------------------------------------------------
WeakReferenceHelper(const Reference<XInterface> & xInt)454 WeakReferenceHelper::WeakReferenceHelper(const Reference< XInterface >& xInt) SAL_THROW( () )
455 	: m_pImpl( 0 )
456 {
457 	if (xInt.is())
458 	{
459 		m_pImpl = new OWeakRefListener(xInt);
460 		m_pImpl->acquire();
461 	}
462 }
463 
WeakReferenceHelper(const WeakReferenceHelper & rWeakRef)464 WeakReferenceHelper::WeakReferenceHelper(const WeakReferenceHelper& rWeakRef) SAL_THROW( () )
465 	: m_pImpl( 0 )
466 {
467 	Reference< XInterface > xInt( rWeakRef.get() );
468 	if (xInt.is())
469 	{
470 		m_pImpl = new OWeakRefListener(xInt);
471 		m_pImpl->acquire();
472 	}
473 }
474 
clear()475 void WeakReferenceHelper::clear() SAL_THROW( () )
476 {
477     try
478     {
479         if (m_pImpl)
480         {
481             if (m_pImpl->m_XWeakConnectionPoint.is())
482             {
483                 m_pImpl->m_XWeakConnectionPoint->removeReference(
484                         (XReference*)m_pImpl);
485                 m_pImpl->m_XWeakConnectionPoint.clear();
486             }
487             m_pImpl->release();
488             m_pImpl = 0;
489         }
490     }
491     catch (RuntimeException &) { OSL_ASSERT( 0 ); } // assert here, but no unexpected()
492 }
493 
operator =(const WeakReferenceHelper & rWeakRef)494 WeakReferenceHelper& WeakReferenceHelper::operator=(const WeakReferenceHelper& rWeakRef) SAL_THROW( () )
495 {
496     if (this == &rWeakRef)
497     {
498         return *this;
499     }
500     Reference< XInterface > xInt( rWeakRef.get() );
501     return operator = ( xInt );
502 }
503 
504 WeakReferenceHelper & SAL_CALL
operator =(const Reference<XInterface> & xInt)505 WeakReferenceHelper::operator= (const Reference< XInterface > & xInt)
506 SAL_THROW( () )
507 {
508     try
509     {
510         clear();
511 		if (xInt.is())
512 		{
513 			m_pImpl = new OWeakRefListener(xInt);
514 			m_pImpl->acquire();
515 		}
516     }
517     catch (RuntimeException &) { OSL_ASSERT( 0 ); } // assert here, but no unexpected()
518     return *this;
519 }
520 
~WeakReferenceHelper()521 WeakReferenceHelper::~WeakReferenceHelper() SAL_THROW( () )
522 {
523     clear();
524 }
525 
get() const526 Reference< XInterface > WeakReferenceHelper::get() const SAL_THROW( () )
527 {
528     try
529     {
530 	Reference< XAdapter > xAdp;
531 	{
532 		MutexGuard guard(cppu::getWeakMutex());
533 		if( m_pImpl && m_pImpl->m_XWeakConnectionPoint.is() )
534 			xAdp = m_pImpl->m_XWeakConnectionPoint;
535 	}
536 
537 	if (xAdp.is())
538 		return xAdp->queryAdapted();
539     }
540     catch (RuntimeException &) { OSL_ASSERT( 0 ); } // assert here, but no unexpected()
541 
542 	return Reference< XInterface >();
543 }
544 
545 }
546 }
547 }
548 }
549 
550