Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  weak.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


#include <sal/config.h>
#include <sal/log.hxx>

#include <osl/diagnose.h>
#include <cppuhelper/weakagg.hxx>
#include <cppuhelper/exc_hlp.hxx>
#include <cppuhelper/queryinterface.hxx>

#include <com/sun/star/lang/DisposedException.hpp>

#include <atomic>
#include <algorithm>
#include <vector>
#include <mutex>

using namespace com::sun::star::uno;

namespace cppu
{

// due to static Reflection destruction from usr, there must be a mutex leak (#73272#)
// this is used to lock all instances of OWeakConnectionPoint and OWeakRefListener as well as OWeakObject::m_pWeakConnectionPoint
static std::mutex * gpWeakMutex = new std::mutex;


//-- OWeakConnectionPoint ----------------------------------------------------

class OWeakConnectionPoint: public XAdapter
{
public:
    /**
        Hold the weak object without an acquire (only the pointer).
     */

    explicit OWeakConnectionPoint( OWeakObject* pObj )
        : m_aRefCount( 0 )
        , m_pObject(pObj)
    {}

    // noncopyable
    OWeakConnectionPoint(const OWeakConnectionPoint&) = delete;
    const OWeakConnectionPoint& operator=(const OWeakConnectionPoint&) = delete;

    // XInterface
    Any SAL_CALL        queryInterface( const Type & rType ) override;
    void SAL_CALL       acquire() noexcept override;
    void SAL_CALL       release() noexcept override;

    // XAdapter
    css::uno::Reference< css::uno::XInterface > SAL_CALL queryAdapted() override;
    void SAL_CALL addReference( const css::uno::Reference< css::uno::XReference >& xRef ) override;
    void SAL_CALL removeReference( const css::uno::Reference< css::uno::XReference >& xRef ) override;

    /// Called from the weak object if the reference count goes to zero.
    ///
    /// @throws css::uno::RuntimeException
    void dispose();

private:
    virtual ~OWeakConnectionPoint() {}

