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 
37 namespace cppu
38 {
39 
40 // due to static Reflection destruction from usr, there must be a mutex leak (#73272#)
41 // this is used to lock all instances of OWeakConnectionPoint and OWeakRefListener as well as OWeakObject::m_pWeakConnectionPoint
42 static std::mutex * gpWeakMutex = new std::mutex;
43 
44 
45 //-- OWeakConnectionPoint ----------------------------------------------------
46 
47 class OWeakConnectionPoint: public XAdapter
48 {
49 public:
54  : m_aRefCount( 0 )
55  , m_pObject(pObj)
56  {}
57 
58  // noncopyable
60  const OWeakConnectionPoint& operator=(const OWeakConnectionPoint&) = delete;
61 
62  // XInterface
63  Any SAL_CALL queryInterface( const Type & rType ) override;
64  void SAL_CALL acquire() noexcept override;
65  void SAL_CALL release() noexcept override;
66 
67  // XAdapter
68  css::uno::Reference< css::uno::XInterface > SAL_CALL queryAdapted() override;
69  void SAL_CALL addReference( const css::uno::Reference< css::uno::XReference >& xRef ) override;
70  void SAL_CALL removeReference( const css::uno::Reference< css::uno::XReference >& xRef ) override;
71 
75  void dispose();
76 
77 private:
78  virtual ~OWeakConnectionPoint() {}
79 
81  oslInterlockedCount m_aRefCount;
85  std::vector<Reference<XReference>> m_aReferences;
86 };
87 
88 // XInterface
90 {
92  rType, static_cast< XAdapter * >( this ), static_cast< XInterface * >( this ) );
93 }
94 
95 // XInterface
96 void SAL_CALL OWeakConnectionPoint::acquire() noexcept
97 {
98 #ifdef DBG_UTIL
99  // catch things early which have been deleted and then re-acquired
100  assert(m_aRefCount != -1);
101 #endif
102  osl_atomic_increment( &m_aRefCount );
103 }
104 
105 // XInterface
106 void SAL_CALL OWeakConnectionPoint::release() noexcept
107 {
108  if (! osl_atomic_decrement( &m_aRefCount ))
109  {
110 #ifdef DBG_UTIL
111  m_aRefCount = -1;
112 #endif
113  delete this;
114  }
115 }
116 
117 void OWeakConnectionPoint::dispose()
118 {
119  std::vector<Reference<XReference>> aCopy;
120  { // only hold the mutex while we access the field
121  std::scoped_lock aGuard(*cppu::gpWeakMutex);
122  // OWeakObject is not the only owner of this, so clear m_pObject
123  // so that queryAdapted() won't use it now that it's dead
124  m_pObject = nullptr;
125  // other code is going to call removeReference while we are doing this, so we need a
126  // copy, but since we are disposing and going away, we can just take the original data
127  aCopy.swap(m_aReferences);
128  }
129  Any ex;
130  for (const Reference<XReference> & i : aCopy )
131  {
132  try
133  {
134  i->dispose();
135  }
136  catch (css::lang::DisposedException &) {}
137  catch (RuntimeException &)
138  {
140  }
141  }
142  if (ex.hasValue())
143  {
145  }
146 }
147 
148 // XInterface
149 Reference< XInterface > SAL_CALL OWeakConnectionPoint::queryAdapted()
150 {
152 
153  {
154  std::scoped_lock guard(*gpWeakMutex);
155 
156  if (!m_pObject)
157  return ret;
158 
159  oslInterlockedCount n = osl_atomic_increment( &m_pObject->m_refCount );
160 
161  if (n <= 1)
162  {
163  // Another thread wait in the dispose method at the guard
164  osl_atomic_decrement( &m_pObject->m_refCount );
165  return ret;
166  }
167  }
168 
169  // n is now > 1
170  // The reference is incremented. The object cannot be destroyed.
171  // Release the guard at the earliest point.
172  // WeakObject has a (XInterface *) cast operator
173  ret = *m_pObject;
174  osl_atomic_decrement( &m_pObject->m_refCount );
175 
176  return ret;
177 }
178 
179 // XInterface
180 void SAL_CALL OWeakConnectionPoint::addReference(const Reference< XReference >& rRef)
181 {
182  std::scoped_lock aGuard(*gpWeakMutex);
183  m_aReferences.push_back( rRef );
184 }
185 
186 // XInterface
187 void SAL_CALL OWeakConnectionPoint::removeReference(const Reference< XReference >& rRef)
188 {
189  std::scoped_lock aGuard(*gpWeakMutex);
190  // Search from end because the thing that last added a ref is most likely to be the
191  // first to remove a ref.
192  // It's not really valid to compare the pointer directly, but it's faster.
193  auto it = std::find_if(m_aReferences.rbegin(), m_aReferences.rend(),
194  [&rRef](const Reference<XReference>& rxRef) { return rxRef.get() == rRef.get(); });
195  if (it != m_aReferences.rend()) {
196  m_aReferences.erase( it.base()-1 );
197  return;
198  }
199  // interface not found, use the correct compare method
200  it = std::find(m_aReferences.rbegin(), m_aReferences.rend(), rRef);
201  if ( it != m_aReferences.rend() )
202  m_aReferences.erase( it.base()-1 );
203 }
204 
205 
206 //-- OWeakObject -------------------------------------------------------
207 
208 // XInterface
209 Any SAL_CALL OWeakObject::queryInterface( const Type & rType )
210 {
212  rType,
213  static_cast< XWeak * >( this ), static_cast< XInterface * >( this ) );
214 }
215 
216 // XInterface
217 void SAL_CALL OWeakObject::acquire() noexcept
218 {
219  osl_atomic_increment( &m_refCount );
220 }
221 
222 // XInterface
223 void SAL_CALL OWeakObject::release() noexcept
224 {
225  if (osl_atomic_decrement( &m_refCount ) == 0) {
226  // notify/clear all weak-refs before object's dtor is executed
227  // (which may check weak-refs to this object):
228  disposeWeakConnectionPoint();
229  // destroy object:
230  delete this;
231  }
232 }
233 
234 void OWeakObject::disposeWeakConnectionPoint()
235 {
236  OSL_PRECOND( m_refCount == 0, "OWeakObject::disposeWeakConnectionPoint: only to be called with a ref count of 0!" );
237  if (m_pWeakConnectionPoint != nullptr) {
238  OWeakConnectionPoint * const p = m_pWeakConnectionPoint;
239  m_pWeakConnectionPoint = nullptr;
240  try {
241  p->dispose();
242  }
243  catch (RuntimeException const& exc) {
244  SAL_WARN( "cppuhelper", exc );
245  }
246  p->release();
247  }
248 }
249 
250 OWeakObject::~OWeakObject() COVERITY_NOEXCEPT_FALSE
251 {
252 }
253 
254 // XWeak
255 Reference< XAdapter > SAL_CALL OWeakObject::queryAdapter()
256 {
257  if (!m_pWeakConnectionPoint)
258  {
259  // only acquire mutex if member is not created
260  std::scoped_lock aGuard( *gpWeakMutex );
261  if( !m_pWeakConnectionPoint )
262  {
264  p->acquire();
265  m_pWeakConnectionPoint = p;
266  }
267  }
268 
269  return m_pWeakConnectionPoint;
270 }
271 
272 
273 //-- OWeakAggObject ----------------------------------------------------
274 
275 OWeakAggObject::~OWeakAggObject()
276 {
277 }
278 
279 // XInterface
280 void OWeakAggObject::acquire() noexcept
281 {
282  Reference<XInterface > x( xDelegator );
283  if (x.is())
284  x->acquire();
285  else
286  OWeakObject::acquire();
287 }
288 
289 // XInterface
290 void OWeakAggObject::release() noexcept
291 {
292  Reference<XInterface > x( xDelegator );
293  if (x.is())
294  x->release();
295  else
296  OWeakObject::release();
297 }
298 
299 // XInterface
301 {
302  Reference< XInterface > x( xDelegator ); // harden ref
303  return (x.is() ? x->queryInterface( rType ) : queryAggregation( rType ));
304 }
305 
306 // XAggregation
307 Any OWeakAggObject::queryAggregation( const Type & rType )
308 {
310  rType,
311  static_cast< XInterface * >( static_cast< OWeakObject * >( this ) ),
312  static_cast< XAggregation * >( this ),
313  static_cast< XWeak * >( this ) );
314 }
315 
316 // XAggregation
317 void OWeakAggObject::setDelegator( const Reference<XInterface > & rDelegator )
318 {
319  xDelegator = rDelegator;
320 }
321 
322 }
323 
324 namespace com::sun::star::uno
325 {
326 
327 
328 //-- OWeakRefListener -----------------------------------------------------
329 
330 class OWeakRefListener final : public XReference
331 {
332 public:
333  explicit OWeakRefListener(const Reference< XInterface >& xInt);
334  explicit OWeakRefListener(const Reference< XWeak >& xInt);
335  virtual ~OWeakRefListener();
336 
337  // noncopyable
338  OWeakRefListener(const OWeakRefListener&) = delete;
339  const OWeakRefListener& operator=(const OWeakRefListener&) = delete;
340 
341  // XInterface
342  Any SAL_CALL queryInterface( const Type & rType ) override;
343  void SAL_CALL acquire() noexcept override;
344  void SAL_CALL release() noexcept override;
345 
346  // XReference
347  void SAL_CALL dispose() override;
348 
350  oslInterlockedCount m_aRefCount;
353 };
354 
355 OWeakRefListener::OWeakRefListener(const Reference< XInterface >& xInt)
356  : m_aRefCount( 1 )
357 {
358  try
359  {
361 
362  if (xWeak.is())
363  {
364  m_XWeakConnectionPoint = xWeak->queryAdapter();
365 
366  if (m_XWeakConnectionPoint.is())
367  {
368  m_XWeakConnectionPoint->addReference(static_cast<XReference*>(this));
369  }
370  }
371  }
372  catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected()
373  osl_atomic_decrement( &m_aRefCount );
374 }
375 
377  : m_aRefCount( 1 )
378 {
379  m_XWeakConnectionPoint = xWeak->queryAdapter();
380 
381  if (m_XWeakConnectionPoint.is())
382  {
383  m_XWeakConnectionPoint->addReference(static_cast<XReference*>(this));
384  }
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  std::scoped_lock guard(*cppu::gpWeakMutex);
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  if (xWeak.is())
454  {
455  m_pImpl = new OWeakRefListener(xWeak);
456  m_pImpl->acquire();
457  }
458 }
459 
461  : m_pImpl( nullptr )
462 {
463  Reference< XInterface > xInt( rWeakRef.get() );
464  if (xInt.is())
465  {
466  m_pImpl = new OWeakRefListener(xInt);
467  m_pImpl->acquire();
468  }
469 }
470 
472 {
473  try
474  {
475  if (m_pImpl)
476  {
477  m_pImpl->dispose();
478  m_pImpl->release();
479  m_pImpl = nullptr;
480  }
481  }
482  catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected()
483 }
484 
486 {
487  if (this == &rWeakRef)
488  {
489  return *this;
490  }
491  Reference< XInterface > xInt( rWeakRef.get() );
492  return operator = ( xInt );
493 }
494 
496  WeakReferenceHelper && other)
497 {
498  clear();
499  std::swap(m_pImpl, other.m_pImpl);
500  return *this;
501 }
502 
503 WeakReferenceHelper & SAL_CALL
505 {
506  try
507  {
508  clear();
509  if (xInt.is())
510  {
511  m_pImpl = new OWeakRefListener(xInt);
512  m_pImpl->acquire();
513  }
514  }
515  catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected()
516  return *this;
517 }
518 
521 {
522  clear();
523  if (xWeak)
524  {
525  m_pImpl = new OWeakRefListener(xWeak);
526  m_pImpl->acquire();
527  }
528  return *this;
529 }
530 
532 {
533  clear();
534 }
535 
537 {
538  try
539  {
541  {
542  // must lock to access m_XWeakConnectionPoint
543  std::scoped_lock guard(*cppu::gpWeakMutex);
544  if( m_pImpl && m_pImpl->m_XWeakConnectionPoint.is() )
545  xAdp = m_pImpl->m_XWeakConnectionPoint;
546  }
547 
548  if (xAdp.is())
549  return xAdp->queryAdapted();
550  }
551  catch (RuntimeException &)
552  {
553  OSL_ASSERT( false );
554  } // assert here, but no unexpected()
555 
556  return Reference< XInterface >();
557 }
558 
559 }
560 
561 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Type
static std::mutex * gpWeakMutex
Definition: weak.cxx:42
void SAL_CALL throwException(Any const &exc)
ULONG m_refCount
void SAL_CALL dispose() override
Definition: weak.cxx:421
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
float x
Reference< XAdapter > m_XWeakConnectionPoint
The connection point of the weak object, guarded by getWeakMutex()
Definition: weak.cxx:352
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:85
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:485
int i
The WeakReferenceHelper holds a weak reference to an object.
Definition: weakref.hxx:56
OWeakConnectionPoint(OWeakObject *pObj)
Hold the weak object without an acquire (only the pointer).
Definition: weak.cxx:53
void dispose()
Called from the weak object if the reference count goes to zero.
Definition: weak.cxx:117
Base class to implement a UNO object supporting weak references, i.e.
Definition: weak.hxx:47
void SAL_CALL release() noexcept override
Definition: weak.cxx:106
oslInterlockedCount m_aRefCount
The reference counter.
Definition: weak.cxx:350
oslInterlockedCount m_aRefCount
The reference counter.
Definition: weak.cxx:81
void SAL_CALL clear()
Releases this reference.
Definition: weak.cxx:471
void * p
css::uno::Reference< css::uno::XInterface > SAL_CALL get() const
Gets a hard reference to the object.
Definition: weak.cxx:536
OWeakObject * m_pObject
The weak object.
Definition: weak.cxx:83
~WeakReferenceHelper()
Releases this reference.
Definition: weak.cxx:531
#define SAL_WARN(area, stream)
OWeakRefListener(const Reference< XInterface > &xInt)
Definition: weak.cxx:355
void dispose()
::std::unique_ptr< XmlIdRegistry_Impl > m_pImpl
void SAL_CALL acquire() noexcept override
Definition: weak.cxx:96
css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType, Interface1 *p1)
Compares demanded type to given template argument types.