summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephan Bergmann <sbergman@redhat.com>2020-02-19 11:43:02 +0100
committerStephan Bergmann <sbergman@redhat.com>2020-02-19 13:41:46 +0100
commitbbe5e5bad4465b3f37b9060312a87b971f8e5655 (patch)
tree9cac033a2c4221062c1dc85457fbec9fece6a1f9
parent867b5bb769f24f3f3f87a53e5e660f8766659bea (diff)
Turn SfxGlobalEvents_Impl into an XComponent
...so that it can drop all its UNO references during shut down of the service manager (when every XComponent service/singleton will be disposed), and not keep other UNO objects alive until exit as has been discussed in the comments of <https://gerrit.libreoffice.org/c/core/+/85367/2# message-ecbc68109994a471c1033a4e6eab0dfd562dca1c> "Elide use of rtl_Instance (which is obsoleted by C++11 thread-safe statics)". Change-Id: Ife7cdbe5baad9b3eb4d1ab8687d4dd2970200997 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/89005 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
-rw-r--r--sfx2/source/notify/globalevents.cxx130
1 files changed, 127 insertions, 3 deletions
diff --git a/sfx2/source/notify/globalevents.cxx b/sfx2/source/notify/globalevents.cxx
index b8cc21131090..9ac9e8707565 100644
--- a/sfx2/source/notify/globalevents.cxx
+++ b/sfx2/source/notify/globalevents.cxx
@@ -26,6 +26,7 @@
#include <com/sun/star/document/XEventBroadcaster.hpp>
#include <com/sun/star/document/XDocumentEventListener.hpp>
#include <com/sun/star/frame/XGlobalEventBroadcaster.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
#include <com/sun/star/lang/NoSupportException.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/uno/Type.hxx>
@@ -40,6 +41,7 @@
#include <unotools/eventcfg.hxx>
#include <eventsupplier.hxx>
+#include <set>
#include <vector>
using namespace css;
@@ -61,13 +63,16 @@ class SfxGlobalEvents_Impl : public ModelCollectionMutexBase
, css::frame::XGlobalEventBroadcaster
, css::document::XEventBroadcaster
, css::document::XEventListener
+ , css::lang::XComponent
>
{
css::uno::Reference< css::container::XNameReplace > m_xEvents;
css::uno::Reference< css::document::XEventListener > m_xJobExecutorListener;
::comphelper::OInterfaceContainerHelper2 m_aLegacyListeners;
::comphelper::OInterfaceContainerHelper2 m_aDocumentListeners;
+ std::multiset<css::uno::Reference<css::lang::XEventListener>> m_disposeListeners;
TModelList m_lModels;
+ bool m_disposed;
public:
explicit SfxGlobalEvents_Impl(const css::uno::Reference < css::uno::XComponentContext >& rxContext);
@@ -124,6 +129,15 @@ public:
// css.lang.XEventListener
virtual void SAL_CALL disposing(const css::lang::EventObject& aEvent) override;
+ // css.lang.XComponent
+ void SAL_CALL dispose() override;
+
+ void SAL_CALL addEventListener(css::uno::Reference<css::lang::XEventListener> const & xListener)
+ override;
+
+ void SAL_CALL removeEventListener(
+ css::uno::Reference<css::lang::XEventListener> const & aListener) override;
+
private:
// threadsafe
@@ -140,6 +154,7 @@ SfxGlobalEvents_Impl::SfxGlobalEvents_Impl( const uno::Reference < uno::XCompone
, m_xJobExecutorListener( task::theJobExecutor::get( rxContext ), uno::UNO_QUERY_THROW )
, m_aLegacyListeners (m_aLock)
, m_aDocumentListeners (m_aLock)
+ , m_disposed(false)
{
osl_atomic_increment(&m_refCount);
SfxApplication::GetOrCreate();
@@ -151,6 +166,9 @@ uno::Reference< container::XNameReplace > SAL_CALL SfxGlobalEvents_Impl::getEven
{
// SAFE ->
osl::MutexGuard aLock(m_aLock);
+ if (m_disposed) {
+ throw css::lang::DisposedException();
+ }
return m_xEvents;
// <- SAFE
}
@@ -158,13 +176,28 @@ uno::Reference< container::XNameReplace > SAL_CALL SfxGlobalEvents_Impl::getEven
void SAL_CALL SfxGlobalEvents_Impl::addEventListener(const uno::Reference< document::XEventListener >& xListener)
{
+ {
+ osl::MutexGuard g(m_aLock);
+ if (m_disposed) {
+ throw css::lang::DisposedException();
+ }
+ }
// container is threadsafe
m_aLegacyListeners.addInterface(xListener);
+ // Take care of an XComponent::dispose being processed in parallel with the above addInterface:
+ {
+ osl::MutexGuard g(m_aLock);
+ if (!m_disposed) {
+ return;
+ }
+ }
+ m_aLegacyListeners.disposeAndClear({static_cast<OWeakObject *>(this)});
}
void SAL_CALL SfxGlobalEvents_Impl::removeEventListener(const uno::Reference< document::XEventListener >& xListener)
{
+ // The below removeInterface will silently do nothing when m_disposed:
// container is threadsafe
m_aLegacyListeners.removeInterface(xListener);
}
@@ -172,12 +205,27 @@ void SAL_CALL SfxGlobalEvents_Impl::removeEventListener(const uno::Reference< do
void SAL_CALL SfxGlobalEvents_Impl::addDocumentEventListener( const uno::Reference< document::XDocumentEventListener >& Listener )
{
+ {
+ osl::MutexGuard g(m_aLock);
+ if (m_disposed) {
+ throw css::lang::DisposedException();
+ }
+ }
m_aDocumentListeners.addInterface( Listener );
+ // Take care of an XComponent::dispose being processed in parallel with the above addInterface:
+ {
+ osl::MutexGuard g(m_aLock);
+ if (!m_disposed) {
+ return;
+ }
+ }
+ m_aDocumentListeners.disposeAndClear({static_cast<OWeakObject *>(this)});
}
void SAL_CALL SfxGlobalEvents_Impl::removeDocumentEventListener( const uno::Reference< document::XDocumentEventListener >& Listener )
{
+ // The below removeInterface will silently do nothing when m_disposed:
m_aDocumentListeners.removeInterface( Listener );
}
@@ -192,6 +240,7 @@ void SAL_CALL SfxGlobalEvents_Impl::notifyDocumentEvent( const OUString& /*_Even
void SAL_CALL SfxGlobalEvents_Impl::notifyEvent(const document::EventObject& aEvent)
{
+ // The below implts_* will silently do nothing when m_disposed:
document::DocumentEvent aDocEvent(aEvent.Source, aEvent.EventName, nullptr, uno::Any());
implts_notifyJobExecution(aEvent);
implts_checkAndExecuteEventBindings(aDocEvent);
@@ -201,6 +250,7 @@ void SAL_CALL SfxGlobalEvents_Impl::notifyEvent(const document::EventObject& aEv
void SAL_CALL SfxGlobalEvents_Impl::documentEventOccured( const document::DocumentEvent& Event )
{
+ // The below implts_* will silently do nothing when m_disposed:
implts_notifyJobExecution(document::EventObject(Event.Source, Event.EventName));
implts_checkAndExecuteEventBindings(Event);
implts_notifyListener(Event);
@@ -219,6 +269,52 @@ void SAL_CALL SfxGlobalEvents_Impl::disposing(const lang::EventObject& aEvent)
// <- SAFE
}
+void SfxGlobalEvents_Impl::dispose() {
+ std::multiset<css::uno::Reference<css::lang::XEventListener>> listeners;
+ {
+ osl::MutexGuard g(m_aLock);
+ m_xEvents.clear();
+ m_xJobExecutorListener.clear();
+ m_disposeListeners.swap(listeners);
+ m_lModels.clear();
+ m_disposed = true;
+ }
+ m_aLegacyListeners.disposeAndClear({static_cast<OWeakObject *>(this)});
+ m_aDocumentListeners.disposeAndClear({static_cast<OWeakObject *>(this)});
+ for (auto const & i: listeners) {
+ try {
+ i->disposing({static_cast< cppu::OWeakObject * >(this)});
+ } catch (css::lang::DisposedException &) {}
+ }
+}
+
+void SfxGlobalEvents_Impl::addEventListener(
+ css::uno::Reference<css::lang::XEventListener> const & xListener)
+{
+ if (!xListener.is()) {
+ throw css::uno::RuntimeException("null listener");
+ }
+ {
+ osl::MutexGuard g(m_aLock);
+ if (!m_disposed) {
+ m_disposeListeners.insert(xListener);
+ return;
+ }
+ }
+ try {
+ xListener->disposing({static_cast< cppu::OWeakObject * >(this)});
+ } catch (css::lang::DisposedException &) {}
+}
+
+void SfxGlobalEvents_Impl::removeEventListener(
+ css::uno::Reference<css::lang::XEventListener> const & aListener)
+{
+ osl::MutexGuard g(m_aLock);
+ auto const i = m_disposeListeners.find(aListener);
+ if (i != m_disposeListeners.end()) {
+ m_disposeListeners.erase(i);
+ }
+}
sal_Bool SAL_CALL SfxGlobalEvents_Impl::has(const uno::Any& aElement)
{
@@ -229,6 +325,9 @@ sal_Bool SAL_CALL SfxGlobalEvents_Impl::has(const uno::Any& aElement)
// SAFE ->
osl::MutexGuard aLock(m_aLock);
+ if (m_disposed) {
+ throw css::lang::DisposedException();
+ }
TModelList::iterator pIt = impl_searchDoc(xDoc);
if (pIt != m_lModels.end())
bHas = true;
@@ -251,6 +350,9 @@ void SAL_CALL SfxGlobalEvents_Impl::insert( const uno::Any& aElement )
// SAFE ->
{
osl::MutexGuard aLock(m_aLock);
+ if (m_disposed) {
+ throw css::lang::DisposedException();
+ }
TModelList::iterator pIt = impl_searchDoc(xDoc);
if (pIt != m_lModels.end())
throw container::ElementExistException(
@@ -312,6 +414,9 @@ uno::Reference< container::XEnumeration > SAL_CALL SfxGlobalEvents_Impl::createE
{
// SAFE ->
osl::MutexGuard aLock(m_aLock);
+ if (m_disposed) {
+ throw css::lang::DisposedException();
+ }
uno::Sequence<uno::Any> models(m_lModels.size());
for (size_t i = 0; i < m_lModels.size(); ++i)
{
@@ -334,6 +439,9 @@ sal_Bool SAL_CALL SfxGlobalEvents_Impl::hasElements()
{
// SAFE ->
osl::MutexGuard aLock(m_aLock);
+ if (m_disposed) {
+ throw css::lang::DisposedException();
+ }
return (!m_lModels.empty());
// <- SAFE
}
@@ -341,9 +449,17 @@ sal_Bool SAL_CALL SfxGlobalEvents_Impl::hasElements()
void SfxGlobalEvents_Impl::implts_notifyJobExecution(const document::EventObject& aEvent)
{
+ css::uno::Reference<css::document::XEventListener> listener;
+ {
+ osl::MutexGuard g(m_aLock);
+ listener = m_xJobExecutorListener;
+ }
+ if (!listener.is()) {
+ return;
+ }
try
{
- m_xJobExecutorListener->notifyEvent(aEvent);
+ listener->notifyEvent(aEvent);
}
catch(const uno::RuntimeException&)
{ throw; }
@@ -354,11 +470,19 @@ void SfxGlobalEvents_Impl::implts_notifyJobExecution(const document::EventObject
void SfxGlobalEvents_Impl::implts_checkAndExecuteEventBindings(const document::DocumentEvent& aEvent)
{
+ css::uno::Reference<css::container::XNameReplace> events;
+ {
+ osl::MutexGuard g(m_aLock);
+ events = m_xEvents;
+ }
+ if (!events.is()) {
+ return;
+ }
try
{
uno::Any aAny;
- if ( m_xEvents->hasByName( aEvent.EventName ) )
- aAny = m_xEvents->getByName(aEvent.EventName);
+ if ( events->hasByName( aEvent.EventName ) )
+ aAny = events->getByName(aEvent.EventName);
SfxEvents_Impl::Execute(aAny, aEvent, nullptr);
}
catch ( uno::RuntimeException const & )