xref: /trunk/main/cppuhelper/source/weak.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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