    /// The reference counter.
    oslInterlockedCount         m_aRefCount;
    /// The weak object
    OWeakObject*                m_pObject;
    /// The container to hold the weak references
    std::vector<Reference<XReference>>  m_aReferences;
};

// XInterface
Any SAL_CALL OWeakConnectionPoint::queryInterface( const Type & rType )
{
    return ::cppu::queryInterface(
        rType, static_cast< XAdapter * >( this ), static_cast< XInterface * >( this ) );
}

// XInterface
void SAL_CALL OWeakConnectionPoint::acquire() noexcept
{
#ifdef DBG_UTIL
    // catch things early which have been deleted and then re-acquired
    assert(m_aRefCount != -1);
#endif
    osl_atomic_increment( &m_aRefCount );
}

// XInterface
void SAL_CALL OWeakConnectionPoint::release() noexcept
{
    if (! osl_atomic_decrement( &m_aRefCount ))
    {
#ifdef DBG_UTIL
        m_aRefCount = -1;
#endif
        delete this;
    }
}

void OWeakConnectionPoint::dispose()
{
    std::vector<Reference<XReference>> aCopy;
    { // only hold the mutex while we access the field
        std::scoped_lock aGuard(*cppu::gpWeakMutex);
        // OWeakObject is not the only owner of this, so clear m_pObject
        // so that queryAdapted() won't use it now that it's dead
        m_pObject = nullptr;
        // other code is going to call removeReference while we are doing this, so we need a
        // copy, but since we are disposing and going away, we can just take the original data
        aCopy.swap(m_aReferences);
    }
    Any ex;
    for (const Reference<XReference> & i : aCopy )
    {
        try
        {
            i->dispose();
        }
        catch (css::lang::DisposedException &) {}
        catch (RuntimeException &)
        {
            ex = cppu::getCaughtException();
        }
    }
    if (ex.hasValue())
    {
        cppu::throwException(ex);
    }
}

// XInterface
Reference< XInterface > SAL_CALL OWeakConnectionPoint::queryAdapted()
{
    Reference< XInterface > ret;

    {
        std::scoped_lock guard(*gpWeakMutex);

        if (!m_pObject)
            return ret;

        oslInterlockedCount n = osl_atomic_increment( &m_pObject->m_refCount );

        if (n <= 1)
        {
            // Another thread wait in the dispose method at the guard
            osl_atomic_decrement( &m_pObject->m_refCount );
            return ret;
        }
    }

    // n is now > 1
    // The reference is incremented. The object cannot be destroyed.
    // Release the guard at the earliest point.
    // WeakObject has a (XInterface *) cast operator
    ret = *m_pObject;
    osl_atomic_decrement( &m_pObject->m_refCount );

    return ret;
}

// XInterface
void SAL_CALL OWeakConnectionPoint::addReference(const Reference< XReference >& rRef)
{
    std::scoped_lock aGuard(*gpWeakMutex);
    m_aReferences.push_back( rRef );
}

// XInterface
void SAL_CALL OWeakConnectionPoint::removeReference(const Reference< XReference >& rRef)
{
    std::scoped_lock aGuard(*gpWeakMutex);
    // Search from end because the thing that last added a ref is most likely to be the
    // first to remove a ref.
    // It's not really valid to compare the pointer directly, but it's faster.
    auto it = std::find_if(m_aReferences.rbegin(), m_aReferences.rend(),
        [&rRef](const Reference<XReference>& rxRef) { return rxRef.get() == rRef.get(); });
    if (it != m_aReferences.rend()) {
        m_aReferences.erase( it.base()-1 );
        return;
    }
    // interface not found, use the correct compare method
    it = std::find(m_aReferences.rbegin(), m_aReferences.rend(), rRef);
    if ( it != m_aReferences.rend() )
        m_aReferences.erase( it.base()-1 );
}


//-- OWeakObject -------------------------------------------------------

// XInterface
Any SAL_CALL OWeakObject::queryInterface( const Type & rType )
{
    return ::cppu::queryInterface(
        rType,
        static_cast< XWeak * >( this ), static_cast< XInterface * >( this ) );
}

// XInterface
void SAL_CALL OWeakObject::acquire() noexcept
{
    osl_atomic_increment( &m_refCount );
}

// XInterface
void SAL_CALL OWeakObject::release() noexcept
{
    if (osl_atomic_decrement( &m_refCount ) == 0) {
        // notify/clear all weak-refs before object's dtor is executed
        // (which may check weak-refs to this object):
        disposeWeakConnectionPoint();
        // destroy object:
        delete this;
    }
}

void OWeakObject::disposeWeakConnectionPoint()
{
    OSL_PRECOND( (atomic_thread_fence(std::memory_order_acquire), m_refCount == 0), "OWeakObject::disposeWeakConnectionPoint: only to be called with a ref count of 0!" );
    if (m_pWeakConnectionPoint != nullptr) {
        OWeakConnectionPoint * const p = m_pWeakConnectionPoint;
        m_pWeakConnectionPoint = nullptr;
        try {
            p->dispose();
        }
        catch (RuntimeException const& exc) {
            SAL_WARN( "cppuhelper", exc );
        }
        p->release();
    }
}

OWeakObject::~OWeakObject() COVERITY_NOEXCEPT_FALSE
{
}

// XWeak
Reference< XAdapter > SAL_CALL OWeakObject::queryAdapter()
{
    std::scoped_lock aGuard( *gpWeakMutex );
    if( !m_pWeakConnectionPoint )
    {
        OWeakConnectionPoint * p = new OWeakConnectionPoint(this);
        p->acquire();
        m_pWeakConnectionPoint = p;
    }

    return m_pWeakConnectionPoint;
}


//-- OWeakAggObject ----------------------------------------------------

OWeakAggObject::~OWeakAggObject()
{
}

// XInterface
void OWeakAggObject::acquire() noexcept
{
    Reference<XInterface > x( xDelegator );
    if (x.is())
        x->acquire();
    else
        OWeakObject::acquire();
}

// XInterface
void OWeakAggObject::release() noexcept
{
    Reference<XInterface > x( xDelegator );
    if (x.is())
        x->release();
    else
        OWeakObject::release();
}

// XInterface
Any OWeakAggObject::queryInterface( const Type & rType )
{
    Reference< XInterface > x( xDelegator ); // harden ref
    return (x.is() ? x->queryInterface( rType ) : queryAggregation( rType ));
}

// XAggregation
Any OWeakAggObject::queryAggregation( const Type & rType )
{
    return ::cppu::queryInterface(
        rType,
        static_cast< XInterface * >( static_cast< OWeakObject * >( this ) ),
        static_cast< XAggregation * >( this ),
        static_cast< XWeak * >( this ) );
}

// XAggregation
void OWeakAggObject::setDelegator( const Reference<XInterface > & rDelegator )
{
    xDelegator = rDelegator;
}

}

namespace com::sun::star::uno
{


//-- OWeakRefListener -----------------------------------------------------

class OWeakRefListener final : public XReference
{
public:
    explicit OWeakRefListener(const Reference< XInterface >& xInt);
    explicit OWeakRefListener(const Reference< XWeak >& xInt);
    ~OWeakRefListener();

    // noncopyable
    OWeakRefListener(const OWeakRefListener&) = delete;
    const OWeakRefListener& operator=(const OWeakRefListener&) = delete;

    // XInterface
    Any SAL_CALL queryInterface( const Type & rType ) override;
    void SAL_CALL acquire() noexcept override;
    void SAL_CALL release() noexcept override;

    // XReference
    void SAL_CALL   dispose() override;

