xref: /AOO41X/main/cppuhelper/source/weak.cxx (revision 9d7e27acf3441a88e7e2e9d0bd0e0c145f24ac0d)
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(); // dont 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