LibreOffice Module cppuhelper (master)  1
weak.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/config.h>
21 #include <sal/log.hxx>
22 
23 #include <osl/diagnose.h>
24 #include <osl/mutex.hxx>
25 #include <cppuhelper/weakagg.hxx>
26 #include <cppuhelper/exc_hlp.hxx>
28 
29 #include <com/sun/star/lang/DisposedException.hpp>
30 
31 #include <algorithm>
32 #include <vector>
33 
34 using namespace osl;
35 using namespace com::sun::star::uno;
36  //for docpp
38 namespace cppu
39 {
40 
41 // due to static Reflection destruction from usr, there must be a mutex leak (#73272#)
42 // this is used to lock all instances of OWeakConnectionPoint and OWeakRefListener as well as OWeakObject::m_pWeakConnectionPoint
43 static Mutex & getWeakMutex()
44 {
45  static Mutex * s_pMutex = new Mutex();
46  return *s_pMutex;
47 }
48 
49 
50 //-- OWeakConnectionPoint ----------------------------------------------------
51 
52 class OWeakConnectionPoint: public XAdapter
53 {
54 public:
59  : m_aRefCount( 0 )
60  , m_pObject(pObj)
61  {}
62 
63  // noncopyable
65  const OWeakConnectionPoint& operator=(const OWeakConnectionPoint&) = delete;
66 
67  // XInterface
68  Any SAL_CALL queryInterface( const Type & rType ) override;
69  void SAL_CALL acquire() noexcept override;
70  void SAL_CALL release() noexcept override;
71 
72  // XAdapter
73  css::uno::Reference< css::uno::XInterface > SAL_CALL queryAdapted() override;
74  void SAL_CALL addReference( const css::uno::Reference< css::uno::XReference >& xRef ) override;
75  void SAL_CALL removeReference( const css::uno::Reference< css::uno::XReference >& xRef ) override;
76 
80  void dispose();
81 
82 private:
83  virtual ~OWeakConnectionPoint() {}
84 
86  oslInterlockedCount m_aRefCount;
90  std::vector<Reference<XReference>> m_aReferences;
91 };
92 
93 // XInterface
95 {
97  rType, static_cast< XAdapter * >( this ), static_cast< XInterface * >( this ) );
98 }
99 
100 // XInterface
101 void SAL_CALL OWeakConnectionPoint::acquire() noexcept
102 {
103 #ifdef DBG_UTIL
104  // catch things early which have been deleted and then re-acquired
105  assert(m_aRefCount != -1);
106 #endif
107  osl_atomic_increment( &m_aRefCount );
108 }
109 
110 // XInterface
111 void SAL_CALL OWeakConnectionPoint::release() noexcept
112 {
113  if (! osl_atomic_decrement( &m_aRefCount ))
114  {
115 #ifdef DBG_UTIL
116  m_aRefCount = -1;
117 #endif
118  delete this;
119  }
120 }
121 
122 void OWeakConnectionPoint::dispose()
123 {
124  std::vector<Reference<XReference>> aCopy;
125  { // only hold the mutex while we access the field
126  MutexGuard aGuard(getWeakMutex());
127  // OWeakObject is not the only owner of this, so clear m_pObject
128  // so that queryAdapted() won't use it now that it's dead
129  m_pObject = nullptr;
130  // other code is going to call removeReference while we are doing this, so we need a
131  // copy, but since we are disposing and going away, we can just take the original data
132  aCopy.swap(m_aReferences);
133  }
134  Any ex;
135  for (const Reference<XReference> & i : aCopy )
136  {
137  try
138  {
139  i->dispose();
140  }
141  catch (css::lang::DisposedException &) {}
142  catch (RuntimeException &)
143  {
145  }
146  }
147  if (ex.hasValue())
148  {
150  }
151 }
152 
153 // XInterface
154 Reference< XInterface > SAL_CALL OWeakConnectionPoint::queryAdapted()
155 {
157 
158  ClearableMutexGuard guard(getWeakMutex());
159 
160  if (m_pObject)
161  {
162  oslInterlockedCount n = osl_atomic_increment( &m_pObject->m_refCount );
163 
164  if (n > 1)
165  {
166  // The reference is incremented. The object cannot be destroyed.
167  // Release the guard at the earliest point.
168  guard.clear();
169  // WeakObject has a (XInterface *) cast operator
170  ret = *m_pObject;
171  osl_atomic_decrement( &m_pObject->m_refCount );
172  }
173  else
174  // Another thread wait in the dispose method at the guard
175  osl_atomic_decrement( &m_pObject->m_refCount );
176  }
177 
178  return ret;
179 }
180 
181 // XInterface
182 void SAL_CALL OWeakConnectionPoint::addReference(const Reference< XReference >& rRef)
183 {
184  MutexGuard aGuard(getWeakMutex());
185  m_aReferences.push_back( rRef );
186 }
187 
188 // XInterface
189 void SAL_CALL OWeakConnectionPoint::removeReference(const Reference< XReference >& rRef)
190 {
191  MutexGuard aGuard(getWeakMutex());
192  // Search from end because the thing that last added a ref is most likely to be the
193  // first to remove a ref.
194  // It's not really valid to compare the pointer directly, but it's faster.
195  auto it = std::find_if(m_aReferences.rbegin(), m_aReferences.rend(),
196  [&rRef](const Reference<XReference>& rxRef) { return rxRef.get() == rRef.get(); });
197  if (it != m_aReferences.rend()) {
198  m_aReferences.erase( it.base()-1 );
199  return;
200  }
201  // interface not found, use the correct compare method
202  it = std::find(m_aReferences.rbegin(), m_aReferences.rend(), rRef);
203  if ( it != m_aReferences.rend() )
204  m_aReferences.erase( it.base()-1 );
205 }
206 
207 
208 //-- OWeakObject -------------------------------------------------------
209 
210 
211 #ifdef _MSC_VER
212 // Accidentally occurs in msvc mapfile = > had to be outlined.
213 OWeakObject::OWeakObject()
214  : m_refCount( 0 ),
215  m_pWeakConnectionPoint( nullptr )
216 {
217 }
218 #endif
219 
220 // XInterface
221 Any SAL_CALL OWeakObject::queryInterface( const Type & rType )
222 {
224  rType,
225  static_cast< XWeak * >( this ), static_cast< XInterface * >( this ) );
226 }
227 
228 // XInterface
229 void SAL_CALL OWeakObject::acquire() noexcept
230 {
231  osl_atomic_increment( &m_refCount );
232 }
233 
234 // XInterface
235 void SAL_CALL OWeakObject::release() noexcept
236 {
237  if (osl_atomic_decrement( &m_refCount ) == 0) {
238  // notify/clear all weak-refs before object's dtor is executed
239  // (which may check weak-refs to this object):
241  // destroy object:
242  delete this;
243  }
244 }
245 
247 {
248  OSL_PRECOND( m_refCount == 0, "OWeakObject::disposeWeakConnectionPoint: only to be called with a ref count of 0!" );
249  if (m_pWeakConnectionPoint != nullptr) {
250  OWeakConnectionPoint * const p = m_pWeakConnectionPoint;
251  m_pWeakConnectionPoint = nullptr;
252  try {
253  p->dispose();
254  }
255  catch (RuntimeException const& exc) {
256  SAL_WARN( "cppuhelper", exc );
257  }
258  p->release();
259  }
260 }
261 
262 OWeakObject::~OWeakObject() COVERITY_NOEXCEPT_FALSE
263 {
264 }
265 
266 // XWeak
268 {
269  if (!m_pWeakConnectionPoint)
270  {
271  // only acquire mutex if member is not created
272  MutexGuard aGuard( getWeakMutex() );
273  if( !m_pWeakConnectionPoint )
274  {
276  p->acquire();
277  m_pWeakConnectionPoint = p;
278  }
279  }
280 
281  return m_pWeakConnectionPoint;
282 }
283 
284 
285 //-- OWeakAggObject ----------------------------------------------------
286 
288 {
289 }
290 
291 // XInterface
292 void OWeakAggObject::acquire() noexcept
293 {
295  if (x.is())
296  x->acquire();
297  else
299 }
300 
301 // XInterface
302 void OWeakAggObject::release() noexcept
303 {
305  if (x.is())
306  x->release();
307  else
309 }
310 
311 // XInterface
313 {
314  Reference< XInterface > x( xDelegator ); // harden ref
315  return (x.is() ? x->queryInterface( rType ) : queryAggregation( rType ));
316 }
317 
318 // XAggregation
320 {
322  rType,
323  static_cast< XInterface * >( static_cast< OWeakObject * >( this ) ),
324  static_cast< XAggregation * >( this ),
325  static_cast< XWeak * >( this ) );
326 }
327 
328 // XAggregation
330 {
331  xDelegator = rDelegator;
332 }
333 
334 }
335  //for docpp
337 namespace com::sun::star::uno
338 {
339 
340 
341 //-- OWeakRefListener -----------------------------------------------------
342 
343 class OWeakRefListener final : public XReference
344 {
345 public:
346  explicit OWeakRefListener(const Reference< XInterface >& xInt);
347  virtual ~OWeakRefListener();
348 
349  // noncopyable
350  OWeakRefListener(const OWeakRefListener&) = delete;
351  const OWeakRefListener& operator=(const OWeakRefListener&) = delete;
352 
353  // XInterface
354  Any SAL_CALL queryInterface( const Type & rType ) override;
355  void SAL_CALL acquire() noexcept override;
356  void SAL_CALL release() noexcept override;
357 
358  // XReference
359  void SAL_CALL dispose() override;
360 
362  oslInterlockedCount m_aRefCount;
365 };
366 
368  : m_aRefCount( 1 )
369 {
370  try
371  {
373 
374  if (xWeak.is())
375  {
376  m_XWeakConnectionPoint = xWeak->queryAdapter();
377 
378  if (m_XWeakConnectionPoint.is())
379  {
380  m_XWeakConnectionPoint->addReference(static_cast<XReference*>(this));
381  }
382  }
383  }
384  catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected()
385  osl_atomic_decrement( &m_aRefCount );
386 }
387 
389 {
390  try
391  {
392  if (m_XWeakConnectionPoint.is())
393  {
394  acquire(); // don't die again
395  m_XWeakConnectionPoint->removeReference(static_cast<XReference*>(this));
396  }
397  }
398  catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected()
399 }
400 
401 // XInterface
402 Any SAL_CALL OWeakRefListener::queryInterface( const Type & rType )
403 {
405  rType, static_cast< XReference * >( this ), static_cast< XInterface * >( this ) );
406 }
407 
408 // XInterface
409 void SAL_CALL OWeakRefListener::acquire() noexcept
410 {
411  osl_atomic_increment( &m_aRefCount );
412 }
413 
414 // XInterface
415 void SAL_CALL OWeakRefListener::release() noexcept
416 {
417  if( ! osl_atomic_decrement( &m_aRefCount ) )
418  delete this;
419 }
420 
422 {
424  {
425  MutexGuard guard(cppu::getWeakMutex());
426  if( m_XWeakConnectionPoint.is() )
427  {
428  xAdp = m_XWeakConnectionPoint;
429  m_XWeakConnectionPoint.clear();
430  }
431  }
432 
433  if( xAdp.is() )
434  xAdp->removeReference(static_cast<XReference*>(this));
435 }
436 
437 
438 //-- WeakReferenceHelper ----------------------------------------------------------
439 
441  : m_pImpl( nullptr )
442 {
443  if (xInt.is())
444  {
445  m_pImpl = new OWeakRefListener(xInt);
446  m_pImpl->acquire();
447  }
448 }
449 
451  : m_pImpl( nullptr )
452 {
453  Reference< XInterface > xInt( rWeakRef.get() );
454  if (xInt.is())
455  {
456  m_pImpl = new OWeakRefListener(xInt);
457  m_pImpl->acquire();
458  }
459 }
460 
462 {
463  try
464  {
465  if (m_pImpl)
466  {
467  m_pImpl->dispose();
468  m_pImpl->release();
469  m_pImpl = nullptr;
470  }
471  }
472  catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected()
473 }
474 
476 {
477  if (this == &rWeakRef)
478  {
479  return *this;
480  }
481  Reference< XInterface > xInt( rWeakRef.get() );
482  return operator = ( xInt );
483 }
484 
486  WeakReferenceHelper && other)
487 {
488  clear();
489  std::swap(m_pImpl, other.m_pImpl);
490  return *this;
491 }
492 
493 WeakReferenceHelper & SAL_CALL
495 {
496  try
497  {
498  clear();
499  if (xInt.is())
500  {
501  m_pImpl = new OWeakRefListener(xInt);
502  m_pImpl->acquire();
503  }
504  }
505  catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected()
506  return *this;
507 }
508 
510 {
511  clear();
512 }
513 
515 {
516  try
517  {
519  {
520  // must lock to access m_XWeakConnectionPoint
521  MutexGuard guard(cppu::getWeakMutex());
522  if( m_pImpl && m_pImpl->m_XWeakConnectionPoint.is() )
523  xAdp = m_pImpl->m_XWeakConnectionPoint;
524  }
525 
526  if (xAdp.is())
527  return xAdp->queryAdapted();
528  }
529  catch (RuntimeException &)
530  {
531  OSL_ASSERT( false );
532  } // assert here, but no unexpected()
533 
534  return Reference< XInterface >();
535 }
536 
537 }
538 
539 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Type
const OWeakRefListener & operator=(const OWeakRefListener &)=delete
virtual void SAL_CALL acquire() SAL_NOEXCEPT SAL_OVERRIDE
If a delegator is set, then the delegators gets acquired.
Definition: weak.cxx:292
void SAL_CALL throwException(Any const &exc)
virtual css::uno::Any SAL_CALL queryAggregation(const css::uno::Type &rType) SAL_OVERRIDE
Called by the delegator or queryInterface.
Definition: weak.cxx:319
static Mutex & getWeakMutex()
Definition: weak.cxx:43
ULONG m_refCount
void SAL_CALL dispose() override
Definition: weak.cxx:421
friend class OWeakConnectionPoint
Definition: weak.hxx:49
sal_Int64 n
Any SAL_CALL queryInterface(const Type &rType) override
Definition: weak.cxx:402
void SAL_CALL release() noexcept override
Definition: weak.cxx:415
virtual void SAL_CALL acquire() SAL_NOEXCEPT SAL_OVERRIDE
increasing m_refCount
Definition: weak.cxx:229
float x
Reference< XAdapter > m_XWeakConnectionPoint
The connection point of the weak object, guarded by getWeakMutex()
Definition: weak.cxx:364
void SAL_CALL acquire() noexcept override
Definition: weak.cxx:409
std::vector< Reference< XReference > > m_aReferences
The container to hold the weak references.
Definition: weak.cxx:90
Any SAL_CALL getCaughtException()
Use this function to get the dynamic type of a caught C++-UNO exception; completes the above function...
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
WeakReferenceHelper &SAL_CALL operator=(const WeakReferenceHelper &rWeakRef)
Releases this reference and takes over rWeakRef.
Definition: weak.cxx:475
virtual ~OWeakAggObject() SAL_OVERRIDE
Virtual dtor.
Definition: weak.cxx:287
int i
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType) SAL_OVERRIDE
If a delegator is set, then the delegator is queried for the demanded interface.
Definition: weak.cxx:312
virtual ~OWeakObject() COVERITY_NOEXCEPT_FALSE
Virtual dtor.
Definition: weak.cxx:262
The WeakReferenceHelper holds a weak reference to an object.
Definition: weakref.hxx:55
OWeakConnectionPoint(OWeakObject *pObj)
Hold the weak object without an acquire (only the pointer).
Definition: weak.cxx:58
void dispose()
Called from the weak object if the reference count goes to zero.
Definition: weak.cxx:122
Base class to implement a UNO object supporting weak references, i.e.
Definition: weak.hxx:47
virtual css::uno::Reference< css::uno::XAdapter > SAL_CALL queryAdapter() SAL_OVERRIDE
XWeak::queryAdapter() implementation.
Definition: weak.cxx:267
oslInterlockedCount m_refCount
reference count.
Definition: weak.hxx:71
void SAL_CALL release() noexcept override
Definition: weak.cxx:111
oslInterlockedCount m_aRefCount
The reference counter.
Definition: weak.cxx:362
oslInterlockedCount m_aRefCount
The reference counter.
Definition: weak.cxx:86
void SAL_CALL clear()
Releases this reference.
Definition: weak.cxx:461
void disposeWeakConnectionPoint()
disposes and resets m_pWeakConnectionPoint
Definition: weak.cxx:246
void * p
css::uno::Reference< css::uno::XInterface > SAL_CALL get() const
Gets a hard reference to the object.
Definition: weak.cxx:514
OWeakObject * m_pObject
The weak object.
Definition: weak.cxx:88
~WeakReferenceHelper()
Releases this reference.
Definition: weak.cxx:509
#define SAL_WARN(area, stream)
OWeakRefListener(const Reference< XInterface > &xInt)
Definition: weak.cxx:367
virtual void SAL_CALL release() SAL_NOEXCEPT SAL_OVERRIDE
decreasing m_refCount
Definition: weak.cxx:235
css::uno::WeakReferenceHelper xDelegator
weak reference to delegator.
Definition: weakagg.hxx:96
::std::unique_ptr< XmlIdRegistry_Impl > m_pImpl
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType) SAL_OVERRIDE
Basic queryInterface() implementation supporting com::sun::star::uno::XWeak and com::sun::star::uno::...
Definition: weak.cxx:221
void SAL_CALL acquire() noexcept override
Definition: weak.cxx:101
css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType, Interface1 *p1)
Compares demanded type to given template argument types.
virtual void SAL_CALL release() SAL_NOEXCEPT SAL_OVERRIDE
If a delegator is set, then the delegators gets released.
Definition: weak.cxx:302
virtual void SAL_CALL setDelegator(const css::uno::Reference< css::uno::XInterface > &Delegator) SAL_OVERRIDE
Set the delegator.
Definition: weak.cxx:329