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:
InnerThread(AffineBridge * threadEnvironment)97 InnerThread(AffineBridge * threadEnvironment)
98 : m_pAffineBridge(threadEnvironment)
99 {
100 create();
101 }
102 };
103
run(void)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
OuterThread(AffineBridge * threadEnvironment)121 OuterThread::OuterThread(AffineBridge * threadEnvironment)
122 : m_pAffineBridge(threadEnvironment)
123 {
124 create();
125 }
126
run(void)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
AffineBridge(void)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
~AffineBridge(void)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
outerDispatch(int loop)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
innerDispatch(void)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
v_callInto_v(uno_EnvCallee * pCallee,va_list * pParam)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
v_callOut_v(uno_EnvCallee * pCallee,va_list * pParam)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
v_enter(void)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
v_leave(void)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
v_isValid(rtl::OUString * pReason)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
uno_initEnvironment(uno_Environment * pEnv)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
uno_ext_getMapping(uno_Mapping ** ppMapping,uno_Environment * pFrom,uno_Environment * pTo)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