Branch data 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: */
|