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