xref: /trunk/main/cppu/source/AffineBridge/AffineBridge.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_cppu.hxx"
30 
31 #include "osl/thread.hxx"
32 #include "osl/conditn.hxx"
33 #include "osl/mutex.hxx"
34 
35 #include "cppu/helper/purpenv/Environment.hxx"
36 #include "cppu/helper/purpenv/Mapping.hxx"
37 
38 
39 #ifdef debug
40 # define LOG_LIFECYCLE_AffineBridge
41 #endif
42 
43 #ifdef LOG_LIFECYCLE_AffineBridge
44 #  include <iostream>
45 #  define LOG_LIFECYCLE_AffineBridge_emit(x) x
46 
47 #else
48 #  define LOG_LIFECYCLE_AffineBridge_emit(x)
49 
50 #endif
51 
52 class InnerThread;
53 class OuterThread;
54 
55 class SAL_DLLPRIVATE AffineBridge : public cppu::Enterable
56 {
57 public:
58     enum Msg
59     {
60         CB_DONE,
61         CB_FPOINTER
62     };
63 
64     Msg                   m_message;
65     uno_EnvCallee       * m_pCallee;
66     va_list             * m_pParam;
67 
68     osl::Mutex            m_innerMutex;
69     oslThreadIdentifier   m_innerThreadId;
70     InnerThread         * m_pInnerThread;
71     osl::Condition        m_innerCondition;
72     sal_Int32             m_enterCount;
73 
74     osl::Mutex            m_outerMutex;
75     oslThreadIdentifier   m_outerThreadId;
76     osl::Condition        m_outerCondition;
77     OuterThread         * m_pOuterThread;
78 
79     explicit  AffineBridge(void);
80     virtual  ~AffineBridge(void);
81 
82     virtual void  v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam);
83     virtual void  v_callOut_v (uno_EnvCallee * pCallee, va_list * pParam);
84 
85     virtual void  v_enter(void);
86     virtual void  v_leave(void);
87 
88     virtual int  v_isValid(rtl::OUString * pReason);
89 
90     void innerDispatch(void);
91     void outerDispatch(int loop);
92 };
93 
94 class SAL_DLLPRIVATE InnerThread : public osl::Thread
95 {
96     virtual void SAL_CALL run(void);
97 
98     AffineBridge * m_pAffineBridge;
99 
100 public:
101     InnerThread(AffineBridge * threadEnvironment)
102         : m_pAffineBridge(threadEnvironment)
103         {
104             create();
105         }
106 };
107 
108 void InnerThread::run(void)
109 {
110     m_pAffineBridge->enter();
111     m_pAffineBridge->innerDispatch();
112     m_pAffineBridge->leave();
113 }
114 
115 class SAL_DLLPRIVATE OuterThread : public osl::Thread
116 {
117     virtual void SAL_CALL run(void);
118 
119     AffineBridge * m_pAffineBridge;
120 
121 public:
122     OuterThread(AffineBridge * threadEnvironment);
123 };
124 
125 OuterThread::OuterThread(AffineBridge * threadEnvironment)
126     : m_pAffineBridge(threadEnvironment)
127 {
128     create();
129 }
130 
131 void OuterThread::run(void)
132 {
133     osl::MutexGuard guard(m_pAffineBridge->m_outerMutex);
134 
135     m_pAffineBridge->m_outerThreadId = getIdentifier();
136     m_pAffineBridge->outerDispatch(0);
137     m_pAffineBridge->m_outerThreadId = 0;
138 
139     m_pAffineBridge->m_pOuterThread = NULL;
140     m_pAffineBridge = NULL;
141 }
142 
143 
144 AffineBridge::AffineBridge(void)
145     : m_innerThreadId(0),
146       m_pInnerThread (NULL),
147       m_enterCount   (0),
148       m_outerThreadId(0),
149       m_pOuterThread (NULL)
150 {
151     LOG_LIFECYCLE_AffineBridge_emit(fprintf(stderr, "LIFE: %s -> %p\n", "AffineBridge::AffineBridge(uno_Environment * pEnv)", this));
152 }
153 
154 AffineBridge::~AffineBridge(void)
155 {
156     LOG_LIFECYCLE_AffineBridge_emit(fprintf(stderr, "LIFE: %s -> %p\n", "AffineBridge::~AffineBridge(void)", this));
157 
158     if (m_pInnerThread && osl_getThreadIdentifier(NULL) != m_innerThreadId)
159     {
160         m_message = CB_DONE;
161         m_innerCondition.set();
162 
163         m_pInnerThread->join();
164     }
165 
166     delete m_pInnerThread;
167 
168     if (m_pOuterThread)
169     {
170         m_pOuterThread->join();
171         delete m_pOuterThread;
172     }
173 }
174 
175 
176 void AffineBridge::outerDispatch(int loop)
177 {
178     OSL_ASSERT(m_outerThreadId == osl_getThreadIdentifier(NULL));
179     OSL_ASSERT(m_innerThreadId != m_outerThreadId);
180 
181     Msg mm;
182 
183     do
184     {
185         // FIXME: created outer thread must not wait
186         // in case of no message
187         // note: no message can happen in case newly created
188         // outer thread acquire outerMutex after a real outer
189         // thread enters outerDispatch!
190         m_outerCondition.wait();
191         m_outerCondition.reset();
192 
193         mm = m_message;
194 
195         switch(mm)
196         {
197         case CB_DONE:
198             break;
199 
200         case CB_FPOINTER:
201         {
202             m_pCallee(m_pParam);
203 
204             m_message = CB_DONE;
205             m_innerCondition.set();
206             break;
207         }
208         default:
209             abort();
210         }
211     }
212     while(mm != CB_DONE && loop);
213 }
214 
215 void AffineBridge::innerDispatch(void)
216 {
217     OSL_ASSERT(m_innerThreadId == osl_getThreadIdentifier(NULL));
218     OSL_ASSERT(m_innerThreadId != m_outerThreadId);
219 
220     Msg mm;
221 
222     do
223     {
224         m_innerCondition.wait();
225         m_innerCondition.reset();
226 
227         mm = m_message;
228 
229         switch(mm)
230         {
231         case CB_DONE:
232             break;
233 
234         case CB_FPOINTER:
235         {
236             m_pCallee(m_pParam);
237 
238             m_message = CB_DONE;
239             m_outerCondition.set();
240             break;
241         }
242         default:
243             abort();
244         }
245     }
246     while(mm != CB_DONE);
247 }
248 
249 void AffineBridge::v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam)
250 {
251     osl::MutexGuard guard(m_outerMutex); // only one thread at a time can call into
252 
253     if (m_innerThreadId == 0) // no inner thread yet
254     {
255         m_pInnerThread  = new InnerThread(this);
256         m_pInnerThread->resume();
257     }
258 
259     bool resetId = false;
260     if (!m_outerThreadId)
261     {
262         m_outerThreadId = osl_getThreadIdentifier(NULL);
263         resetId = true;
264     }
265 
266     m_message = CB_FPOINTER;
267     m_pCallee = pCallee;
268     m_pParam  = pParam;
269     m_innerCondition.set();
270 
271     outerDispatch(1);
272 
273     if (resetId)
274         m_outerThreadId = 0;
275 }
276 
277 void AffineBridge::v_callOut_v(uno_EnvCallee * pCallee, va_list * pParam)
278 {
279     OSL_ASSERT(m_innerThreadId);
280 
281     osl::MutexGuard guard(m_innerMutex);
282 
283     if (m_outerThreadId == 0) // no outer thread yet
284     {
285         osl::MutexGuard guard_m_outerMutex(m_outerMutex);
286 
287         if (m_outerThreadId == 0)
288         {
289             if (m_pOuterThread)
290             {
291                 m_pOuterThread->join();
292                 delete m_pOuterThread;
293             }
294 
295             m_pOuterThread = new OuterThread(this);
296         }
297     }
298 
299     m_message = CB_FPOINTER;
300     m_pCallee = pCallee;
301     m_pParam  = pParam;
302     m_outerCondition.set();
303 
304     innerDispatch();
305 }
306 
307 void AffineBridge::v_enter(void)
308 {
309     m_innerMutex.acquire();
310 
311     if (!m_enterCount)
312         m_innerThreadId = osl_getThreadIdentifier(NULL);
313 
314     OSL_ASSERT(m_innerThreadId == osl_getThreadIdentifier(NULL));
315 
316     ++ m_enterCount;
317 }
318 
319 void AffineBridge::v_leave(void)
320 {
321     OSL_ASSERT(m_innerThreadId == osl_getThreadIdentifier(NULL));
322 
323     -- m_enterCount;
324     if (!m_enterCount)
325         m_innerThreadId = 0;
326 
327     m_innerMutex.release();
328 }
329 
330 int  AffineBridge::v_isValid(rtl::OUString * pReason)
331 {
332     int result = 1;
333 
334     result = m_enterCount > 0;
335     if (!result)
336         *pReason = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("not entered"));
337 
338     else
339     {
340         result = m_innerThreadId == osl_getThreadIdentifier(NULL);
341 
342         if (!result)
343             *pReason = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("wrong thread"));
344     }
345 
346     if (result)
347         *pReason = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("OK"));
348 
349     return result;
350 }
351 
352 extern "C" void SAL_DLLPUBLIC_EXPORT SAL_CALL uno_initEnvironment(uno_Environment * pEnv)
353     SAL_THROW_EXTERN_C()
354 {
355     cppu::helper::purpenv::Environment_initWithEnterable(pEnv, new AffineBridge());
356 }
357 
358 extern "C" void SAL_DLLPUBLIC_EXPORT SAL_CALL uno_ext_getMapping(uno_Mapping     ** ppMapping,
359                                                         uno_Environment  * pFrom,
360                                                         uno_Environment  * pTo )
361 {
362     cppu::helper::purpenv::createMapping(ppMapping, pFrom, pTo);
363 }
364 
365