/* -*- 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 .
*/
Bridge::Bridge(
rtl::Reference< BridgeFactory > const & factory, OUString name,
css::uno::Reference< css::connection::XConnection > const & connection,
css::uno::Reference< css::bridge::XInstanceProvider > provider):
factory_(factory), name_(std::move(name)), connection_(connection),
provider_(std::move(provider)),
binaryUno_(u"" UNO_LB_UNO ""_ustr),
cppToBinaryMapping_(CPPU_CURRENT_LANGUAGE_BINDING_NAME, u"" UNO_LB_UNO ""_ustr),
binaryToCppMapping_(u"" UNO_LB_UNO ""_ustr, CPPU_CURRENT_LANGUAGE_BINDING_NAME),
protPropTid_( reinterpret_cast< sal_Int8 const * >(".UrpProtocolPropertiesTid"),
RTL_CONSTASCII_LENGTH(".UrpProtocolPropertiesTid")),
protPropOid_(u"UrpProtocolProperties"_ustr),
protPropType_(
cppu::UnoType<
css::uno::Reference< css::bridge::XProtocolProperties > >::get()),
protPropRequest_(u"com.sun.star.bridge.XProtocolProperties::requestChange"_ustr),
protPropCommit_(u"com.sun.star.bridge.XProtocolProperties::commitChange"_ustr),
state_(STATE_INITIAL), threadPool_(nullptr), currentContextMode_(false),
proxies_(0), calls_(0), normalCall_(false), activeCalls_(0),
mode_(MODE_REQUESTED)
{
assert(factory.is() && connection.is()); if (!binaryUno_.is()) { throw css::uno::RuntimeException(u"URP: no binary UNO environment"_ustr);
} if (!(cppToBinaryMapping_.is() && binaryToCppMapping_.is())) { throw css::uno::RuntimeException(u"URP: no C++ UNO mapping"_ustr);
}
passive_.set(); // coverity[uninit_member] - random_ is set in due course by the reader_ thread's state machine
}
void Bridge::start() {
rtl::Reference r(new Reader(this));
rtl::Reference w(new Writer(this));
{
std::lock_guard g(mutex_);
assert(
state_ == STATE_INITIAL && threadPool_ == nullptr && !writer_.is() &&
!reader_.is());
threadPool_ = uno_threadpool_create();
assert(threadPool_ != nullptr);
reader_ = r;
writer_ = w;
state_ = STATE_STARTED;
} // It is important to call reader_->launch() last here; both // Writer::execute and Reader::execute can call Bridge::terminate, but // Writer::execute is initially blocked in unblocked_.wait() until // Reader::execute has called bridge_->sendRequestChangeRequest(), so // effectively only reader_->launch() can lead to an early call to // Bridge::terminate
w->launch();
r->launch();
}
void Bridge::terminate(bool final) {
uno_ThreadPool tp; // Make sure function-local variables (Stubs s, etc.) are destroyed before // the final uno_threadpool_destroy/threadPool_ = 0:
{
rtl::Reference< Reader > r;
rtl::Reference< Writer > w; bool joinW;
Listeners ls;
{
std::unique_lock g(mutex_); switch (state_) { case STATE_INITIAL: // via ~Bridge -> dispose -> terminate case STATE_FINAL: return; case STATE_STARTED: break; case STATE_TERMINATED: if (final) {
g.unlock();
terminated_.wait();
{
std::lock_guard g2(mutex_);
tp = threadPool_;
threadPool_ = nullptr; if (reader_.is()) { if (!isThread(reader_.get())) {
r = reader_;
}
reader_.clear();
} if (writer_.is()) { if (!isThread(writer_.get())) {
w = writer_;
}
writer_.clear();
}
state_ = STATE_FINAL;
}
assert(!(r.is() && w.is())); if (r.is()) {
r->join();
} elseif (w.is()) {
w->join();
} if (tp != nullptr) {
uno_threadpool_destroy(tp);
}
} return;
}
tp = threadPool_;
assert(!(final && isThread(reader_.get()))); if (!isThread(reader_.get())) {
std::swap(reader_, r);
}
w = writer_;
joinW = !isThread(writer_.get());
assert(!final || joinW); if (joinW) {
writer_.clear();
}
ls.swap(listeners_);
state_ = final ? STATE_FINAL : STATE_TERMINATED;
} try {
connection_->close();
} catch (const css::io::IOException & e) {
SAL_INFO("binaryurp", "caught IO exception '" << e << '\'');
}
assert(w.is());
w->stop(); if (r.is()) {
r->join();
} if (joinW) {
w->join();
}
assert(tp != nullptr);
uno_threadpool_dispose(tp);
Stubs s;
{
std::lock_guard g(mutex_);
s.swap(stubs_);
} for (auto & stub : s)
{ for (auto & item : stub.second)
{
SAL_INFO( "binaryurp", "stub '" << stub.first << "', '" << toString(item.first)
<< "' still mapped at Bridge::terminate");
binaryUno_.get()->pExtEnv->revokeInterface(
binaryUno_.get()->pExtEnv, item.second.object.get());
}
}
factory_->removeBridge(this); for (autoconst& listener : ls)
{ try {
listener->disposing(
css::lang::EventObject(
getXWeak()));
} catch (const css::uno::RuntimeException & e) {
SAL_WARN("binaryurp", "caught " << e);
}
}
} if (final) {
uno_threadpool_destroy(tp);
}
{
std::lock_guard g(mutex_); if (final) {
threadPool_ = nullptr;
}
}
terminated_.set();
}
void Bridge::dispose() { // For terminate(true) not to deadlock, an external protocol must ensure // that dispose is not called from a thread pool worker thread (that dispose // is never called from the reader or writer thread is already ensured // internally):
terminate(true); // OOo expects dispose to not return while there are still remote calls in // progress; an external protocol must ensure that dispose is not called // from within an incoming or outgoing remote call, as passive_.wait() would // otherwise deadlock:
passive_.wait();
}
void Bridge::makeReleaseCall(
OUString const & oid, css::uno::TypeDescription const & type)
{ //HACK to decouple the processing of release calls from all other threads. Normally, sending // the release request should use the current thread's TID (via AttachThread), which would cause // that asynchronous request to be processed by a physical thread that is paired with the // physical thread processing the normal synchronous call stack (see ThreadIdHashMap in // cppu/source/threadpool/threadpool.hxx). However, that can lead to deadlock when a thread // illegally makes a synchronous UNO call with the SolarMutex locked (e.g., // SfxBaseModel::postEvent_Impl in sfx2/source/doc/sfxbasemodel.cxx doing documentEventOccurred // and notifyEvent calls), and while that call is on the stack the remote side sends back some // release request on the same logical UNO thread for an object that wants to acquire the // SolarMutex in its destructor (e.g., SwXTextDocument in sw/inc/unotxdoc.hxx holding its // m_pImpl via an sw::UnoImplPtr). While the correct approach would be to not make UNO calls // with the SolarMutex (or any other mutex) locked, fixing that would probably be a heroic // effort. So for now live with this hack, hoping that it does not introduce any new issues of // its own: staticautoconst tid = [] { static sal_Int8 const id[] = {'r', 'e', 'l', 'e', 'a', 's', 'e', 'h', 'a', 'c', 'k'}; return rtl::ByteSequence(id, std::size(id));
}();
sendRequest(
tid, oid, type,
css::uno::TypeDescription(u"com.sun.star.uno.XInterface::release"_ustr),
std::vector< BinaryAny >());
}
void Bridge::terminateWhenUnused(bool unused) { if (unused) { // That the current thread considers the bridge unused implies that it // is not within an incoming or outgoing remote call (so calling // terminate cannot lead to deadlock):
terminate(false);
}
}
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 und die Messung sind noch experimentell.