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