Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 :
21 : #include "osl/thread.hxx"
22 : #include "osl/conditn.hxx"
23 : #include "osl/mutex.hxx"
24 :
25 : #include "cppu/helper/purpenv/Environment.hxx"
26 : #include "cppu/helper/purpenv/Mapping.hxx"
27 :
28 :
29 : #ifdef debug
30 : # define LOG_LIFECYCLE_AffineBridge
31 : #endif
32 :
33 : #ifdef LOG_LIFECYCLE_AffineBridge
34 : # include <iostream>
35 : # define LOG_LIFECYCLE_AffineBridge_emit(x) x
36 :
37 : #else
38 : # define LOG_LIFECYCLE_AffineBridge_emit(x)
39 :
40 : #endif
41 :
42 : class InnerThread;
43 : class OuterThread;
44 :
45 : class AffineBridge : public cppu::Enterable
46 : {
47 : public:
48 : enum Msg
49 : {
50 : CB_DONE,
51 : CB_FPOINTER
52 : };
53 :
54 : Msg m_message;
55 : uno_EnvCallee * m_pCallee;
56 : va_list * m_pParam;
57 :
58 : osl::Mutex m_innerMutex;
59 : oslThreadIdentifier m_innerThreadId;
60 : InnerThread * m_pInnerThread;
61 : osl::Condition m_innerCondition;
62 : sal_Int32 m_enterCount;
63 :
64 : osl::Mutex m_outerMutex;
65 : oslThreadIdentifier m_outerThreadId;
66 : osl::Condition m_outerCondition;
67 : OuterThread * m_pOuterThread;
68 :
69 : explicit AffineBridge(void);
70 : virtual ~AffineBridge(void);
71 :
72 : virtual void v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam) SAL_OVERRIDE;
73 : virtual void v_callOut_v (uno_EnvCallee * pCallee, va_list * pParam) SAL_OVERRIDE;
74 :
75 : virtual void v_enter(void) SAL_OVERRIDE;
76 : virtual void v_leave(void) SAL_OVERRIDE;
77 :
78 : virtual bool v_isValid(rtl::OUString * pReason) SAL_OVERRIDE;
79 :
80 : void innerDispatch(void);
81 : void outerDispatch(int loop);
82 : };
83 :
84 0 : class InnerThread : public osl::Thread
85 : {
86 : virtual void SAL_CALL run(void) SAL_OVERRIDE;
87 :
88 : AffineBridge * m_pAffineBridge;
89 :
90 : public:
91 4 : InnerThread(AffineBridge * threadEnvironment)
92 4 : : m_pAffineBridge(threadEnvironment)
93 : {
94 4 : create();
95 4 : }
96 : };
97 :
98 4 : void InnerThread::run(void)
99 : {
100 4 : osl_setThreadName("UNO AffineBridge InnerThread");
101 :
102 4 : m_pAffineBridge->enter();
103 4 : m_pAffineBridge->innerDispatch();
104 0 : m_pAffineBridge->leave();
105 0 : }
106 :
107 0 : class OuterThread : public osl::Thread
108 : {
109 : virtual void SAL_CALL run(void) SAL_OVERRIDE;
110 :
111 : AffineBridge * m_pAffineBridge;
112 :
113 : public:
114 : OuterThread(AffineBridge * threadEnvironment);
115 : };
116 :
117 0 : OuterThread::OuterThread(AffineBridge * threadEnvironment)
118 0 : : m_pAffineBridge(threadEnvironment)
119 : {
120 0 : create();
121 0 : }
122 :
123 0 : void OuterThread::run(void)
124 : {
125 0 : osl_setThreadName("UNO AffineBridge OuterThread");
126 :
127 0 : osl::MutexGuard guard(m_pAffineBridge->m_outerMutex);
128 :
129 0 : m_pAffineBridge->m_outerThreadId = getIdentifier();
130 0 : m_pAffineBridge->outerDispatch(0);
131 0 : m_pAffineBridge->m_outerThreadId = 0;
132 :
133 0 : m_pAffineBridge->m_pOuterThread = NULL;
134 0 : m_pAffineBridge = NULL;
135 0 : }
136 :
137 :
138 4 : AffineBridge::AffineBridge(void)
139 : : m_message (CB_DONE),
140 : m_pCallee (0),
141 : m_pParam (0),
142 : m_innerThreadId(0),
143 : m_pInnerThread (NULL),
144 : m_enterCount (0),
145 : m_outerThreadId(0),
146 4 : m_pOuterThread (NULL)
147 : {
148 : LOG_LIFECYCLE_AffineBridge_emit(fprintf(stderr, "LIFE: %s -> %p\n", "AffineBridge::AffineBridge(uno_Environment * pEnv)", this));
149 4 : }
150 :
151 0 : AffineBridge::~AffineBridge(void)
152 : {
153 : LOG_LIFECYCLE_AffineBridge_emit(fprintf(stderr, "LIFE: %s -> %p\n", "AffineBridge::~AffineBridge(void)", this));
154 :
155 0 : if (m_pInnerThread && osl::Thread::getCurrentIdentifier() != m_innerThreadId)
156 : {
157 0 : m_message = CB_DONE;
158 0 : m_innerCondition.set();
159 :
160 0 : m_pInnerThread->join();
161 : }
162 :
163 0 : delete m_pInnerThread;
164 :
165 0 : if (m_pOuterThread)
166 : {
167 0 : m_pOuterThread->join();
168 0 : delete m_pOuterThread;
169 : }
170 0 : }
171 :
172 :
173 15814 : void AffineBridge::outerDispatch(int loop)
174 : {
175 : OSL_ASSERT(m_outerThreadId == osl::Thread::getCurrentIdentifier());
176 : OSL_ASSERT(m_innerThreadId != m_outerThreadId);
177 :
178 : Msg mm;
179 :
180 15814 : do
181 : {
182 : // FIXME: created outer thread must not wait
183 : // in case of no message
184 : // note: no message can happen in case newly created
185 : // outer thread acquire outerMutex after a real outer
186 : // thread enters outerDispatch!
187 15814 : m_outerCondition.wait();
188 15814 : m_outerCondition.reset();
189 :
190 15814 : mm = m_message;
191 :
192 15814 : switch(mm)
193 : {
194 : case CB_DONE:
195 15254 : break;
196 :
197 : case CB_FPOINTER:
198 : {
199 560 : m_pCallee(m_pParam);
200 :
201 560 : m_message = CB_DONE;
202 560 : m_innerCondition.set();
203 560 : break;
204 : }
205 : default:
206 0 : abort();
207 : }
208 : }
209 560 : while(mm != CB_DONE && loop);
210 15254 : }
211 :
212 15818 : void AffineBridge::innerDispatch(void)
213 : {
214 : OSL_ASSERT(m_innerThreadId == osl::Thread::getCurrentIdentifier());
215 : OSL_ASSERT(m_innerThreadId != m_outerThreadId);
216 :
217 : Msg mm;
218 :
219 15814 : do
220 : {
221 15818 : m_innerCondition.wait();
222 15814 : m_innerCondition.reset();
223 :
224 15814 : mm = m_message;
225 :
226 15814 : switch(mm)
227 : {
228 : case CB_DONE:
229 560 : break;
230 :
231 : case CB_FPOINTER:
232 : {
233 15254 : m_pCallee(m_pParam);
234 :
235 15254 : m_message = CB_DONE;
236 15254 : m_outerCondition.set();
237 15254 : break;
238 : }
239 : default:
240 0 : abort();
241 : }
242 : }
243 : while(mm != CB_DONE);
244 560 : }
245 :
246 15254 : void AffineBridge::v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam)
247 : {
248 15254 : osl::MutexGuard guard(m_outerMutex); // only one thread at a time can call into
249 :
250 15254 : if (m_innerThreadId == 0) // no inner thread yet
251 : {
252 4 : m_pInnerThread = new InnerThread(this);
253 4 : m_pInnerThread->resume();
254 : }
255 :
256 15254 : bool resetId = false;
257 15254 : if (!m_outerThreadId)
258 : {
259 15198 : m_outerThreadId = osl::Thread::getCurrentIdentifier();
260 15198 : resetId = true;
261 : }
262 :
263 15254 : m_message = CB_FPOINTER;
264 15254 : m_pCallee = pCallee;
265 15254 : m_pParam = pParam;
266 15254 : m_innerCondition.set();
267 :
268 15254 : outerDispatch(1);
269 :
270 15254 : if (resetId)
271 15198 : m_outerThreadId = 0;
272 15254 : }
273 :
274 560 : void AffineBridge::v_callOut_v(uno_EnvCallee * pCallee, va_list * pParam)
275 : {
276 : OSL_ASSERT(m_innerThreadId);
277 :
278 560 : osl::MutexGuard guard(m_innerMutex);
279 :
280 560 : if (m_outerThreadId == 0) // no outer thread yet
281 : {
282 0 : osl::MutexGuard guard_m_outerMutex(m_outerMutex);
283 :
284 0 : if (m_outerThreadId == 0)
285 : {
286 0 : if (m_pOuterThread)
287 : {
288 0 : m_pOuterThread->join();
289 0 : delete m_pOuterThread;
290 : }
291 :
292 0 : m_pOuterThread = new OuterThread(this);
293 0 : }
294 : }
295 :
296 560 : m_message = CB_FPOINTER;
297 560 : m_pCallee = pCallee;
298 560 : m_pParam = pParam;
299 560 : m_outerCondition.set();
300 :
301 560 : innerDispatch();
302 560 : }
303 :
304 4 : void AffineBridge::v_enter(void)
305 : {
306 4 : m_innerMutex.acquire();
307 :
308 4 : if (!m_enterCount)
309 4 : m_innerThreadId = osl::Thread::getCurrentIdentifier();
310 :
311 : OSL_ASSERT(m_innerThreadId == osl::Thread::getCurrentIdentifier());
312 :
313 4 : ++ m_enterCount;
314 4 : }
315 :
316 0 : void AffineBridge::v_leave(void)
317 : {
318 : OSL_ASSERT(m_innerThreadId == osl::Thread::getCurrentIdentifier());
319 :
320 0 : -- m_enterCount;
321 0 : if (!m_enterCount)
322 0 : m_innerThreadId = 0;
323 :
324 0 : m_innerMutex.release();
325 0 : }
326 :
327 0 : bool AffineBridge::v_isValid(rtl::OUString * pReason)
328 : {
329 0 : bool result = m_enterCount > 0;
330 0 : if (!result)
331 0 : *pReason = rtl::OUString("not entered");
332 :
333 : else
334 : {
335 0 : result = m_innerThreadId == osl::Thread::getCurrentIdentifier();
336 :
337 0 : if (!result)
338 0 : *pReason = rtl::OUString("wrong thread");
339 : }
340 :
341 0 : if (result)
342 0 : *pReason = rtl::OUString("OK");
343 :
344 0 : return result;
345 : }
346 :
347 : #ifdef DISABLE_DYNLOADING
348 :
349 : #define uno_initEnvironment affine_uno_uno_initEnvironment
350 : #define uno_ext_getMapping affine_uno_uno_ext_getMapping
351 :
352 : #endif
353 :
354 4 : extern "C" void SAL_DLLPUBLIC_EXPORT SAL_CALL uno_initEnvironment(uno_Environment * pEnv)
355 : SAL_THROW_EXTERN_C()
356 : {
357 4 : cppu::helper::purpenv::Environment_initWithEnterable(pEnv, new AffineBridge());
358 4 : }
359 :
360 8 : extern "C" void SAL_DLLPUBLIC_EXPORT SAL_CALL uno_ext_getMapping(uno_Mapping ** ppMapping,
361 : uno_Environment * pFrom,
362 : uno_Environment * pTo )
363 : {
364 8 : cppu::helper::purpenv::createMapping(ppMapping, pFrom, pTo);
365 8 : }
366 :
367 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|