diff options
author | Stephan Bergmann <sbergman@redhat.com> | 2020-09-30 21:31:10 +0200 |
---|---|---|
committer | Stephan Bergmann <sbergman@redhat.com> | 2020-10-01 09:44:53 +0200 |
commit | 1a1d432420646bcf129624a866fd6c754e25d195 (patch) | |
tree | 9c0b292838486fccbda4942a5a44da82db6e9b2a /cppuhelper/source | |
parent | 9c850ca827486db3702699e5c2218842d7361b1b (diff) |
Add single-instance attribute for *.compoonent <implementation>s
...to ease the implementation in C++ code of constructor-based <implementation>s
that shall be single-instance (and which would have been implemented with e.g.
cppu::creaetOneInstanceFactory for non--constructor-based <implementation>s).
See e.g. 6e35794cad555485955c3b43593497dcdbf29840 "terminate XDesktop properly
in unit tests" and 6362ebab298549e8616c32cafd75cb3959ba7d65 "dbaccess: create
instances with uno constructors" for the clumsy approach used until now, where
the C++ constructor function uses a static instance that is cleared in
dispose(), adding fake <singleton> entries to <implementation>s where necessary
so that the ServiceManager will call those XComponent::dispose() functions when
it itself gets disposed.
For every <implementation>, the ServiceManager already holds an Implementation
data structure, so it can easily hold a singleInstance there and clear it when
the ServiceManager gets disposed. (One consequence is that single-instance
implementations are now created with their Instance.mutex locked, but that
should not cause problems in practice, given that the construction of a single-
instance implementation should not recursively request its own construction
anyway.)
The new single-instance="true" attribute is mostly useful in combination with
the constructor attribute (see above), but it can also be used for non--
constructor-based <implementation>s, at least in theory.
(The single-instance="true" attribute is orthogonal to <singleton> elements.
There are existing single-instance services---even if those should arguably have
been defined as singletons in the first place---that can benefit from
single-instance="true". And there are <implementation>s that support one or
more <singleton>s alongside one or more <service>s, where the latter are not
single-instance.)
This new single-instance="true" attribute in *.component files should not
interfere with the lo_get_constructor_map machinery in the DISABLE_DYNLOADING
branch of cppuhelper::detail::loadSharedLibComponentFactory
(cppuhelper/source/shlib.cxx) used by Android, iOS and some fuzzer code.
AFAIU, the lo_get_constructor_map machinery should only ever come into play
after the ServiceManager has decided whether or not to create a new instance
based on the single-instance attributes in the *.component files.
This commit only provides the new single-instance="true" attribute. Actual
changes of <implementation>s and their C++ constructor functions are delegated
to a series of follow-up commits. (So that they can easily be reverted
individually should the need arise.)
Change-Id: Iea6c0fc539d74477b7a536dc771b198df6b0510e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/103734
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
Diffstat (limited to 'cppuhelper/source')
-rw-r--r-- | cppuhelper/source/servicemanager.cxx | 97 | ||||
-rw-r--r-- | cppuhelper/source/servicemanager.hxx | 19 |
2 files changed, 88 insertions, 28 deletions
diff --git a/cppuhelper/source/servicemanager.cxx b/cppuhelper/source/servicemanager.cxx index f06405f7794b..fe9ef7dbd2b4 100644 --- a/cppuhelper/source/servicemanager.cxx +++ b/cppuhelper/source/servicemanager.cxx @@ -327,6 +327,7 @@ void Parser::handleComponent() { void Parser::handleImplementation() { OUString attrName; OUString attrConstructor; + bool attrSingleInstance = false; xmlreader::Span name; int nsId; while (reader_.nextAttribute(&nsId, &name)) { @@ -366,6 +367,19 @@ void Parser::handleImplementation() { + ": <implementation> has \"constructor\" attribute but" " <component> has no \"environment\" attribute"); } + } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE + && name.equals(RTL_CONSTASCII_STRINGPARAM("single-instance"))) + { + if (attrSingleInstance) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + + ": <implementation> has multiple \"single-instance\" attributes"); + } + if (!reader_.getAttributeValue(false).equals(RTL_CONSTASCII_STRINGPARAM("true"))) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": <implementation> has bad \"single-instance\" attribute"); + } + attrSingleInstance = true; } else { throw css::registry::InvalidRegistryException( reader_.getUrl() + ": unexpected element attribute \"" @@ -380,7 +394,7 @@ void Parser::handleImplementation() { implementation_ = std::make_shared<cppuhelper::ServiceManager::Data::Implementation>( attrName, attrLoader_, attrUri_, attrEnvironment_, attrConstructor, - attrPrefix_, alienContext_, reader_.getUrl()); + attrPrefix_, attrSingleInstance, alienContext_, reader_.getUrl()); if (!data_->namedImplementations.emplace(attrName, implementation_). second) { @@ -647,28 +661,62 @@ cppuhelper::ServiceManager::Data::Implementation::createInstance( bool singletonRequest) { css::uno::Reference<css::uno::XInterface> inst; + if (isSingleInstance) { + osl::MutexGuard g(mutex); + if (!singleInstance.is()) { + singleInstance = doCreateInstance(context); + } + inst = singleInstance; + } else { + inst = doCreateInstance(context); + } + updateDisposeInstance(singletonRequest, inst); + return inst; +} + +css::uno::Reference<css::uno::XInterface> +cppuhelper::ServiceManager::Data::Implementation::createInstanceWithArguments( + css::uno::Reference<css::uno::XComponentContext> const & context, + bool singletonRequest, css::uno::Sequence<css::uno::Any> const & arguments) +{ + css::uno::Reference<css::uno::XInterface> inst; + if (isSingleInstance) { + osl::MutexGuard g(mutex); + if (!singleInstance.is()) { + singleInstance = doCreateInstanceWithArguments(context, arguments); + } + inst = singleInstance; + } else { + inst = doCreateInstanceWithArguments(context, arguments); + } + updateDisposeInstance(singletonRequest, inst); + return inst; +} + +css::uno::Reference<css::uno::XInterface> +cppuhelper::ServiceManager::Data::Implementation::doCreateInstance( + css::uno::Reference<css::uno::XComponentContext> const & context) +{ if (constructorFn) { - inst.set( + return css::uno::Reference<css::uno::XInterface>( constructorFn(context.get(), css::uno::Sequence<css::uno::Any>()), SAL_NO_ACQUIRE); } else if (factory1.is()) { - inst = factory1->createInstanceWithContext(context); + return factory1->createInstanceWithContext(context); } else { assert(factory2.is()); - inst = factory2->createInstance(); + return factory2->createInstance(); } - updateDisposeSingleton(singletonRequest, inst); - return inst; } css::uno::Reference<css::uno::XInterface> -cppuhelper::ServiceManager::Data::Implementation::createInstanceWithArguments( +cppuhelper::ServiceManager::Data::Implementation::doCreateInstanceWithArguments( css::uno::Reference<css::uno::XComponentContext> const & context, - bool singletonRequest, css::uno::Sequence<css::uno::Any> const & arguments) + css::uno::Sequence<css::uno::Any> const & arguments) { - css::uno::Reference<css::uno::XInterface> inst; if (constructorFn) { - inst.set(constructorFn(context.get(), arguments), SAL_NO_ACQUIRE); + css::uno::Reference<css::uno::XInterface> inst( + constructorFn(context.get(), arguments), SAL_NO_ACQUIRE); //HACK: The constructor will either observe arguments and return inst // that does not implement XInitialization (or null), or ignore // arguments and return inst that implements XInitialization; this @@ -679,18 +727,17 @@ cppuhelper::ServiceManager::Data::Implementation::createInstanceWithArguments( if (init.is()) { init->initialize(arguments); } + return inst; } else if (factory1.is()) { - inst = factory1->createInstanceWithArgumentsAndContext( + return factory1->createInstanceWithArgumentsAndContext( arguments, context); } else { assert(factory2.is()); - inst = factory2->createInstanceWithArguments(arguments); + return factory2->createInstanceWithArguments(arguments); } - updateDisposeSingleton(singletonRequest, inst); - return inst; } -void cppuhelper::ServiceManager::Data::Implementation::updateDisposeSingleton( +void cppuhelper::ServiceManager::Data::Implementation::updateDisposeInstance( bool singletonRequest, css::uno::Reference<css::uno::XInterface> const & instance) { @@ -702,15 +749,15 @@ void cppuhelper::ServiceManager::Data::Implementation::updateDisposeSingleton( // the implementation hands out different instances): if (singletonRequest) { osl::MutexGuard g(mutex); - disposeSingleton.clear(); + disposeInstance.clear(); dispose = false; - } else if (!singletons.empty()) { + } else if (shallDispose()) { css::uno::Reference<css::lang::XComponent> comp( instance, css::uno::UNO_QUERY); if (comp.is()) { osl::MutexGuard g(mutex); if (dispose) { - disposeSingleton = comp; + disposeInstance = comp; } } } @@ -840,20 +887,20 @@ void cppuhelper::ServiceManager::disposing() { for (const auto& rEntry : data_.namedImplementations) { assert(rEntry.second); - if (!rEntry.second->singletons.empty()) { + if (rEntry.second->shallDispose()) { osl::MutexGuard g2(rEntry.second->mutex); - if (rEntry.second->disposeSingleton.is()) { - sngls.push_back(rEntry.second->disposeSingleton); + if (rEntry.second->disposeInstance.is()) { + sngls.push_back(rEntry.second->disposeInstance); } } } for (const auto& rEntry : data_.dynamicImplementations) { assert(rEntry.second); - if (!rEntry.second->singletons.empty()) { + if (rEntry.second->shallDispose()) { osl::MutexGuard g2(rEntry.second->mutex); - if (rEntry.second->disposeSingleton.is()) { - sngls.push_back(rEntry.second->disposeSingleton); + if (rEntry.second->disposeInstance.is()) { + sngls.push_back(rEntry.second->disposeInstance); } } if (rEntry.second->component.is()) { @@ -1395,7 +1442,7 @@ bool cppuhelper::ServiceManager::readLegacyRdbFile(OUString const & uri) { std::shared_ptr< Data::Implementation > impl = std::make_shared<Data::Implementation>( name, readLegacyRdbString(uri, implKey, "UNO/ACTIVATOR"), - readLegacyRdbString(uri, implKey, "UNO/LOCATION"), "", "", "", + readLegacyRdbString(uri, implKey, "UNO/LOCATION"), "", "", "", false, css::uno::Reference< css::uno::XComponentContext >(), uri); if (!data_.namedImplementations.emplace(name, impl).second) { diff --git a/cppuhelper/source/servicemanager.hxx b/cppuhelper/source/servicemanager.hxx index 9a7cac513402..24a7e56a4ba9 100644 --- a/cppuhelper/source/servicemanager.hxx +++ b/cppuhelper/source/servicemanager.hxx @@ -74,11 +74,13 @@ public: OUString const & theUri, OUString const & theEnvironment, OUString const & theConstructorName, OUString const & thePrefix, + bool theIsSingleInstance, css::uno::Reference< css::uno::XComponentContext > const & theAlienContext, OUString const & theRdbFile): name(theName), loader(theLoader), uri(theUri), environment(theEnvironment), constructorName(theConstructorName), prefix(thePrefix), + isSingleInstance(theIsSingleInstance), alienContext(theAlienContext), rdbFile(theRdbFile), constructorFn(nullptr), status(STATUS_NEW), dispose(true) {} @@ -91,7 +93,7 @@ public: theFactory2, css::uno::Reference< css::lang::XComponent > const & theComponent): - name(theName), constructorFn(nullptr), + name(theName), isSingleInstance(false), constructorFn(nullptr), factory1(theFactory1), factory2(theFactory2), component(theComponent), status(STATUS_LOADED), dispose(true) { assert(theFactory1.is() || theFactory2.is()); } @@ -111,6 +113,8 @@ public: bool singletonRequest, css::uno::Sequence<css::uno::Any> const & arguments); + bool shallDispose() const { return isSingleInstance || !singletons.empty(); } + enum Status { STATUS_NEW, STATUS_WRAPPER, STATUS_LOADED }; // Logically, exactly one of constructorFn, factory1, factory2 should @@ -130,6 +134,7 @@ public: OUString environment; OUString constructorName; OUString prefix; + bool isSingleInstance; css::uno::Reference< css::uno::XComponentContext > alienContext; OUString rdbFile; std::vector< OUString > services; @@ -141,11 +146,19 @@ public: Status status; osl::Mutex mutex; - css::uno::Reference< css::lang::XComponent > disposeSingleton; + css::uno::Reference<css::uno::XInterface> singleInstance; + css::uno::Reference< css::lang::XComponent > disposeInstance; bool dispose; private: - void updateDisposeSingleton( + css::uno::Reference<css::uno::XInterface> doCreateInstance( + css::uno::Reference<css::uno::XComponentContext> const & context); + + css::uno::Reference<css::uno::XInterface> doCreateInstanceWithArguments( + css::uno::Reference<css::uno::XComponentContext> const & context, + css::uno::Sequence<css::uno::Any> const & arguments); + + void updateDisposeInstance( bool singletonRequest, css::uno::Reference<css::uno::XInterface> const & instance); }; |