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