1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
29 #include <com/sun/star/bridge/InvalidProtocolChangeException.hpp>
30 #include <com/sun/star/bridge/XBridge.hpp>
31 #include <com/sun/star/bridge/XInstanceProvider.hpp>
32 #include <com/sun/star/bridge/XProtocolProperties.hpp>
33 #include <com/sun/star/connection/XConnection.hpp>
34 #include <com/sun/star/io/IOException.hpp>
35 #include <com/sun/star/lang/DisposedException.hpp>
36 #include <com/sun/star/lang/EventObject.hpp>
37 #include <com/sun/star/lang/XEventListener.hpp>
38 #include <com/sun/star/uno/Reference.hxx>
39 #include <com/sun/star/uno/RuntimeException.hpp>
40 #include <com/sun/star/uno/Sequence.hxx>
41 #include <com/sun/star/uno/XInterface.hpp>
42 #include <cppuhelper/exc_hlp.hxx>
43 #include <cppuhelper/weak.hxx>
44 #include <osl/mutex.hxx>
45 #include <osl/thread.hxx>
46 #include <rtl/byteseq.hxx>
47 #include <rtl/random.h>
48 #include <rtl/ref.hxx>
49 #include <rtl/string.h>
50 #include <rtl/ustring.hxx>
51 #include <sal/log.hxx>
52 #include <sal/types.h>
53 #include <typelib/typeclass.h>
54 #include <typelib/typedescription.h>
55 #include <typelib/typedescription.hxx>
56 #include <uno/dispatcher.hxx>
57 #include <uno/environment.hxx>
58 #include <uno/lbnames.h>
60 #include "binaryany.hxx"
62 #include "bridgefactory.hxx"
63 #include "incomingreply.hxx"
64 #include "lessoperators.hxx"
65 #include "outgoingrequest.hxx"
66 #include "outgoingrequests.hxx"
76 rtlRandomPool pool
= rtl_random_createPool();
77 rtl_random_getBytes(pool
, &n
, sizeof n
);
78 rtl_random_destroyPool(pool
);
82 OUString
toString(css::uno::TypeDescription
const & type
) {
83 typelib_TypeDescription
* d
= type
.get();
84 assert(d
!= nullptr && d
->pTypeName
!= nullptr);
85 return OUString(d
->pTypeName
);
88 extern "C" void freeProxyCallback(
89 SAL_UNUSED_PARAMETER uno_ExtEnvironment
*, void * pProxy
)
91 assert(pProxy
!= nullptr);
92 static_cast< Proxy
* >(pProxy
)->do_free();
95 bool isThread(salhelper::Thread
* thread
) {
96 assert(thread
!= nullptr);
97 return osl::Thread::getCurrentIdentifier() == thread
->getIdentifier();
102 explicit AttachThread(uno_ThreadPool threadPool
);
106 const rtl::ByteSequence
& getTid() const throw () { return tid_
;}
109 AttachThread(const AttachThread
&) = delete;
110 AttachThread
& operator=(const AttachThread
&) = delete;
112 uno_ThreadPool threadPool_
;
113 rtl::ByteSequence tid_
;
116 AttachThread::AttachThread(uno_ThreadPool threadPool
): threadPool_(threadPool
) {
117 sal_Sequence
* s
= nullptr;
118 uno_getIdOfCurrentThread(&s
);
119 tid_
= rtl::ByteSequence(s
, rtl::BYTESEQ_NOACQUIRE
);
120 uno_threadpool_attach(threadPool_
);
123 AttachThread::~AttachThread() {
124 uno_threadpool_detach(threadPool_
);
125 uno_releaseIdFromCurrentThread();
129 class PopOutgoingRequest
{
132 OutgoingRequests
& requests
, rtl::ByteSequence
const & tid
,
133 OutgoingRequest
const & request
);
135 ~PopOutgoingRequest();
140 PopOutgoingRequest(const PopOutgoingRequest
&) = delete;
141 PopOutgoingRequest
& operator=(const PopOutgoingRequest
&) = delete;
143 OutgoingRequests
& requests_
;
144 rtl::ByteSequence tid_
;
148 PopOutgoingRequest::PopOutgoingRequest(
149 OutgoingRequests
& requests
, rtl::ByteSequence
const & tid
,
150 OutgoingRequest
const & request
):
151 requests_(requests
), tid_(tid
), cleared_(false)
153 requests_
.push(tid_
, request
);
156 PopOutgoingRequest::~PopOutgoingRequest() {
162 void PopOutgoingRequest::clear() {
168 struct Bridge::SubStub
{
169 com::sun::star::uno::UnoInterfaceReference object
;
171 sal_uInt32 references
;
175 rtl::Reference
< BridgeFactory
> const & factory
, OUString
const & name
,
176 css::uno::Reference
< css::connection::XConnection
> const & connection
,
177 css::uno::Reference
< css::bridge::XInstanceProvider
> const & provider
):
178 factory_(factory
), name_(name
), connection_(connection
),
180 binaryUno_(UNO_LB_UNO
),
181 cppToBinaryMapping_(CPPU_CURRENT_LANGUAGE_BINDING_NAME
, UNO_LB_UNO
),
182 binaryToCppMapping_(UNO_LB_UNO
, CPPU_CURRENT_LANGUAGE_BINDING_NAME
),
184 reinterpret_cast< sal_Int8
const * >(".UrpProtocolPropertiesTid"),
185 RTL_CONSTASCII_LENGTH(".UrpProtocolPropertiesTid")),
186 protPropOid_("UrpProtocolProperties"),
189 css::uno::Reference
< css::bridge::XProtocolProperties
> >::get()),
190 protPropRequest_("com.sun.star.bridge.XProtocolProperties::requestChange"),
191 protPropCommit_("com.sun.star.bridge.XProtocolProperties::commitChange"),
192 state_(STATE_INITIAL
), threadPool_(nullptr), currentContextMode_(false),
193 proxies_(0), calls_(0), normalCall_(false), activeCalls_(0),
194 mode_(MODE_REQUESTED
)
196 assert(factory
.is() && connection
.is());
197 if (!binaryUno_
.is()) {
198 throw css::uno::RuntimeException("URP: no binary UNO environment");
200 if (!(cppToBinaryMapping_
.is() && binaryToCppMapping_
.is())) {
201 throw css::uno::RuntimeException("URP: no C++ UNO mapping");
206 void Bridge::start() {
207 rtl::Reference
r(new Reader(this));
208 rtl::Reference
w(new Writer(this));
210 osl::MutexGuard
g(mutex_
);
212 state_
== STATE_INITIAL
&& threadPool_
== nullptr && !writer_
.is() &&
214 threadPool_
= uno_threadpool_create();
215 assert(threadPool_
!= nullptr);
218 state_
= STATE_STARTED
;
220 // It is important to call reader_->launch() last here; both
221 // Writer::execute and Reader::execute can call Bridge::terminate, but
222 // Writer::execute is initially blocked in unblocked_.wait() until
223 // Reader::execute has called bridge_->sendRequestChangeRequest(), so
224 // effectively only reader_->launch() can lead to an early call to
230 void Bridge::terminate(bool final
) {
232 // Make sure function-local variables (Stubs s, etc.) are destroyed before
233 // the final uno_threadpool_destroy/threadPool_ = 0:
235 rtl::Reference
< Reader
> r
;
236 rtl::Reference
< Writer
> w
;
240 osl::ClearableMutexGuard
g(mutex_
);
242 case STATE_INITIAL
: // via ~Bridge -> dispose -> terminate
247 case STATE_TERMINATED
:
252 osl::MutexGuard
g2(mutex_
);
254 threadPool_
= nullptr;
256 if (!isThread(reader_
.get())) {
262 if (!isThread(writer_
.get())) {
267 state_
= STATE_FINAL
;
269 assert(!(r
.is() && w
.is()));
276 uno_threadpool_destroy(tp
);
282 assert(!(final
&& isThread(reader_
.get())));
283 if (!isThread(reader_
.get())) {
284 std::swap(reader_
, r
);
287 joinW
= !isThread(writer_
.get());
288 assert(!final
|| joinW
);
293 state_
= final
? STATE_FINAL
: STATE_TERMINATED
;
296 connection_
->close();
297 } catch (const css::io::IOException
& e
) {
298 SAL_INFO("binaryurp", "caught IO exception '" << e
<< '\'');
308 assert(tp
!= nullptr);
309 uno_threadpool_dispose(tp
);
312 osl::MutexGuard
g(mutex_
);
315 for (auto & stub
: s
)
317 for (auto & item
: stub
.second
)
321 "stub '" << stub
.first
<< "', '" << toString(item
.first
)
322 << "' still mapped at Bridge::terminate");
323 binaryUno_
.get()->pExtEnv
->revokeInterface(
324 binaryUno_
.get()->pExtEnv
, item
.second
.object
.get());
327 factory_
->removeBridge(this);
328 for (auto const& listener
: ls
)
332 css::lang::EventObject(
333 static_cast< cppu::OWeakObject
* >(this)));
334 } catch (const css::uno::RuntimeException
& e
) {
335 SAL_WARN("binaryurp", "caught " << e
);
340 uno_threadpool_destroy(tp
);
343 osl::MutexGuard
g(mutex_
);
345 threadPool_
= nullptr;
352 BinaryAny
Bridge::mapCppToBinaryAny(css::uno::Any
const & cppAny
) {
353 css::uno::Any
in(cppAny
);
356 uno_copyAndConvertData(
358 css::uno::TypeDescription(cppu::UnoType
< css::uno::Any
>::get()).get(),
359 cppToBinaryMapping_
.get());
363 uno_ThreadPool
Bridge::getThreadPool() {
364 osl::MutexGuard
g(mutex_
);
366 assert(threadPool_
!= nullptr);
370 rtl::Reference
< Writer
> Bridge::getWriter() {
371 osl::MutexGuard
g(mutex_
);
373 assert(writer_
.is());
377 css::uno::UnoInterfaceReference
Bridge::registerIncomingInterface(
378 OUString
const & oid
, css::uno::TypeDescription
const & type
)
382 return css::uno::UnoInterfaceReference();
384 css::uno::UnoInterfaceReference
obj(findStub(oid
, type
));
386 binaryUno_
.get()->pExtEnv
->getRegisteredInterface(
387 binaryUno_
.get()->pExtEnv
,
388 reinterpret_cast< void ** >(&obj
.m_pUnoI
), oid
.pData
,
389 reinterpret_cast< typelib_InterfaceTypeDescription
* >(type
.get()));
391 makeReleaseCall(oid
, type
);
393 obj
.set(new Proxy(this, oid
, type
), SAL_NO_ACQUIRE
);
395 osl::MutexGuard
g(mutex_
);
396 assert(proxies_
< std::numeric_limits
< std::size_t >::max());
399 binaryUno_
.get()->pExtEnv
->registerProxyInterface(
400 binaryUno_
.get()->pExtEnv
,
401 reinterpret_cast< void ** >(&obj
.m_pUnoI
), &freeProxyCallback
,
403 reinterpret_cast< typelib_InterfaceTypeDescription
* >(
410 OUString
Bridge::registerOutgoingInterface(
411 css::uno::UnoInterfaceReference
const & object
,
412 css::uno::TypeDescription
const & type
)
419 if (!Proxy::isProxy(this, object
, &oid
)) {
420 binaryUno_
.get()->pExtEnv
->getObjectIdentifier(
421 binaryUno_
.get()->pExtEnv
, &oid
.pData
, object
.get());
422 osl::MutexGuard
g(mutex_
);
423 Stubs::iterator
i(stubs_
.find(oid
));
425 Stub
* stub
= i
== stubs_
.end() ? &newStub
: &i
->second
;
426 Stub::iterator
j(stub
->find(type
));
427 //TODO: Release sub-stub if it is not successfully sent to remote side
428 // (otherwise, stub will leak until terminate()):
429 if (j
== stub
->end()) {
430 j
= stub
->emplace(type
, SubStub()).first
;
431 if (stub
== &newStub
) {
432 i
= stubs_
.emplace(oid
, Stub()).first
;
433 std::swap(i
->second
, newStub
);
434 j
= i
->second
.find(type
);
435 assert(j
!= i
->second
.end());
437 j
->second
.object
= object
;
438 j
->second
.references
= 1;
439 binaryUno_
.get()->pExtEnv
->registerInterface(
440 binaryUno_
.get()->pExtEnv
,
441 reinterpret_cast< void ** >(&j
->second
.object
.m_pUnoI
),
443 reinterpret_cast< typelib_InterfaceTypeDescription
* >(
446 assert(stub
!= &newStub
);
447 if (j
->second
.references
== SAL_MAX_UINT32
) {
448 throw css::uno::RuntimeException(
449 "URP: stub reference count overflow");
451 ++j
->second
.references
;
457 css::uno::UnoInterfaceReference
Bridge::findStub(
458 OUString
const & oid
, css::uno::TypeDescription
const & type
)
460 assert(!oid
.isEmpty() && type
.is());
461 osl::MutexGuard
g(mutex_
);
462 Stubs::iterator
i(stubs_
.find(oid
));
463 if (i
!= stubs_
.end()) {
464 Stub::iterator
j(i
->second
.find(type
));
465 if (j
!= i
->second
.end()) {
466 return j
->second
.object
;
468 for (auto const& item
: i
->second
)
470 if (typelib_typedescription_isAssignableFrom(
471 type
.get(), item
.first
.get()))
473 return item
.second
.object
;
477 return css::uno::UnoInterfaceReference();
480 void Bridge::releaseStub(
481 OUString
const & oid
, css::uno::TypeDescription
const & type
)
483 assert(!oid
.isEmpty() && type
.is());
484 css::uno::UnoInterfaceReference obj
;
487 osl::MutexGuard
g(mutex_
);
488 Stubs::iterator
i(stubs_
.find(oid
));
489 if (i
== stubs_
.end()) {
490 throw css::uno::RuntimeException("URP: release unknown stub");
492 Stub::iterator
j(i
->second
.find(type
));
493 if (j
== i
->second
.end()) {
494 throw css::uno::RuntimeException("URP: release unknown stub");
496 assert(j
->second
.references
> 0);
497 --j
->second
.references
;
498 if (j
->second
.references
== 0) {
499 obj
= j
->second
.object
;
501 if (i
->second
.empty()) {
505 unused
= becameUnused();
508 binaryUno_
.get()->pExtEnv
->revokeInterface(
509 binaryUno_
.get()->pExtEnv
, obj
.get());
511 terminateWhenUnused(unused
);
514 void Bridge::resurrectProxy(Proxy
& proxy
) {
515 uno_Interface
* p
= &proxy
;
516 binaryUno_
.get()->pExtEnv
->registerProxyInterface(
517 binaryUno_
.get()->pExtEnv
,
518 reinterpret_cast< void ** >(&p
), &freeProxyCallback
,
519 proxy
.getOid().pData
,
520 reinterpret_cast< typelib_InterfaceTypeDescription
* >(
521 proxy
.getType().get()));
525 void Bridge::revokeProxy(Proxy
& proxy
) {
526 binaryUno_
.get()->pExtEnv
->revokeInterface(
527 binaryUno_
.get()->pExtEnv
, &proxy
);
530 void Bridge::freeProxy(Proxy
& proxy
) {
532 makeReleaseCall(proxy
.getOid(), proxy
.getType());
533 } catch (const css::uno::RuntimeException
& e
) {
535 "binaryurp", "caught runtime exception '" << e
<< '\'');
536 } catch (const std::exception
& e
) {
537 SAL_WARN("binaryurp", "caught C++ exception '" << e
.what() << '\'');
541 osl::MutexGuard
g(mutex_
);
542 assert(proxies_
> 0);
544 unused
= becameUnused();
546 terminateWhenUnused(unused
);
549 void Bridge::incrementCalls(bool normalCall
) throw () {
550 osl::MutexGuard
g(mutex_
);
551 assert(calls_
< std::numeric_limits
< std::size_t >::max());
553 normalCall_
|= normalCall
;
556 void Bridge::decrementCalls() {
559 osl::MutexGuard
g(mutex_
);
562 unused
= becameUnused();
564 terminateWhenUnused(unused
);
567 void Bridge::incrementActiveCalls() throw () {
568 osl::MutexGuard
g(mutex_
);
570 activeCalls_
<= calls_
&&
571 activeCalls_
< std::numeric_limits
< std::size_t >::max());
576 void Bridge::decrementActiveCalls() throw () {
577 osl::MutexGuard
g(mutex_
);
578 assert(activeCalls_
<= calls_
&& activeCalls_
> 0);
580 if (activeCalls_
== 0) {
585 bool Bridge::makeCall(
586 OUString
const & oid
, css::uno::TypeDescription
const & member
,
587 bool setter
, std::vector
< BinaryAny
> const & inArguments
,
588 BinaryAny
* returnValue
, std::vector
< BinaryAny
> * outArguments
)
590 std::unique_ptr
< IncomingReply
> resp
;
592 uno_ThreadPool tp
= getThreadPool();
593 AttachThread
att(tp
);
594 PopOutgoingRequest
pop(
595 outgoingRequests_
, att
.getTid(),
596 OutgoingRequest(OutgoingRequest::KIND_NORMAL
, member
, setter
));
598 att
.getTid(), oid
, css::uno::TypeDescription(), member
,
601 incrementCalls(true);
602 incrementActiveCalls();
604 uno_threadpool_enter(tp
, &job
);
605 resp
.reset(static_cast< IncomingReply
* >(job
));
606 decrementActiveCalls();
611 throw css::lang::DisposedException(
612 "Binary URP bridge disposed during call",
613 static_cast< cppu::OWeakObject
* >(this));
615 *returnValue
= resp
->returnValue
;
616 if (!resp
->exception
) {
617 *outArguments
= resp
->outArguments
;
619 return resp
->exception
;
622 void Bridge::sendRequestChangeRequest() {
623 assert(mode_
== MODE_REQUESTED
);
625 std::vector
< BinaryAny
> a
;
627 css::uno::TypeDescription(cppu::UnoType
< sal_Int32
>::get()),
629 sendProtPropRequest(OutgoingRequest::KIND_REQUEST_CHANGE
, a
);
632 void Bridge::handleRequestChangeReply(
633 bool exception
, BinaryAny
const & returnValue
)
636 throwException(exception
, returnValue
);
637 } catch (css::uno::RuntimeException
& e
) {
638 // Before OOo 2.2, Java URP would throw a RuntimeException when
639 // receiving a requestChange message (see i#35277 "Java URP: Support
640 // Manipulation of Protocol Properties"):
641 if (mode_
!= MODE_REQUESTED
) {
646 "requestChange caught " << e
<< " in state 'requested'");
648 getWriter()->unblock();
652 sal_Int32 n
= *static_cast< sal_Int32
* >(
653 returnValue
.getValue(
654 css::uno::TypeDescription(cppu::UnoType
< sal_Int32
>::get())));
661 case MODE_REPLY_MINUS1
:
663 mode_
= MODE_REQUESTED
;
670 assert(false); // this cannot happen
674 throw css::uno::RuntimeException(
675 "URP: requestChange reply with unexpected return value received",
676 static_cast< cppu::OWeakObject
* >(this));
681 sendRequestChangeRequest();
686 sendCommitChangeRequest();
689 assert(false); // this cannot happen
694 void Bridge::handleCommitChangeReply(
695 bool exception
, BinaryAny
const & returnValue
)
699 throwException(exception
, returnValue
);
700 } catch (const css::bridge::InvalidProtocolChangeException
&) {
704 setCurrentContextMode();
706 assert(mode_
== MODE_REQUESTED
|| mode_
== MODE_REPLY_1
);
708 getWriter()->unblock();
712 void Bridge::handleRequestChangeRequest(
713 rtl::ByteSequence
const & tid
, std::vector
< BinaryAny
> const & inArguments
)
715 assert(inArguments
.size() == 1);
719 sal_Int32 n2
= *static_cast< sal_Int32
* >(
720 inArguments
[0].getValue(
721 css::uno::TypeDescription(
722 cppu::UnoType
< sal_Int32
>::get())));
726 mode_
= MODE_REPLY_0
;
727 } else if (n2
== random_
) {
729 mode_
= MODE_REPLY_MINUS1
;
732 mode_
= MODE_REPLY_1
;
734 getWriter()->sendDirectReply(
735 tid
, protPropRequest_
, false,
737 css::uno::TypeDescription(
738 cppu::UnoType
< sal_Int32
>::get()),
740 std::vector
< BinaryAny
>());
745 mode_
= MODE_NORMAL_WAIT
;
747 getWriter()->queueReply(
748 tid
, protPropRequest_
, false, false,
750 css::uno::TypeDescription(
751 cppu::UnoType
< sal_Int32
>::get()),
753 std::vector
< BinaryAny
>(), false);
757 throw css::uno::RuntimeException(
758 "URP: unexpected requestChange request received",
759 static_cast< cppu::OWeakObject
* >(this));
763 void Bridge::handleCommitChangeRequest(
764 rtl::ByteSequence
const & tid
, std::vector
< BinaryAny
> const & inArguments
)
766 bool bCcMode
= false;
769 assert(inArguments
.size() == 1);
770 css::uno::Sequence
< css::bridge::ProtocolProperty
> s
;
771 [[maybe_unused
]] bool ok
= (mapBinaryToCppAny(inArguments
[0]) >>= s
);
773 for (const auto & pp
: std::as_const(s
)) {
774 if (pp
.Name
== "CurrentContext") {
779 ret
= mapCppToBinaryAny(
781 css::bridge::InvalidProtocolChangeException(
782 "InvalidProtocolChangeException",
783 css::uno::Reference
< css::uno::XInterface
>(), pp
,
790 getWriter()->sendDirectReply(
791 tid
, protPropCommit_
, bExc
, ret
, std::vector
< BinaryAny
>());
793 setCurrentContextMode();
795 getWriter()->unblock();
797 mode_
= MODE_REQUESTED
;
798 sendRequestChangeRequest();
801 case MODE_NORMAL_WAIT
:
802 getWriter()->queueReply(
803 tid
, protPropCommit_
, false, false, ret
, std::vector
< BinaryAny
>(),
808 throw css::uno::RuntimeException(
809 "URP: unexpected commitChange request received",
810 static_cast< cppu::OWeakObject
* >(this));
814 OutgoingRequest
Bridge::lastOutgoingRequest(rtl::ByteSequence
const & tid
) {
815 OutgoingRequest
req(outgoingRequests_
.top(tid
));
816 outgoingRequests_
.pop(tid
);
820 bool Bridge::isProtocolPropertiesRequest(
821 std::u16string_view oid
, css::uno::TypeDescription
const & type
) const
823 return oid
== protPropOid_
&& type
.equals(protPropType_
);
826 void Bridge::setCurrentContextMode() {
827 osl::MutexGuard
g(mutex_
);
828 currentContextMode_
= true;
831 bool Bridge::isCurrentContextMode() {
832 osl::MutexGuard
g(mutex_
);
833 return currentContextMode_
;
837 #if OSL_DEBUG_LEVEL > 0
839 osl::MutexGuard
g(mutex_
);
841 state_
== STATE_STARTED
|| state_
== STATE_TERMINATED
, "binaryurp",
842 "undisposed bridge \"" << name_
<<"\" in state " << state_
843 << ", potential deadlock ahead");
849 css::uno::Reference
< css::uno::XInterface
> Bridge::getInstance(
850 OUString
const & sInstanceName
)
852 if (sInstanceName
.isEmpty()) {
853 throw css::uno::RuntimeException(
854 "XBridge::getInstance sInstanceName must be non-empty",
855 static_cast< cppu::OWeakObject
* >(this));
857 for (sal_Int32 i
= 0; i
!= sInstanceName
.getLength(); ++i
) {
858 if (sInstanceName
[i
] > 0x7F) {
859 throw css::uno::RuntimeException(
860 "XBridge::getInstance sInstanceName contains non-ASCII"
864 css::uno::TypeDescription
ifc(cppu::UnoType
<css::uno::XInterface
>::get());
865 typelib_TypeDescription
* p
= ifc
.get();
866 std::vector
< BinaryAny
> inArgs
;
868 css::uno::TypeDescription(cppu::UnoType
< css::uno::Type
>::get()),
871 std::vector
< BinaryAny
> outArgs
;
872 bool bExc
= makeCall(
874 css::uno::TypeDescription(
875 "com.sun.star.uno.XInterface::queryInterface"),
876 false, inArgs
, &ret
, &outArgs
);
877 throwException(bExc
, ret
);
878 auto const t
= ret
.getType();
879 if (t
.get()->eTypeClass
== typelib_TypeClass_VOID
) {
882 if (!t
.equals(ifc
)) {
883 throw css::uno::RuntimeException(
884 "initial object queryInterface for OID \"" + sInstanceName
+ "\" returned ANY of type "
885 + OUString::unacquired(&t
.get()->pTypeName
));
887 auto const val
= *static_cast< uno_Interface
** >(ret
.getValue(ifc
));
888 if (val
== nullptr) {
889 throw css::uno::RuntimeException(
890 "initial object queryInterface for OID \"" + sInstanceName
891 + "\" returned null css.uno.XInterface ANY");
893 return css::uno::Reference
< css::uno::XInterface
>(
894 static_cast< css::uno::XInterface
* >(
895 binaryToCppMapping_
.mapInterface(
901 OUString
Bridge::getName() {
905 OUString
Bridge::getDescription() {
906 OUString b
= name_
+ ":" + connection_
->getDescription();
910 void Bridge::dispose() {
911 // For terminate(true) not to deadlock, an external protocol must ensure
912 // that dispose is not called from a thread pool worker thread (that dispose
913 // is never called from the reader or writer thread is already ensured
916 // OOo expects dispose to not return while there are still remote calls in
917 // progress; an external protocol must ensure that dispose is not called
918 // from within an incoming or outgoing remote call, as passive_.wait() would
919 // otherwise deadlock:
923 void Bridge::addEventListener(
924 css::uno::Reference
< css::lang::XEventListener
> const & xListener
)
926 assert(xListener
.is());
928 osl::MutexGuard
g(mutex_
);
929 assert(state_
!= STATE_INITIAL
);
930 if (state_
== STATE_STARTED
) {
931 listeners_
.push_back(xListener
);
935 xListener
->disposing(
936 css::lang::EventObject(static_cast< cppu::OWeakObject
* >(this)));
939 void Bridge::removeEventListener(
940 css::uno::Reference
< css::lang::XEventListener
> const & aListener
)
942 osl::MutexGuard
g(mutex_
);
943 Listeners::iterator
i(
944 std::find(listeners_
.begin(), listeners_
.end(), aListener
));
945 if (i
!= listeners_
.end()) {
950 void Bridge::sendCommitChangeRequest() {
951 assert(mode_
== MODE_REQUESTED
|| mode_
== MODE_REPLY_1
);
952 css::uno::Sequence
< css::bridge::ProtocolProperty
> s(1);
953 s
[0].Name
= "CurrentContext";
954 std::vector
< BinaryAny
> a
;
955 a
.push_back(mapCppToBinaryAny(css::uno::Any(s
)));
956 sendProtPropRequest(OutgoingRequest::KIND_COMMIT_CHANGE
, a
);
959 void Bridge::sendProtPropRequest(
960 OutgoingRequest::Kind kind
, std::vector
< BinaryAny
> const & inArguments
)
963 kind
== OutgoingRequest::KIND_REQUEST_CHANGE
||
964 kind
== OutgoingRequest::KIND_COMMIT_CHANGE
);
965 incrementCalls(false);
966 css::uno::TypeDescription
member(
967 kind
== OutgoingRequest::KIND_REQUEST_CHANGE
968 ? protPropRequest_
: protPropCommit_
);
969 PopOutgoingRequest
pop(
970 outgoingRequests_
, protPropTid_
, OutgoingRequest(kind
, member
, false));
971 getWriter()->sendDirectRequest(
972 protPropTid_
, protPropOid_
, protPropType_
, member
, inArguments
);
976 void Bridge::makeReleaseCall(
977 OUString
const & oid
, css::uno::TypeDescription
const & type
)
979 //HACK to decouple the processing of release calls from all other threads. Normally, sending
980 // the release request should use the current thread's TID (via AttachThread), which would cause
981 // that asynchronous request to be processed by a physical thread that is paired with the
982 // physical thread processing the normal synchronous call stack (see ThreadIdHashMap in
983 // cppu/source/threadpool/threadpool.hxx). However, that can lead to deadlock when a thread
984 // illegally makes a synchronous UNO call with the SolarMutex locked (e.g.,
985 // SfxBaseModel::postEvent_Impl in sfx2/source/doc/sfxbasemodel.cxx doing documentEventOccurred
986 // and notifyEvent calls), and while that call is on the stack the remote side sends back some
987 // release request on the same logical UNO thread for an object that wants to acquire the
988 // SolarMutex in its destructor (e.g., SwXTextDocument in sw/inc/unotxdoc.hxx holding its
989 // m_pImpl via an sw::UnoImplPtr). While the correct approach would be to not make UNO calls
990 // with the SolarMutex (or any other mutex) locked, fixing that would probably be a heroic
991 // effort. So for now live with this hack, hoping that it does not introduce any new issues of
993 static auto const tid
= [] {
994 static sal_Int8
const id
[] = {'r', 'e', 'l', 'e', 'a', 's', 'e', 'h', 'a', 'c', 'k'};
995 return rtl::ByteSequence(id
, SAL_N_ELEMENTS(id
));
999 css::uno::TypeDescription("com.sun.star.uno.XInterface::release"),
1000 std::vector
< BinaryAny
>());
1003 void Bridge::sendRequest(
1004 rtl::ByteSequence
const & tid
, OUString
const & oid
,
1005 css::uno::TypeDescription
const & type
,
1006 css::uno::TypeDescription
const & member
,
1007 std::vector
< BinaryAny
> const & inArguments
)
1009 getWriter()->queueRequest(tid
, oid
, type
, member
, inArguments
);
1012 void Bridge::throwException(bool exception
, BinaryAny
const & value
) {
1014 cppu::throwException(mapBinaryToCppAny(value
));
1018 css::uno::Any
Bridge::mapBinaryToCppAny(BinaryAny
const & binaryAny
) {
1019 BinaryAny
in(binaryAny
);
1022 uno_copyAndConvertData(
1024 css::uno::TypeDescription(cppu::UnoType
< css::uno::Any
>::get()).get(),
1025 binaryToCppMapping_
.get());
1029 bool Bridge::becameUnused() const {
1030 return stubs_
.empty() && proxies_
== 0 && calls_
== 0 && normalCall_
;
1033 void Bridge::terminateWhenUnused(bool unused
) {
1035 // That the current thread considers the bridge unused implies that it
1036 // is not within an incoming or outgoing remote call (so calling
1037 // terminate cannot lead to deadlock):
1042 void Bridge::checkDisposed() {
1043 assert(state_
!= STATE_INITIAL
);
1044 if (state_
!= STATE_STARTED
) {
1045 throw css::lang::DisposedException(
1046 "Binary URP bridge already disposed",
1047 static_cast< cppu::OWeakObject
* >(this));
1053 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */