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