| /************************************************************** |
| * |
| * 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 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_cppu.hxx" |
| |
| #include "osl/thread.hxx" |
| #include "osl/conditn.hxx" |
| #include "osl/mutex.hxx" |
| |
| #include "cppu/helper/purpenv/Environment.hxx" |
| #include "cppu/helper/purpenv/Mapping.hxx" |
| |
| |
| #ifdef debug |
| # define LOG_LIFECYCLE_AffineBridge |
| #endif |
| |
| #ifdef LOG_LIFECYCLE_AffineBridge |
| # include <iostream> |
| # define LOG_LIFECYCLE_AffineBridge_emit(x) x |
| |
| #else |
| # define LOG_LIFECYCLE_AffineBridge_emit(x) |
| |
| #endif |
| |
| class InnerThread; |
| class OuterThread; |
| |
| class SAL_DLLPRIVATE AffineBridge : public cppu::Enterable |
| { |
| public: |
| enum Msg |
| { |
| CB_DONE, |
| CB_FPOINTER |
| }; |
| |
| Msg m_message; |
| uno_EnvCallee * m_pCallee; |
| va_list * m_pParam; |
| |
| osl::Mutex m_innerMutex; |
| oslThreadIdentifier m_innerThreadId; |
| InnerThread * m_pInnerThread; |
| osl::Condition m_innerCondition; |
| sal_Int32 m_enterCount; |
| |
| osl::Mutex m_outerMutex; |
| oslThreadIdentifier m_outerThreadId; |
| osl::Condition m_outerCondition; |
| OuterThread * m_pOuterThread; |
| |
| explicit AffineBridge(void); |
| virtual ~AffineBridge(void); |
| |
| virtual void v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam); |
| virtual void v_callOut_v (uno_EnvCallee * pCallee, va_list * pParam); |
| |
| virtual void v_enter(void); |
| virtual void v_leave(void); |
| |
| virtual int v_isValid(rtl::OUString * pReason); |
| |
| void innerDispatch(void); |
| void outerDispatch(int loop); |
| }; |
| |
| class SAL_DLLPRIVATE InnerThread : public osl::Thread |
| { |
| virtual void SAL_CALL run(void); |
| |
| AffineBridge * m_pAffineBridge; |
| |
| public: |
| InnerThread(AffineBridge * threadEnvironment) |
| : m_pAffineBridge(threadEnvironment) |
| { |
| create(); |
| } |
| }; |
| |
| void InnerThread::run(void) |
| { |
| m_pAffineBridge->enter(); |
| m_pAffineBridge->innerDispatch(); |
| m_pAffineBridge->leave(); |
| } |
| |
| class SAL_DLLPRIVATE OuterThread : public osl::Thread |
| { |
| virtual void SAL_CALL run(void); |
| |
| AffineBridge * m_pAffineBridge; |
| |
| public: |
| OuterThread(AffineBridge * threadEnvironment); |
| }; |
| |
| OuterThread::OuterThread(AffineBridge * threadEnvironment) |
| : m_pAffineBridge(threadEnvironment) |
| { |
| create(); |
| } |
| |
| void OuterThread::run(void) |
| { |
| osl::MutexGuard guard(m_pAffineBridge->m_outerMutex); |
| |
| m_pAffineBridge->m_outerThreadId = getIdentifier(); |
| m_pAffineBridge->outerDispatch(0); |
| m_pAffineBridge->m_outerThreadId = 0; |
| |
| m_pAffineBridge->m_pOuterThread = NULL; |
| m_pAffineBridge = NULL; |
| } |
| |
| |
| AffineBridge::AffineBridge(void) |
| : m_innerThreadId(0), |
| m_pInnerThread (NULL), |
| m_enterCount (0), |
| m_outerThreadId(0), |
| m_pOuterThread (NULL) |
| { |
| LOG_LIFECYCLE_AffineBridge_emit(fprintf(stderr, "LIFE: %s -> %p\n", "AffineBridge::AffineBridge(uno_Environment * pEnv)", this)); |
| } |
| |
| AffineBridge::~AffineBridge(void) |
| { |
| LOG_LIFECYCLE_AffineBridge_emit(fprintf(stderr, "LIFE: %s -> %p\n", "AffineBridge::~AffineBridge(void)", this)); |
| |
| if (m_pInnerThread && osl_getThreadIdentifier(NULL) != m_innerThreadId) |
| { |
| m_message = CB_DONE; |
| m_innerCondition.set(); |
| |
| m_pInnerThread->join(); |
| } |
| |
| delete m_pInnerThread; |
| |
| if (m_pOuterThread) |
| { |
| m_pOuterThread->join(); |
| delete m_pOuterThread; |
| } |
| } |
| |
| |
| void AffineBridge::outerDispatch(int loop) |
| { |
| OSL_ASSERT(m_outerThreadId == osl_getThreadIdentifier(NULL)); |
| OSL_ASSERT(m_innerThreadId != m_outerThreadId); |
| |
| Msg mm; |
| |
| do |
| { |
| // FIXME: created outer thread must not wait |
| // in case of no message |
| // note: no message can happen in case newly created |
| // outer thread acquire outerMutex after a real outer |
| // thread enters outerDispatch! |
| m_outerCondition.wait(); |
| m_outerCondition.reset(); |
| |
| mm = m_message; |
| |
| switch(mm) |
| { |
| case CB_DONE: |
| break; |
| |
| case CB_FPOINTER: |
| { |
| m_pCallee(m_pParam); |
| |
| m_message = CB_DONE; |
| m_innerCondition.set(); |
| break; |
| } |
| default: |
| abort(); |
| } |
| } |
| while(mm != CB_DONE && loop); |
| } |
| |
| void AffineBridge::innerDispatch(void) |
| { |
| OSL_ASSERT(m_innerThreadId == osl_getThreadIdentifier(NULL)); |
| OSL_ASSERT(m_innerThreadId != m_outerThreadId); |
| |
| Msg mm; |
| |
| do |
| { |
| m_innerCondition.wait(); |
| m_innerCondition.reset(); |
| |
| mm = m_message; |
| |
| switch(mm) |
| { |
| case CB_DONE: |
| break; |
| |
| case CB_FPOINTER: |
| { |
| m_pCallee(m_pParam); |
| |
| m_message = CB_DONE; |
| m_outerCondition.set(); |
| break; |
| } |
| default: |
| abort(); |
| } |
| } |
| while(mm != CB_DONE); |
| } |
| |
| void AffineBridge::v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam) |
| { |
| osl::MutexGuard guard(m_outerMutex); // only one thread at a time can call into |
| |
| if (m_innerThreadId == 0) // no inner thread yet |
| { |
| m_pInnerThread = new InnerThread(this); |
| m_pInnerThread->resume(); |
| } |
| |
| bool resetId = false; |
| if (!m_outerThreadId) |
| { |
| m_outerThreadId = osl_getThreadIdentifier(NULL); |
| resetId = true; |
| } |
| |
| m_message = CB_FPOINTER; |
| m_pCallee = pCallee; |
| m_pParam = pParam; |
| m_innerCondition.set(); |
| |
| outerDispatch(1); |
| |
| if (resetId) |
| m_outerThreadId = 0; |
| } |
| |
| void AffineBridge::v_callOut_v(uno_EnvCallee * pCallee, va_list * pParam) |
| { |
| OSL_ASSERT(m_innerThreadId); |
| |
| osl::MutexGuard guard(m_innerMutex); |
| |
| if (m_outerThreadId == 0) // no outer thread yet |
| { |
| osl::MutexGuard guard_m_outerMutex(m_outerMutex); |
| |
| if (m_outerThreadId == 0) |
| { |
| if (m_pOuterThread) |
| { |
| m_pOuterThread->join(); |
| delete m_pOuterThread; |
| } |
| |
| m_pOuterThread = new OuterThread(this); |
| } |
| } |
| |
| m_message = CB_FPOINTER; |
| m_pCallee = pCallee; |
| m_pParam = pParam; |
| m_outerCondition.set(); |
| |
| innerDispatch(); |
| } |
| |
| void AffineBridge::v_enter(void) |
| { |
| m_innerMutex.acquire(); |
| |
| if (!m_enterCount) |
| m_innerThreadId = osl_getThreadIdentifier(NULL); |
| |
| OSL_ASSERT(m_innerThreadId == osl_getThreadIdentifier(NULL)); |
| |
| ++ m_enterCount; |
| } |
| |
| void AffineBridge::v_leave(void) |
| { |
| OSL_ASSERT(m_innerThreadId == osl_getThreadIdentifier(NULL)); |
| |
| -- m_enterCount; |
| if (!m_enterCount) |
| m_innerThreadId = 0; |
| |
| m_innerMutex.release(); |
| } |
| |
| int AffineBridge::v_isValid(rtl::OUString * pReason) |
| { |
| int result = 1; |
| |
| result = m_enterCount > 0; |
| if (!result) |
| *pReason = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("not entered")); |
| |
| else |
| { |
| result = m_innerThreadId == osl_getThreadIdentifier(NULL); |
| |
| if (!result) |
| *pReason = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("wrong thread")); |
| } |
| |
| if (result) |
| *pReason = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("OK")); |
| |
| return result; |
| } |
| |
| extern "C" void SAL_DLLPUBLIC_EXPORT SAL_CALL uno_initEnvironment(uno_Environment * pEnv) |
| SAL_THROW_EXTERN_C() |
| { |
| cppu::helper::purpenv::Environment_initWithEnterable(pEnv, new AffineBridge()); |
| } |
| |
| extern "C" void SAL_DLLPUBLIC_EXPORT SAL_CALL uno_ext_getMapping(uno_Mapping ** ppMapping, |
| uno_Environment * pFrom, |
| uno_Environment * pTo ) |
| { |
| cppu::helper::purpenv::createMapping(ppMapping, pFrom, pTo); |
| } |
| |