    /// The reference counter.
    oslInterlockedCount         m_aRefCount;
    /// The connection point of the weak object, guarded by getWeakMutex()
    Reference< XAdapter >       m_XWeakConnectionPoint;
};

OWeakRefListener::OWeakRefListener(const Reference< XInterface >& xInt)
    : m_aRefCount( 1 )
{
    try
    {
    Reference< XWeak > xWeak( Reference< XWeak >::query( xInt ) );

    if (xWeak.is())
    {
        m_XWeakConnectionPoint = xWeak->queryAdapter();

        if (m_XWeakConnectionPoint.is())
        {
            m_XWeakConnectionPoint->addReference(static_cast<XReference*>(this));
        }
    }
    }
    catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected()
    osl_atomic_decrement( &m_aRefCount );
}

OWeakRefListener::OWeakRefListener(const Reference< XWeak >& xWeak)
    : m_aRefCount( 1 )
{
    m_XWeakConnectionPoint = xWeak->queryAdapter();

    if (m_XWeakConnectionPoint.is())
    {
        m_XWeakConnectionPoint->addReference(static_cast<XReference*>(this));
    }
    osl_atomic_decrement( &m_aRefCount );
}

OWeakRefListener::~OWeakRefListener()
{
    try
    {
    if (m_XWeakConnectionPoint.is())
    {
        acquire(); // don't die again
        m_XWeakConnectionPoint->removeReference(static_cast<XReference*>(this));
    }
    }
    catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected()
}

// XInterface
Any SAL_CALL OWeakRefListener::queryInterface( const Type & rType )
{
    return ::cppu::queryInterface(
        rType, static_cast< XReference * >( this ), static_cast< XInterface * >( this ) );
}

// XInterface
void SAL_CALL OWeakRefListener::acquire() noexcept
{
    osl_atomic_increment( &m_aRefCount );
}

// XInterface
void SAL_CALL OWeakRefListener::release() noexcept
{
    if( ! osl_atomic_decrement( &m_aRefCount ) )
        delete this;
}

void SAL_CALL OWeakRefListener::dispose()
{
    Reference< XAdapter > xAdp;
    {
        std::scoped_lock guard(*cppu::gpWeakMutex);
        if( m_XWeakConnectionPoint.is() )
        {
            xAdp = m_XWeakConnectionPoint;
            m_XWeakConnectionPoint.clear();
        }
    }

    if( xAdp.is() )
        xAdp->removeReference(static_cast<XReference*>(this));
}


//-- WeakReferenceHelper ----------------------------------------------------------

WeakReferenceHelper::WeakReferenceHelper(const Reference< XInterface >& xInt)
    : m_pImpl( nullptr )
{
    if (xInt.is())
    {
        m_pImpl = new OWeakRefListener(xInt);
        m_pImpl->acquire();
    }
}

WeakReferenceHelper::WeakReferenceHelper(const Reference< XWeak >& xWeak)
    : m_pImpl( nullptr )
{
    if (xWeak.is())
    {
        m_pImpl = new OWeakRefListener(xWeak);
        m_pImpl->acquire();
    }
}

WeakReferenceHelper::WeakReferenceHelper(const WeakReferenceHelper& rWeakRef)
    : m_pImpl( nullptr )
{
    Reference< XInterface > xInt( rWeakRef.get() );
    if (xInt.is())
    {
        m_pImpl = new OWeakRefListener(xInt);
        m_pImpl->acquire();
    }
}

void WeakReferenceHelper::clear()
{
    try
    {
        if (m_pImpl)
        {
            m_pImpl->dispose();
            m_pImpl->release();
            m_pImpl = nullptr;
        }
    }
    catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected()
}

WeakReferenceHelper& WeakReferenceHelper::operator=(const WeakReferenceHelper&&nbsp;rWeakRef)
{
    if (this == &rWeakRef)
    {
        return *this;
    }
    Reference< XInterface > xInt( rWeakRef.get() );
    return operator = ( xInt );
}

WeakReferenceHelper & WeakReferenceHelper::operator =(
    WeakReferenceHelper && other)
{
    clear();
    std::swap(m_pImpl, other.m_pImpl);
    return *this;
}

WeakReferenceHelper & SAL_CALL
WeakReferenceHelper::operator= (const Reference< XInterface > & xInt)
{
    try
    {
        clear();
        if (xInt.is())
        {
            m_pImpl = new OWeakRefListener(xInt);
            m_pImpl->acquire();
        }
    }
    catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected()
    return *this;
}

WeakReferenceHelper &
WeakReferenceHelper::operator= (const Reference< XWeak > & xWeak)
{
    clear();
    if (xWeak)
    {
        m_pImpl = new OWeakRefListener(xWeak);
        m_pImpl->acquire();
    }
    return *this;
}

WeakReferenceHelper::~WeakReferenceHelper()
{
    clear();
}

Reference< XInterface > WeakReferenceHelper::get() const
{
    try
    {
        Reference< XAdapter > xAdp;
        {
            // must lock to access m_XWeakConnectionPoint
            std::scoped_lock guard(*cppu::gpWeakMutex);
            if( m_pImpl && m_pImpl->m_XWeakConnectionPoint.is() )
                xAdp = m_pImpl->m_XWeakConnectionPoint;
        }

        if (xAdp.is())
            return xAdp->queryAdapted();
    }
    catch (RuntimeException &)
    {
        OSL_ASSERT( false );
    } // assert here, but no unexpected()

    return Reference< XInterface >();
}

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

95%


¤ Dauer der Verarbeitung: 0.9 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge