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 <cppuhelper/weakagg.hxx>
25 #include <cppuhelper/exc_hlp.hxx>
27 
28 #include <com/sun/star/lang/DisposedException.hpp>
29 
30 #include <algorithm>
31 #include <vector>
32 #include <mutex>
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 std::mutex * gpWeakMutex = new std::mutex;
44 
45 
46 //-- OWeakConnectionPoint ----------------------------------------------------
47 
48 class OWeakConnectionPoint: public XAdapter
49 {
50 public:
55  : m_aRefCount( 0 )
56  , m_pObject(pObj)
57  {}
58 
59  // noncopyable
61  const OWeakConnectionPoint& operator=(const OWeakConnectionPoint&) = delete;
62 
63  // XInterface
64  Any SAL_CALL queryInterface( const Type & rType ) override;
65  void SAL_CALL acquire() noexcept override;
66  void SAL_CALL release() noexcept override;
67 
68  // XAdapter
69  css::uno::Reference< css::uno::XInterface > SAL_CALL queryAdapted() override;
70  void SAL_CALL addReference( const css::uno::Reference< css::uno::XReference >& xRef ) override;
71  void SAL_CALL removeReference( const css::uno::Reference< css::uno::XReference >& xRef ) override;
72 
76  void dispose();
77 
78 private:
79  virtual ~OWeakConnectionPoint() {}
80 
82  oslInterlockedCount m_aRefCount;
86  std::vector<Reference<XReference>> m_aReferences;
87 };
88 
89 // XInterface
91 {
93  rType, static_cast< XAdapter * >( this ), static_cast< XInterface * >( this ) );
94 }
95 
96 // XInterface
97 void SAL_CALL OWeakConnectionPoint::acquire() noexcept
98 {
99 #ifdef DBG_UTIL
100  // catch things early which have been deleted and then re-acquired
101  assert(m_aRefCount != -1);
102 #endif
103  osl_atomic_increment( &m_aRefCount );
104 }
105 
106 // XInterface
107 void SAL_CALL OWeakConnectionPoint::release() noexcept
108 {
109  if (! osl_atomic_decrement( &m_aRefCount ))
110  {
111 #ifdef DBG_UTIL
112  m_aRefCount = -1;
113 #endif
114  delete this;
115  }
116 }
117 
118 void OWeakConnectionPoint::dispose()
119 {
120  std::vector<Reference<XReference>> aCopy;
121  { // only hold the mutex while we access the field
122  std::scoped_lock aGuard(*cppu::gpWeakMutex);
123  // OWeakObject is not the only owner of this, so clear m_pObject
124  // so that queryAdapted() won't use it now that it's dead
125  m_pObject = nullptr;
126  // other code is going to call removeReference while we are doing this, so we need a
127  // copy, but since we are disposing and going away, we can just take the original data
128  aCopy.swap(m_aReferences);
129  }
130  Any ex;
131  for (const Reference<XReference> & i : aCopy )
132  {
133  try
134  {
135  i->dispose();
136  }
137  catch (css::lang::DisposedException &) {}
138  catch (RuntimeException &)
139  {
141  }
142  }
143  if (ex.hasValue())
144  {
146  }
147 }
148 
149 // XInterface
150 Reference< XInterface > SAL_CALL OWeakConnectionPoint::queryAdapted()
151 {
153 
154  {
155  std::scoped_lock guard(*gpWeakMutex);
156 
157  if (!m_pObject)
158  return ret;
159 
160  oslInterlockedCount n = osl_atomic_increment( &m_pObject->m_refCount );
161 
162  if (n <= 1)
163  {
164  // Another thread wait in the dispose method at the guard
165  osl_atomic_decrement( &m_pObject->m_refCount );
166  return ret;
167  }
168  }
169 
170  // n is now > 1
171  // The reference is incremented. The object cannot be destroyed.
172  // Release the guard at the earliest point.
173  // WeakObject has a (XInterface *) cast operator
174  ret = *m_pObject;
175  osl_atomic_decrement( &m_pObject->m_refCount );
176 
177  return ret;
178 }
179 
180 // XInterface
181 void SAL_CALL OWeakConnectionPoint::addReference(const Reference< XReference >& rRef)
182 {
183  std::scoped_lock aGuard(*gpWeakMutex);
184  m_aReferences.push_back( rRef );
185 }
186 
187 // XInterface
188 void SAL_CALL OWeakConnectionPoint::removeReference(const Reference< XReference >& rRef)
189 {
190  std::scoped_lock aGuard(*gpWeakMutex);
191  // Search from end because the thing that last added a ref is most likely to be the
192  // first to remove a ref.
193  // It's not really valid to compare the pointer directly, but it's faster.
194  auto it = std::find_if(m_aReferences.rbegin(), m_aReferences.rend(),
195  [&rRef](const Reference<XReference>& rxRef) { return rxRef.get() == rRef.get(); });
196  if (it != m_aReferences.rend()) {
197  m_aReferences.erase( it.base()-1 );
198  return;
199  }
200  // interface not found, use the correct compare method
201  it = std::find(m_aReferences.rbegin(), m_aReferences.rend(), rRef);
202  if ( it != m_aReferences.rend() )
203  m_aReferences.erase( it.base()-1 );
204 }
205 
206 
207 //-- OWeakObject -------------------------------------------------------
208 
209 
210 #ifdef _MSC_VER
211 // Accidentally occurs in msvc mapfile = > had to be outlined.
212 OWeakObject::OWeakObject()
213  : m_refCount( 0 ),
214  m_pWeakConnectionPoint( nullptr )
215 {
216 }
217 #endif
218 
219 // XInterface
220 Any SAL_CALL OWeakObject::queryInterface( const Type & rType )
221 {
223  rType,
224  static_cast< XWeak * >( this ), static_cast< XInterface * >( this ) );
225 }
226 
227 // XInterface
228 void SAL_CALL OWeakObject::acquire() noexcept
229 {
230  osl_atomic_increment( &m_refCount );
231 }
232 
233 // XInterface
234 void SAL_CALL OWeakObject::release() noexcept
235 {
236  if (osl_atomic_decrement( &m_refCount ) == 0) {
237  // notify/clear all weak-refs before object's dtor is executed
238  // (which may check weak-refs to this object):
240  // destroy object:
241  delete this;
242  }
243 }
244 
246 {
247  OSL_PRECOND( m_refCount == 0, "OWeakObject::disposeWeakConnectionPoint: only to be called with a ref count of 0!" );
248  if (m_pWeakConnectionPoint != nullptr) {
249  OWeakConnectionPoint * const p = m_pWeakConnectionPoint;
250  m_pWeakConnectionPoint = nullptr;
251  try {
252  p->dispose();
253  }
254  catch (RuntimeException const& exc) {
255  SAL_WARN( "cppuhelper", exc );
256  }
257  p->release();
258  }
259 }
260 
261 OWeakObject::~OWeakObject() COVERITY_NOEXCEPT_FALSE
262 {
263 }
264 
265 // XWeak
267 {
268  if (!m_pWeakConnectionPoint)
269  {
270  // only acquire mutex if member is not created
271  std::scoped_lock aGuard( *gpWeakMutex );
272  if( !m_pWeakConnectionPoint )
273  {
275  p->acquire();
276  m_pWeakConnectionPoint = p;
277  }
278  }
279 
280  return m_pWeakConnectionPoint;
281 }
282 
283 
284 //-- OWeakAggObject ----------------------------------------------------
285 
287 {
288 }
289 
290 // XInterface
291 void OWeakAggObject::acquire() noexcept
292 {
294  if (x.is())
295  x->acquire();
296  else
298 }
299 
300 // XInterface
301 void OWeakAggObject::release() noexcept
302 {
304  if (x.is())
305  x->release();
306  else
308 }
309 
310 // XInterface
312 {
313  Reference< XInterface > x( xDelegator ); // harden ref
314  return (x.is() ? x->queryInterface( rType ) : queryAggregation( rType ));
315 }
316 
317 // XAggregation
319 {
321  rType,
322  static_cast< XInterface * >( static_cast< OWeakObject * >( this ) ),
323  static_cast< XAggregation * >( this ),
324  static_cast< XWeak * >( this ) );
325 }
326 
327 // XAggregation
329 {
330  xDelegator = rDelegator;
331 }
332 
333 }
334  //for docpp
336 namespace com::sun::star::uno
337 {
338 
339 
340 //-- OWeakRefListener -----------------------------------------------------
341 
342 class OWeakRefListener final : public XReference
343 {
344 public:
345  explicit OWeakRefListener(const Reference< XInterface >& xInt);
346  virtual ~OWeakRefListener();
347 
348  // noncopyable
349  OWeakRefListener(const OWeakRefListener&) = delete;
350  const OWeakRefListener& operator=(const OWeakRefListener&) = delete;
351 
352  // XInterface
353  Any SAL_CALL queryInterface( const Type & rType ) override;
354  void SAL_CALL acquire() noexcept override;
355  void SAL_CALL release() noexcept override;
356 
357  // XReference
358  void SAL_CALL dispose() override;
359 
361  oslInterlockedCount m_aRefCount;
364 };
365 
367  : m_aRefCount( 1 )
368 {
369  try
370  {
372 
373  if (xWeak.is())
374  {
375  m_XWeakConnectionPoint = xWeak->queryAdapter();
376 
377  if (m_XWeakConnectionPoint.is())
378  {
379  m_XWeakConnectionPoint->addReference(static_cast<XReference*>(this));
380  }
381  }
382  }
383  catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected()
384  osl_atomic_decrement( &m_aRefCount );
385 }
386 
388 {
389  try
390  {
391  if (m_XWeakConnectionPoint.is())
392  {
393  acquire(); // don't die again
394  m_XWeakConnectionPoint->removeReference(static_cast<XReference*>(this));
395  }
396  }
397  catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected()
398 }
399 
400 // XInterface
401 Any SAL_CALL OWeakRefListener::queryInterface( const Type & rType )
402 {
404  rType, static_cast< XReference * >( this ), static_cast< XInterface * >( this ) );
405 }
406 
407 // XInterface
408 void SAL_CALL OWeakRefListener::acquire() noexcept
409 {
410  osl_atomic_increment( &m_aRefCount );
411 }
412 
413 // XInterface
414 void SAL_CALL OWeakRefListener::release() noexcept
415 {
416  if( ! osl_atomic_decrement( &m_aRefCount ) )
417  delete this;
418 }
419 
421 {
423  {
424  std::scoped_lock guard(*cppu::gpWeakMutex);
425  if( m_XWeakConnectionPoint.is() )
426  {
427  xAdp = m_XWeakConnectionPoint;
428  m_XWeakConnectionPoint.clear();
429  }
430  }
431 
432  if( xAdp.is() )
433  xAdp->removeReference(static_cast<XReference*>(this));
434 }
435 
436 
437 //-- WeakReferenceHelper ----------------------------------------------------------
438 
440  : m_pImpl( nullptr )
441 {
442  if (xInt.is())
443  {
444  m_pImpl = new OWeakRefListener(xInt);
445  m_pImpl->acquire();
446  }
447 }
448 
450  : m_pImpl( nullptr )
451 {
452  Reference< XInterface > xInt( rWeakRef.get() );
453  if (xInt.is())
454  {
455  m_pImpl = new OWeakRefListener(xInt);
456  m_pImpl->acquire();
457  }
458 }
459 
461 {
462  try
463  {
464  if (m_pImpl)
465  {
466  m_pImpl->dispose();
467  m_pImpl->release();
468  m_pImpl = nullptr;
469  }
470  }
471  catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected()
472 }
473 
475 {
476  if (this == &rWeakRef)
477  {
478  return *this;
479  }
480  Reference< XInterface > xInt( rWeakRef.get() );
481  return operator = ( xInt );
482 }
483 
485  WeakReferenceHelper && other)
486 {
487  clear();
488  std::swap(m_pImpl, other.m_pImpl);
489  return *this;
490 }
491 
492 WeakReferenceHelper & SAL_CALL
494 {
495  try
496  {
497  clear();
498  if (xInt.is())
499  {
500  m_pImpl = new OWeakRefListener(xInt);
501  m_pImpl->acquire();
502  }
503  }
504  catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected()
505  return *this;
506 }
507 
509 {
510  clear();
511 }
512 
514 {
515  try
516  {
518  {
519  // must lock to access m_XWeakConnectionPoint
520  std::scoped_lock guard(*cppu::gpWeakMutex);
521  if( m_pImpl && m_pImpl->m_XWeakConnectionPoint.is() )
522  xAdp = m_pImpl->m_XWeakConnectionPoint;
523  }
524 
525  if (xAdp.is())
526  return xAdp->queryAdapted();
527  }
528  catch (RuntimeException &)
529  {
530  OSL_ASSERT( false );
531  } // assert here, but no unexpected()
532 
533  return Reference< XInterface >();
534 }
535 
536 }
537 
538 /* 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:291
static std::mutex * gpWeakMutex
Definition: weak.cxx:43
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:318
ULONG m_refCount
void SAL_CALL dispose() override
Definition: weak.cxx:420
friend class OWeakConnectionPoint
Definition: weak.hxx:49
sal_Int64 n
Any SAL_CALL queryInterface(const Type &rType) override
Definition: weak.cxx:401
void SAL_CALL release() noexcept override
Definition: weak.cxx:414
virtual void SAL_CALL acquire() SAL_NOEXCEPT SAL_OVERRIDE
increasing m_refCount
Definition: weak.cxx:228
float x
Reference< XAdapter > m_XWeakConnectionPoint
The connection point of the weak object, guarded by getWeakMutex()
Definition: weak.cxx:363
void SAL_CALL acquire() noexcept override
Definition: weak.cxx:408
std::vector< Reference< XReference > > m_aReferences
The container to hold the weak references.
Definition: weak.cxx:86
Any SAL_CALL getCaughtException()
Use this function to get the dynamic type of a caught C++-UNO exception; completes the above function...
WeakReferenceHelper &SAL_CALL operator=(const WeakReferenceHelper &rWeakRef)
Releases this reference and takes over rWeakRef.
Definition: weak.cxx:474
virtual ~OWeakAggObject() SAL_OVERRIDE
Virtual dtor.
Definition: weak.cxx:286
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:311
virtual ~OWeakObject() COVERITY_NOEXCEPT_FALSE
Virtual dtor.
Definition: weak.cxx:261
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:54
void dispose()
Called from the weak object if the reference count goes to zero.
Definition: weak.cxx:118
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:266
oslInterlockedCount m_refCount
reference count.
Definition: weak.hxx:71
void SAL_CALL release() noexcept override
Definition: weak.cxx:107
oslInterlockedCount m_aRefCount
The reference counter.
Definition: weak.cxx:361
oslInterlockedCount m_aRefCount
The reference counter.
Definition: weak.cxx:82
void SAL_CALL clear()
Releases this reference.
Definition: weak.cxx:460
void disposeWeakConnectionPoint()
disposes and resets m_pWeakConnectionPoint
Definition: weak.cxx:245
void * p
css::uno::Reference< css::uno::XInterface > SAL_CALL get() const
Gets a hard reference to the object.
Definition: weak.cxx:513
OWeakObject * m_pObject
The weak object.
Definition: weak.cxx:84
~WeakReferenceHelper()
Releases this reference.
Definition: weak.cxx:508
#define SAL_WARN(area, stream)
OWeakRefListener(const Reference< XInterface > &xInt)
Definition: weak.cxx:366
virtual void SAL_CALL release() SAL_NOEXCEPT SAL_OVERRIDE
decreasing m_refCount
Definition: weak.cxx:234
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:220
void SAL_CALL acquire() noexcept override
Definition: weak.cxx:97
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:301
virtual void SAL_CALL setDelegator(const css::uno::Reference< css::uno::XInterface > &Delegator) SAL_OVERRIDE
Set the delegator.
Definition: weak.cxx:328