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