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