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 0 : InnerThread(AffineBridge * threadEnvironment)
92 0 : : m_pAffineBridge(threadEnvironment)
93 : {
94 0 : create();
95 0 : }
96 : };
97 :
98 0 : void InnerThread::run(void)
99 : {
100 0 : m_pAffineBridge->enter();
101 0 : m_pAffineBridge->innerDispatch();
102 0 : m_pAffineBridge->leave();
103 0 : }
104 :
105 0 : class OuterThread : public osl::Thread
106 : {
107 : virtual void SAL_CALL run(void) SAL_OVERRIDE;
108 :
109 : AffineBridge * m_pAffineBridge;
110 :
111 : public:
112 : OuterThread(AffineBridge * threadEnvironment);
113 : };
114 :
115 0 : OuterThread::OuterThread(AffineBridge * threadEnvironment)
116 0 : : m_pAffineBridge(threadEnvironment)
117 : {
118 0 : create();
119 0 : }
120 :
121 0 : void OuterThread::run(void)
122 : {
123 0 : osl::MutexGuard guard(m_pAffineBridge->m_outerMutex);
124 :
125 0 : m_pAffineBridge->m_outerThreadId = getIdentifier();
126 0 : m_pAffineBridge->outerDispatch(0);
127 0 : m_pAffineBridge->m_outerThreadId = 0;
128 :
129 0 : m_pAffineBridge->m_pOuterThread = NULL;
130 0 : m_pAffineBridge = NULL;
131 0 : }
132 :
133 :
134 0 : AffineBridge::AffineBridge(void)
135 : : m_message (CB_DONE),
136 : m_pCallee (0),
137 : m_pParam (0),
138 : m_innerThreadId(0),
139 : m_pInnerThread (NULL),
140 : m_enterCount (0),
141 : m_outerThreadId(0),
142 0 : m_pOuterThread (NULL)
143 : {
144 : LOG_LIFECYCLE_AffineBridge_emit(fprintf(stderr, "LIFE: %s -> %p\n", "AffineBridge::AffineBridge(uno_Environment * pEnv)", this));
145 0 : }
146 :
147 0 : AffineBridge::~AffineBridge(void)
148 : {
149 : LOG_LIFECYCLE_AffineBridge_emit(fprintf(stderr, "LIFE: %s -> %p\n", "AffineBridge::~AffineBridge(void)", this));
150 :
151 0 : if (m_pInnerThread && osl::Thread::getCurrentIdentifier() != m_innerThreadId)
152 : {
153 0 : m_message = CB_DONE;
154 0 : m_innerCondition.set();
155 :
156 0 : m_pInnerThread->join();
157 : }
158 :
159 0 : delete m_pInnerThread;
160 :
161 0 : if (m_pOuterThread)
162 : {
163 0 : m_pOuterThread->join();
164 0 : delete m_pOuterThread;
165 : }
166 0 : }
167 :
168 :
169 0 : void AffineBridge::outerDispatch(int loop)
170 : {
171 : OSL_ASSERT(m_outerThreadId == osl::Thread::getCurrentIdentifier());
172 : OSL_ASSERT(m_innerThreadId != m_outerThreadId);
173 :
174 : Msg mm;
175 :
176 0 : do
177 : {
178 : // FIXME: created outer thread must not wait
179 : // in case of no message
180 : // note: no message can happen in case newly created
181 : // outer thread acquire outerMutex after a real outer
182 : // thread enters outerDispatch!
183 0 : m_outerCondition.wait();
184 0 : m_outerCondition.reset();
185 :
186 0 : mm = m_message;
187 :
188 0 : switch(mm)
189 : {
190 : case CB_DONE:
191 0 : break;
192 :
193 : case CB_FPOINTER:
194 : {
195 0 : m_pCallee(m_pParam);
196 :
197 0 : m_message = CB_DONE;
198 0 : m_innerCondition.set();
199 0 : break;
200 : }
201 : default:
202 0 : abort();
203 : }
204 : }
205 0 : while(mm != CB_DONE && loop);
206 0 : }
207 :
208 0 : void AffineBridge::innerDispatch(void)
209 : {
210 : OSL_ASSERT(m_innerThreadId == osl::Thread::getCurrentIdentifier());
211 : OSL_ASSERT(m_innerThreadId != m_outerThreadId);
212 :
213 : Msg mm;
214 :
215 0 : do
216 : {
217 0 : m_innerCondition.wait();
218 0 : m_innerCondition.reset();
219 :
220 0 : mm = m_message;
221 :
222 0 : switch(mm)
223 : {
224 : case CB_DONE:
225 0 : break;
226 :
227 : case CB_FPOINTER:
228 : {
229 0 : m_pCallee(m_pParam);
230 :
231 0 : m_message = CB_DONE;
232 0 : m_outerCondition.set();
233 0 : break;
234 : }
235 : default:
236 0 : abort();
237 : }
238 : }
239 : while(mm != CB_DONE);
240 0 : }
241 :
242 0 : void AffineBridge::v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam)
243 : {
244 0 : osl::MutexGuard guard(m_outerMutex); // only one thread at a time can call into
245 :
246 0 : if (m_innerThreadId == 0) // no inner thread yet
247 : {
248 0 : m_pInnerThread = new InnerThread(this);
249 0 : m_pInnerThread->resume();
250 : }
251 :
252 0 : bool resetId = false;
253 0 : if (!m_outerThreadId)
254 : {
255 0 : m_outerThreadId = osl::Thread::getCurrentIdentifier();
256 0 : resetId = true;
257 : }
258 :
259 0 : m_message = CB_FPOINTER;
260 0 : m_pCallee = pCallee;
261 0 : m_pParam = pParam;
262 0 : m_innerCondition.set();
263 :
264 0 : outerDispatch(1);
265 :
266 0 : if (resetId)
267 0 : m_outerThreadId = 0;
268 0 : }
269 :
270 0 : void AffineBridge::v_callOut_v(uno_EnvCallee * pCallee, va_list * pParam)
271 : {
272 : OSL_ASSERT(m_innerThreadId);
273 :
274 0 : osl::MutexGuard guard(m_innerMutex);
275 :
276 0 : if (m_outerThreadId == 0) // no outer thread yet
277 : {
278 0 : osl::MutexGuard guard_m_outerMutex(m_outerMutex);
279 :
280 0 : if (m_outerThreadId == 0)
281 : {
282 0 : if (m_pOuterThread)
283 : {
284 0 : m_pOuterThread->join();
285 0 : delete m_pOuterThread;
286 : }
287 :
288 0 : m_pOuterThread = new OuterThread(this);
289 0 : }
290 : }
291 :
292 0 : m_message = CB_FPOINTER;
293 0 : m_pCallee = pCallee;
294 0 : m_pParam = pParam;
295 0 : m_outerCondition.set();
296 :
297 0 : innerDispatch();
298 0 : }
299 :
300 0 : void AffineBridge::v_enter(void)
301 : {
302 0 : m_innerMutex.acquire();
303 :
304 0 : if (!m_enterCount)
305 0 : m_innerThreadId = osl::Thread::getCurrentIdentifier();
306 :
307 : OSL_ASSERT(m_innerThreadId == osl::Thread::getCurrentIdentifier());
308 :
309 0 : ++ m_enterCount;
310 0 : }
311 :
312 0 : void AffineBridge::v_leave(void)
313 : {
314 : OSL_ASSERT(m_innerThreadId == osl::Thread::getCurrentIdentifier());
315 :
316 0 : -- m_enterCount;
317 0 : if (!m_enterCount)
318 0 : m_innerThreadId = 0;
319 :
320 0 : m_innerMutex.release();
321 0 : }
322 :
323 0 : bool AffineBridge::v_isValid(rtl::OUString * pReason)
324 : {
325 0 : bool result = m_enterCount > 0;
326 0 : if (!result)
327 0 : *pReason = rtl::OUString("not entered");
328 :
329 : else
330 : {
331 0 : result = m_innerThreadId == osl::Thread::getCurrentIdentifier();
332 :
333 0 : if (!result)
334 0 : *pReason = rtl::OUString("wrong thread");
335 : }
336 :
337 0 : if (result)
338 0 : *pReason = rtl::OUString("OK");
339 :
340 0 : return result;
341 : }
342 :
343 : #ifdef DISABLE_DYNLOADING
344 :
345 : #define uno_initEnvironment affine_uno_uno_initEnvironment
346 : #define uno_ext_getMapping affine_uno_uno_ext_getMapping
347 :
348 : #endif
349 :
350 0 : extern "C" void SAL_DLLPUBLIC_EXPORT SAL_CALL uno_initEnvironment(uno_Environment * pEnv)
351 : SAL_THROW_EXTERN_C()
352 : {
353 0 : cppu::helper::purpenv::Environment_initWithEnterable(pEnv, new AffineBridge());
354 0 : }
355 :
356 0 : extern "C" void SAL_DLLPUBLIC_EXPORT SAL_CALL uno_ext_getMapping(uno_Mapping ** ppMapping,
357 : uno_Environment * pFrom,
358 : uno_Environment * pTo )
359 : {
360 0 : cppu::helper::purpenv::createMapping(ppMapping, pFrom, pTo);
361 0 : }
362 :
363 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|