summaryrefslogtreecommitdiff
path: root/binaryurp/source/bridge.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'binaryurp/source/bridge.cxx')
-rw-r--r--binaryurp/source/bridge.cxx131
1 files changed, 103 insertions, 28 deletions
diff --git a/binaryurp/source/bridge.cxx b/binaryurp/source/bridge.cxx
index f591fe0e9e43..13987fe3bd51 100644
--- a/binaryurp/source/bridge.cxx
+++ b/binaryurp/source/bridge.cxx
@@ -105,11 +105,9 @@ extern "C" void SAL_CALL freeProxyCallback(uno_ExtEnvironment *, void * pProxy)
static_cast< Proxy * >(pProxy)->do_free();
}
-void joinThread(osl::Thread * thread) {
+bool isThread(osl::Thread * thread) {
assert(thread != 0);
- if (thread->getIdentifier() != osl::Thread::getCurrentIdentifier()) {
- thread->join();
- }
+ return osl::Thread::getCurrentIdentifier() == thread->getIdentifier();
}
class AttachThread: private boost::noncopyable {
@@ -213,8 +211,8 @@ Bridge::Bridge(
rtl::OUString(
RTL_CONSTASCII_USTRINGPARAM(
"com.sun.star.bridge.XProtocolProperties::commitChange"))),
- threadPool_(0), currentContextMode_(false), proxies_(0), calls_(0),
- normalCall_(false), activeCalls_(0), terminated_(false),
+ state_(STATE_INITIAL), threadPool_(0), currentContextMode_(false),
+ proxies_(0), calls_(0), normalCall_(false), activeCalls_(0),
mode_(MODE_REQUESTED)
{
assert(factory.is() && connection.is());
@@ -238,11 +236,14 @@ void Bridge::start() {
rtl::Reference< Writer > w(new Writer(this));
{
osl::MutexGuard g(mutex_);
- assert(threadPool_ == 0 && !writer_.is() && !reader_.is());
+ assert(
+ state_ == STATE_INITIAL && threadPool_ == 0 && !writer_.is() &&
+ !reader_.is());
threadPool_ = uno_threadpool_create();
assert(threadPool_ != 0);
reader_ = r;
writer_ = w;
+ state_ = STATE_STARTED;
}
// It is important to call reader_->create() last here; both
// Writer::execute and Reader::execute can call Bridge::terminate, but
@@ -254,21 +255,62 @@ void Bridge::start() {
r->create();
}
-void Bridge::terminate() {
+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;
{
- osl::MutexGuard g(mutex_);
- if (terminated_) {
+ osl::ClearableMutexGuard 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.clear();
+ terminated_.wait();
+ {
+ osl::MutexGuard g2(mutex_);
tp = threadPool_;
+ threadPool_ = 0;
+ assert(!(reader_.is() && isThread(reader_.get())));
std::swap(reader_, r);
+ assert(!(writer_.is() && isThread(writer_.get())));
std::swap(writer_, w);
+ state_ = STATE_FINAL;
+ }
+ assert(!(r.is() && w.is()));
+ if (r.is()) {
+ r->join();
+ } else if (w.is()) {
+ w->join();
+ }
+ if (tp != 0) {
+ 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_);
- terminated_ = true;
+ state_ = final ? STATE_FINAL : STATE_TERMINATED;
}
try {
connection_->close();
@@ -277,8 +319,12 @@ void Bridge::terminate() {
}
assert(w.is());
w->stop();
- joinThread(r.get());
- joinThread(w.get());
+ if (r.is()) {
+ r->join();
+ }
+ if (joinW) {
+ w->join();
+ }
assert(tp != 0);
uno_threadpool_dispose(tp);
Stubs s;
@@ -287,7 +333,8 @@ void Bridge::terminate() {
s.swap(stubs_);
}
for (Stubs::iterator i(s.begin()); i != s.end(); ++i) {
- for (Stub::iterator j(i->second.begin()); j != i->second.end(); ++j) {
+ for (Stub::iterator j(i->second.begin()); j != i->second.end(); ++j)
+ {
SAL_INFO(
"binaryurp",
"stub '" << i->first << "', '" << toString(j->first)
@@ -304,11 +351,22 @@ void Bridge::terminate() {
static_cast< cppu::OWeakObject * >(this)));
} catch (const css::uno::RuntimeException & e) {
SAL_WARN(
- "binaryurp", "caught runtime exception '" << e.Message << '\'');
+ "binaryurp",
+ "caught runtime exception '" << e.Message << '\'');
}
}
+ }
+ if (final) {
uno_threadpool_destroy(tp);
}
+ {
+ osl::MutexGuard g(mutex_);
+ if (final) {
+ threadPool_ = 0;
+ }
+ }
+ terminated_.set();
+}
css::uno::Reference< css::connection::XConnection > Bridge::getConnection()
const
@@ -339,19 +397,14 @@ BinaryAny Bridge::mapCppToBinaryAny(css::uno::Any const & cppAny) {
uno_ThreadPool Bridge::getThreadPool() {
osl::MutexGuard g(mutex_);
+ checkDisposed();
assert(threadPool_ != 0);
return threadPool_;
}
rtl::Reference< Writer > Bridge::getWriter() {
osl::MutexGuard g(mutex_);
- if (terminated_) {
- throw css::lang::DisposedException(
- rtl::OUString(
- RTL_CONSTASCII_USTRINGPARAM(
- "Binary URP bridge already disposed")),
- static_cast< cppu::OWeakObject * >(this));
- }
+ checkDisposed();
assert(writer_.is());
return writer_;
}
@@ -822,9 +875,15 @@ bool Bridge::isCurrentContextMode() {
}
Bridge::~Bridge() {
- if (getThreadPool() != 0) {
- terminate();
+#if OSL_DEBUG_LEVEL > 0
+ {
+ osl::MutexGuard g(mutex_);
+ SAL_WARN_IF(
+ state_ == STATE_STARTED || state_ == STATE_TERMINATED, "binaryurp",
+ "undisposed bridge, potential deadlock ahead");
}
+#endif
+ dispose();
}
css::uno::Reference< css::uno::XInterface > Bridge::getInstance(
@@ -885,7 +944,11 @@ rtl::OUString Bridge::getDescription() throw (css::uno::RuntimeException) {
}
void Bridge::dispose() throw (css::uno::RuntimeException) {
- terminate();
+ // 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
@@ -900,7 +963,8 @@ void Bridge::addEventListener(
assert(xListener.is());
{
osl::MutexGuard g(mutex_);
- if (!terminated_) {
+ assert(state_ != STATE_INITIAL);
+ if (state_ == STATE_STARTED) {
listeners_.push_back(xListener);
return;
}
@@ -995,7 +1059,18 @@ void Bridge::terminateWhenUnused(bool 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();
+ terminate(false);
+ }
+}
+
+void Bridge::checkDisposed() {
+ assert(state_ != STATE_INITIAL);
+ if (state_ != STATE_STARTED) {
+ throw css::lang::DisposedException(
+ rtl::OUString(
+ RTL_CONSTASCII_USTRINGPARAM(
+ "Binary URP bridge already disposed")),
+ static_cast< cppu::OWeakObject * >(this));
}
}