1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_cppu.hxx" 26 27 #include "osl/thread.hxx" 28 #include "osl/conditn.hxx" 29 #include "osl/mutex.hxx" 30 31 #include "cppu/helper/purpenv/Environment.hxx" 32 #include "cppu/helper/purpenv/Mapping.hxx" 33 34 35 #ifdef debug 36 # define LOG_LIFECYCLE_AffineBridge 37 #endif 38 39 #ifdef LOG_LIFECYCLE_AffineBridge 40 # include <iostream> 41 # define LOG_LIFECYCLE_AffineBridge_emit(x) x 42 43 #else 44 # define LOG_LIFECYCLE_AffineBridge_emit(x) 45 46 #endif 47 48 class InnerThread; 49 class OuterThread; 50 51 class SAL_DLLPRIVATE AffineBridge : public cppu::Enterable 52 { 53 public: 54 enum Msg 55 { 56 CB_DONE, 57 CB_FPOINTER 58 }; 59 60 Msg m_message; 61 uno_EnvCallee * m_pCallee; 62 va_list * m_pParam; 63 64 osl::Mutex m_innerMutex; 65 oslThreadIdentifier m_innerThreadId; 66 InnerThread * m_pInnerThread; 67 osl::Condition m_innerCondition; 68 sal_Int32 m_enterCount; 69 70 osl::Mutex m_outerMutex; 71 oslThreadIdentifier m_outerThreadId; 72 osl::Condition m_outerCondition; 73 OuterThread * m_pOuterThread; 74 75 explicit AffineBridge(void); 76 virtual ~AffineBridge(void); 77 78 virtual void v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam); 79 virtual void v_callOut_v (uno_EnvCallee * pCallee, va_list * pParam); 80 81 virtual void v_enter(void); 82 virtual void v_leave(void); 83 84 virtual int v_isValid(rtl::OUString * pReason); 85 86 void innerDispatch(void); 87 void outerDispatch(int loop); 88 }; 89 90 class SAL_DLLPRIVATE InnerThread : public osl::Thread 91 { 92 virtual void SAL_CALL run(void); 93 94 AffineBridge * m_pAffineBridge; 95 96 public: 97 InnerThread(AffineBridge * threadEnvironment) 98 : m_pAffineBridge(threadEnvironment) 99 { 100 create(); 101 } 102 }; 103 104 void InnerThread::run(void) 105 { 106 m_pAffineBridge->enter(); 107 m_pAffineBridge->innerDispatch(); 108 m_pAffineBridge->leave(); 109 } 110 111 class SAL_DLLPRIVATE OuterThread : public osl::Thread 112 { 113 virtual void SAL_CALL run(void); 114 115 AffineBridge * m_pAffineBridge; 116 117 public: 118 OuterThread(AffineBridge * threadEnvironment); 119 }; 120 121 OuterThread::OuterThread(AffineBridge * threadEnvironment) 122 : m_pAffineBridge(threadEnvironment) 123 { 124 create(); 125 } 126 127 void OuterThread::run(void) 128 { 129 osl::MutexGuard guard(m_pAffineBridge->m_outerMutex); 130 131 m_pAffineBridge->m_outerThreadId = getIdentifier(); 132 m_pAffineBridge->outerDispatch(0); 133 m_pAffineBridge->m_outerThreadId = 0; 134 135 m_pAffineBridge->m_pOuterThread = NULL; 136 m_pAffineBridge = NULL; 137 } 138 139 140 AffineBridge::AffineBridge(void) 141 : m_innerThreadId(0), 142 m_pInnerThread (NULL), 143 m_enterCount (0), 144 m_outerThreadId(0), 145 m_pOuterThread (NULL) 146 { 147 LOG_LIFECYCLE_AffineBridge_emit(fprintf(stderr, "LIFE: %s -> %p\n", "AffineBridge::AffineBridge(uno_Environment * pEnv)", this)); 148 } 149 150 AffineBridge::~AffineBridge(void) 151 { 152 LOG_LIFECYCLE_AffineBridge_emit(fprintf(stderr, "LIFE: %s -> %p\n", "AffineBridge::~AffineBridge(void)", this)); 153 154 if (m_pInnerThread && osl_getThreadIdentifier(NULL) != m_innerThreadId) 155 { 156 m_message = CB_DONE; 157 m_innerCondition.set(); 158 159 m_pInnerThread->join(); 160 } 161 162 delete m_pInnerThread; 163 164 if (m_pOuterThread) 165 { 166 m_pOuterThread->join(); 167 delete m_pOuterThread; 168 } 169 } 170 171 172 void AffineBridge::outerDispatch(int loop) 173 { 174 OSL_ASSERT(m_outerThreadId == osl_getThreadIdentifier(NULL)); 175 OSL_ASSERT(m_innerThreadId != m_outerThreadId); 176 177 Msg mm; 178 179 do 180 { 181 // FIXME: created outer thread must not wait 182 // in case of no message 183 // note: no message can happen in case newly created 184 // outer thread acquire outerMutex after a real outer 185 // thread enters outerDispatch! 186 m_outerCondition.wait(); 187 m_outerCondition.reset(); 188 189 mm = m_message; 190 191 switch(mm) 192 { 193 case CB_DONE: 194 break; 195 196 case CB_FPOINTER: 197 { 198 m_pCallee(m_pParam); 199 200 m_message = CB_DONE; 201 m_innerCondition.set(); 202 break; 203 } 204 default: 205 abort(); 206 } 207 } 208 while(mm != CB_DONE && loop); 209 } 210 211 void AffineBridge::innerDispatch(void) 212 { 213 OSL_ASSERT(m_innerThreadId == osl_getThreadIdentifier(NULL)); 214 OSL_ASSERT(m_innerThreadId != m_outerThreadId); 215 216 Msg mm; 217 218 do 219 { 220 m_innerCondition.wait(); 221 m_innerCondition.reset(); 222 223 mm = m_message; 224 225 switch(mm) 226 { 227 case CB_DONE: 228 break; 229 230 case CB_FPOINTER: 231 { 232 m_pCallee(m_pParam); 233 234 m_message = CB_DONE; 235 m_outerCondition.set(); 236 break; 237 } 238 default: 239 abort(); 240 } 241 } 242 while(mm != CB_DONE); 243 } 244 245 void AffineBridge::v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam) 246 { 247 osl::MutexGuard guard(m_outerMutex); // only one thread at a time can call into 248 249 if (m_innerThreadId == 0) // no inner thread yet 250 { 251 m_pInnerThread = new InnerThread(this); 252 m_pInnerThread->resume(); 253 } 254 255 bool resetId = false; 256 if (!m_outerThreadId) 257 { 258 m_outerThreadId = osl_getThreadIdentifier(NULL); 259 resetId = true; 260 } 261 262 m_message = CB_FPOINTER; 263 m_pCallee = pCallee; 264 m_pParam = pParam; 265 m_innerCondition.set(); 266 267 outerDispatch(1); 268 269 if (resetId) 270 m_outerThreadId = 0; 271 } 272 273 void AffineBridge::v_callOut_v(uno_EnvCallee * pCallee, va_list * pParam) 274 { 275 OSL_ASSERT(m_innerThreadId); 276 277 osl::MutexGuard guard(m_innerMutex); 278 279 if (m_outerThreadId == 0) // no outer thread yet 280 { 281 osl::MutexGuard guard_m_outerMutex(m_outerMutex); 282 283 if (m_outerThreadId == 0) 284 { 285 if (m_pOuterThread) 286 { 287 m_pOuterThread->join(); 288 delete m_pOuterThread; 289 } 290 291 m_pOuterThread = new OuterThread(this); 292 } 293 } 294 295 m_message = CB_FPOINTER; 296 m_pCallee = pCallee; 297 m_pParam = pParam; 298 m_outerCondition.set(); 299 300 innerDispatch(); 301 } 302 303 void AffineBridge::v_enter(void) 304 { 305 m_innerMutex.acquire(); 306 307 if (!m_enterCount) 308 m_innerThreadId = osl_getThreadIdentifier(NULL); 309 310 OSL_ASSERT(m_innerThreadId == osl_getThreadIdentifier(NULL)); 311 312 ++ m_enterCount; 313 } 314 315 void AffineBridge::v_leave(void) 316 { 317 OSL_ASSERT(m_innerThreadId == osl_getThreadIdentifier(NULL)); 318 319 -- m_enterCount; 320 if (!m_enterCount) 321 m_innerThreadId = 0; 322 323 m_innerMutex.release(); 324 } 325 326 int AffineBridge::v_isValid(rtl::OUString * pReason) 327 { 328 int result = 1; 329 330 result = m_enterCount > 0; 331 if (!result) 332 *pReason = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("not entered")); 333 334 else 335 { 336 result = m_innerThreadId == osl_getThreadIdentifier(NULL); 337 338 if (!result) 339 *pReason = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("wrong thread")); 340 } 341 342 if (result) 343 *pReason = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("OK")); 344 345 return result; 346 } 347 348 extern "C" void SAL_DLLPUBLIC_EXPORT SAL_CALL uno_initEnvironment(uno_Environment * pEnv) 349 SAL_THROW_EXTERN_C() 350 { 351 cppu::helper::purpenv::Environment_initWithEnterable(pEnv, new AffineBridge()); 352 } 353 354 extern "C" void SAL_DLLPUBLIC_EXPORT SAL_CALL uno_ext_getMapping(uno_Mapping ** ppMapping, 355 uno_Environment * pFrom, 356 uno_Environment * pTo ) 357 { 358 cppu::helper::purpenv::createMapping(ppMapping, pFrom, pTo); 359 } 360 361