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