1*0d63794cSAndrew Rist /**************************************************************
2cdf0e10cSrcweir *
3*0d63794cSAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one
4*0d63794cSAndrew Rist * or more contributor license agreements. See the NOTICE file
5*0d63794cSAndrew Rist * distributed with this work for additional information
6*0d63794cSAndrew Rist * regarding copyright ownership. The ASF licenses this file
7*0d63794cSAndrew Rist * to you under the Apache License, Version 2.0 (the
8*0d63794cSAndrew Rist * "License"); you may not use this file except in compliance
9*0d63794cSAndrew Rist * with the License. You may obtain a copy of the License at
10*0d63794cSAndrew Rist *
11*0d63794cSAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0
12*0d63794cSAndrew Rist *
13*0d63794cSAndrew Rist * Unless required by applicable law or agreed to in writing,
14*0d63794cSAndrew Rist * software distributed under the License is distributed on an
15*0d63794cSAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*0d63794cSAndrew Rist * KIND, either express or implied. See the License for the
17*0d63794cSAndrew Rist * specific language governing permissions and limitations
18*0d63794cSAndrew Rist * under the License.
19*0d63794cSAndrew Rist *
20*0d63794cSAndrew Rist *************************************************************/
21*0d63794cSAndrew Rist
22*0d63794cSAndrew Rist
23cdf0e10cSrcweir
24cdf0e10cSrcweir #include <osl/conditn.h>
25cdf0e10cSrcweir #include <osl/thread.h>
26cdf0e10cSrcweir #include <tools/link.hxx>
27cdf0e10cSrcweir #include <vcl/dllapi.h>
28cdf0e10cSrcweir
29cdf0e10cSrcweir #if ! defined(_CPPUHELPER_EXC_HLP_HXX_)
30cdf0e10cSrcweir #include "cppuhelper/exc_hlp.hxx"
31cdf0e10cSrcweir #endif
32cdf0e10cSrcweir #include "boost/optional.hpp"
33cdf0e10cSrcweir #include <memory>
34cdf0e10cSrcweir
35cdf0e10cSrcweir namespace vcl
36cdf0e10cSrcweir {
37cdf0e10cSrcweir class VCL_DLLPUBLIC ThreadExecutor
38cdf0e10cSrcweir {
39cdf0e10cSrcweir oslThread m_aThread;
40cdf0e10cSrcweir oslCondition m_aFinish;
41cdf0e10cSrcweir long m_nReturn;
42cdf0e10cSrcweir
43cdf0e10cSrcweir #ifdef THREADEX_IMPLEMENTATION
44cdf0e10cSrcweir public:
45cdf0e10cSrcweir SAL_DLLPRIVATE static void SAL_CALL worker( void* );
46cdf0e10cSrcweir #endif
47cdf0e10cSrcweir public:
48cdf0e10cSrcweir ThreadExecutor();
49cdf0e10cSrcweir virtual ~ThreadExecutor();
50cdf0e10cSrcweir
51cdf0e10cSrcweir virtual long doIt() = 0;
52cdf0e10cSrcweir long execute();
53cdf0e10cSrcweir };
54cdf0e10cSrcweir
55cdf0e10cSrcweir class VCL_DLLPUBLIC SolarThreadExecutor
56cdf0e10cSrcweir {
57cdf0e10cSrcweir oslCondition m_aStart;
58cdf0e10cSrcweir oslCondition m_aFinish;
59cdf0e10cSrcweir long m_nReturn;
60cdf0e10cSrcweir bool m_bTimeout;
61cdf0e10cSrcweir
62cdf0e10cSrcweir DECL_DLLPRIVATE_LINK( worker, void* );
63cdf0e10cSrcweir
64cdf0e10cSrcweir public:
65cdf0e10cSrcweir SolarThreadExecutor();
66cdf0e10cSrcweir virtual ~SolarThreadExecutor();
67cdf0e10cSrcweir
68cdf0e10cSrcweir virtual long doIt() = 0;
execute()69cdf0e10cSrcweir long execute() { return impl_execute( NULL ); }
70cdf0e10cSrcweir // caution: timeout for getting the solar mutex, not for ending
71cdf0e10cSrcweir // the operation of doIt(). If doIt actually gets called within
72cdf0e10cSrcweir // the specified timeout, execute will only return after
73cdf0e10cSrcweir // doIt() completed
execute(const TimeValue & _rTimeout)74cdf0e10cSrcweir long execute( const TimeValue& _rTimeout ) { return impl_execute( &_rTimeout ); }
75cdf0e10cSrcweir
76cdf0e10cSrcweir public:
didTimeout() const77cdf0e10cSrcweir bool didTimeout() const { return m_bTimeout; }
78cdf0e10cSrcweir
79cdf0e10cSrcweir private:
80cdf0e10cSrcweir long impl_execute( const TimeValue* _pTimeout );
81cdf0e10cSrcweir };
82cdf0e10cSrcweir
83cdf0e10cSrcweir namespace solarthread {
84cdf0e10cSrcweir
85cdf0e10cSrcweir /// @internal
86cdf0e10cSrcweir namespace detail {
87cdf0e10cSrcweir
88cdf0e10cSrcweir template <typename FuncT, typename ResultT>
89cdf0e10cSrcweir class GenericSolarThreadExecutor : public SolarThreadExecutor
90cdf0e10cSrcweir {
91cdf0e10cSrcweir public:
exec(FuncT const & func)92cdf0e10cSrcweir static ResultT exec( FuncT const& func )
93cdf0e10cSrcweir {
94cdf0e10cSrcweir typedef GenericSolarThreadExecutor<FuncT, ResultT> ExecutorT;
95cdf0e10cSrcweir ::std::auto_ptr<ExecutorT> const pExecutor( new ExecutorT(func) );
96cdf0e10cSrcweir pExecutor->execute();
97cdf0e10cSrcweir #if ! defined(EXCEPTIONS_OFF)
98cdf0e10cSrcweir if (pExecutor->m_exc.hasValue())
99cdf0e10cSrcweir ::cppu::throwException( pExecutor->m_exc );
100cdf0e10cSrcweir #endif
101cdf0e10cSrcweir return *pExecutor->m_result;
102cdf0e10cSrcweir }
103cdf0e10cSrcweir
104cdf0e10cSrcweir private:
GenericSolarThreadExecutor(FuncT const & func)105cdf0e10cSrcweir explicit GenericSolarThreadExecutor( FuncT const& func )
106cdf0e10cSrcweir : m_exc(), m_func(func), m_result() {}
107cdf0e10cSrcweir
doIt()108cdf0e10cSrcweir virtual long doIt()
109cdf0e10cSrcweir {
110cdf0e10cSrcweir #if defined(EXCEPTIONS_OFF)
111cdf0e10cSrcweir m_result.reset( m_func() );
112cdf0e10cSrcweir #else
113cdf0e10cSrcweir try {
114cdf0e10cSrcweir m_result.reset( m_func() );
115cdf0e10cSrcweir }
116cdf0e10cSrcweir catch (::com::sun::star::uno::Exception &) {
117cdf0e10cSrcweir // only UNO exceptions can be dispatched:
118cdf0e10cSrcweir m_exc = ::cppu::getCaughtException();
119cdf0e10cSrcweir }
120cdf0e10cSrcweir #endif
121cdf0e10cSrcweir return 0;
122cdf0e10cSrcweir }
123cdf0e10cSrcweir
124cdf0e10cSrcweir ::com::sun::star::uno::Any m_exc;
125cdf0e10cSrcweir FuncT const m_func;
126cdf0e10cSrcweir // using boost::optional here omits the need that ResultT is default
127cdf0e10cSrcweir // constructable:
128cdf0e10cSrcweir ::boost::optional<ResultT> m_result;
129cdf0e10cSrcweir };
130cdf0e10cSrcweir
131cdf0e10cSrcweir template <typename FuncT>
132cdf0e10cSrcweir class GenericSolarThreadExecutor<FuncT, void> : public SolarThreadExecutor
133cdf0e10cSrcweir {
134cdf0e10cSrcweir public:
exec(FuncT const & func)135cdf0e10cSrcweir static void exec( FuncT const& func )
136cdf0e10cSrcweir {
137cdf0e10cSrcweir typedef GenericSolarThreadExecutor<FuncT, void> ExecutorT;
138cdf0e10cSrcweir ::std::auto_ptr<ExecutorT> const pExecutor( new ExecutorT(func) );
139cdf0e10cSrcweir pExecutor->execute();
140cdf0e10cSrcweir #if ! defined(EXCEPTIONS_OFF)
141cdf0e10cSrcweir if (pExecutor->m_exc.hasValue())
142cdf0e10cSrcweir ::cppu::throwException( pExecutor->m_exc );
143cdf0e10cSrcweir #endif
144cdf0e10cSrcweir }
145cdf0e10cSrcweir
146cdf0e10cSrcweir private:
GenericSolarThreadExecutor(FuncT const & func)147cdf0e10cSrcweir explicit GenericSolarThreadExecutor( FuncT const& func )
148cdf0e10cSrcweir : m_exc(), m_func(func) {}
149cdf0e10cSrcweir
doIt()150cdf0e10cSrcweir virtual long doIt()
151cdf0e10cSrcweir {
152cdf0e10cSrcweir #if defined(EXCEPTIONS_OFF)
153cdf0e10cSrcweir m_func();
154cdf0e10cSrcweir #else
155cdf0e10cSrcweir try {
156cdf0e10cSrcweir m_func();
157cdf0e10cSrcweir }
158cdf0e10cSrcweir catch (::com::sun::star::uno::Exception &) {
159cdf0e10cSrcweir // only UNO exceptions can be dispatched:
160cdf0e10cSrcweir m_exc = ::cppu::getCaughtException();
161cdf0e10cSrcweir }
162cdf0e10cSrcweir #endif
163cdf0e10cSrcweir return 0;
164cdf0e10cSrcweir }
165cdf0e10cSrcweir
166cdf0e10cSrcweir ::com::sun::star::uno::Any m_exc;
167cdf0e10cSrcweir FuncT const m_func;
168cdf0e10cSrcweir };
169cdf0e10cSrcweir
170cdf0e10cSrcweir template <typename T>
171cdf0e10cSrcweir class copy_back_wrapper
172cdf0e10cSrcweir {
173cdf0e10cSrcweir public:
operator T*() const174cdf0e10cSrcweir operator T *() const { return &m_holder->m_value; }
operator T&() const175cdf0e10cSrcweir operator T &() const { return m_holder->m_value; }
176cdf0e10cSrcweir
copy_back_wrapper(T * p)177cdf0e10cSrcweir explicit copy_back_wrapper( T * p ) : m_holder( new data_holder(p) ) {}
178cdf0e10cSrcweir
179cdf0e10cSrcweir // no thread-safe counting needed here, because calling thread blocks
180cdf0e10cSrcweir // until solar thread has executed the functor.
copy_back_wrapper(copy_back_wrapper<T> const & r)181cdf0e10cSrcweir copy_back_wrapper( copy_back_wrapper<T> const& r )
182cdf0e10cSrcweir : m_holder(r.m_holder) { ++m_holder->m_refCount; }
~copy_back_wrapper()183cdf0e10cSrcweir ~copy_back_wrapper() {
184cdf0e10cSrcweir --m_holder->m_refCount;
185cdf0e10cSrcweir if (m_holder->m_refCount == 0) {
186cdf0e10cSrcweir delete m_holder;
187cdf0e10cSrcweir }
188cdf0e10cSrcweir }
189cdf0e10cSrcweir private:
190cdf0e10cSrcweir struct data_holder {
191cdf0e10cSrcweir T m_value;
192cdf0e10cSrcweir T * const m_ptr;
193cdf0e10cSrcweir sal_Int32 m_refCount;
data_holdervcl::solarthread::detail::copy_back_wrapper::data_holder194cdf0e10cSrcweir data_holder( T * p ) : m_value(*p), m_ptr(p), m_refCount(1) {}
~data_holdervcl::solarthread::detail::copy_back_wrapper::data_holder195cdf0e10cSrcweir ~data_holder() { *m_ptr = m_value; }
196cdf0e10cSrcweir };
197cdf0e10cSrcweir data_holder * const m_holder;
198cdf0e10cSrcweir };
199cdf0e10cSrcweir
200cdf0e10cSrcweir } // namespace detail
201cdf0e10cSrcweir
202cdf0e10cSrcweir /** Makes a copy back reference wrapper to be used for inout parameters.
203cdf0e10cSrcweir Only use for syncExecute(), the returned wrapper relies on its
204cdf0e10cSrcweir implemenation, i.e. the function object is stored in free store.
205cdf0e10cSrcweir Type T needs to be copy constructable assignable.
206cdf0e10cSrcweir
207cdf0e10cSrcweir @see syncExecute()
208cdf0e10cSrcweir @param r reference to a stack variable
209cdf0e10cSrcweir @return reference wrapper
210cdf0e10cSrcweir */
211cdf0e10cSrcweir template <typename T>
inout_by_ref(T & r)212cdf0e10cSrcweir inline detail::copy_back_wrapper<T> inout_by_ref( T & r )
213cdf0e10cSrcweir {
214cdf0e10cSrcweir return detail::copy_back_wrapper<T>(&r);
215cdf0e10cSrcweir }
216cdf0e10cSrcweir
217cdf0e10cSrcweir /** Makes a copy back ptr wrapper to be used for inout parameters.
218cdf0e10cSrcweir Only use for syncExecute(), the returned wrapper relies on its
219cdf0e10cSrcweir implemenation, i.e. the function object is stored in free store.
220cdf0e10cSrcweir Type T needs to be copy constructable assignable.
221cdf0e10cSrcweir
222cdf0e10cSrcweir @see syncExecute()
223cdf0e10cSrcweir @param p pointer to a stack variable
224cdf0e10cSrcweir @return ptr wrapper
225cdf0e10cSrcweir */
226cdf0e10cSrcweir template <typename T>
inout_by_ptr(T * p)227cdf0e10cSrcweir inline detail::copy_back_wrapper<T> inout_by_ptr( T * p )
228cdf0e10cSrcweir {
229cdf0e10cSrcweir return detail::copy_back_wrapper<T>(p);
230cdf0e10cSrcweir }
231cdf0e10cSrcweir
232cdf0e10cSrcweir /** This function will execute the passed functor synchronously in the
233cdf0e10cSrcweir solar thread, thus the calling thread will (eventually) be blocked until
234cdf0e10cSrcweir the functor has been called.
235cdf0e10cSrcweir Any UNO exception that came up calling the functor in the solar thread
236cdf0e10cSrcweir will be caught and rethrown in the calling thread. Any non-UNO
237cdf0e10cSrcweir exception needs to be handled by the called functor.
238cdf0e10cSrcweir The result type of this function needs to be default constructable.
239cdf0e10cSrcweir Please keep in mind not to pass addresses to stack variables
240cdf0e10cSrcweir (e.g. for out parameters) to foreign threads, use inout_by_ref()
241cdf0e10cSrcweir for this purpose. For in parameters, this may not affect you, because
242cdf0e10cSrcweir the functor object is copy constructed into free store. This way
243cdf0e10cSrcweir you must not use boost::cref()/boost::ref() or similar for objects on
244cdf0e10cSrcweir your thread's stack.
245cdf0e10cSrcweir Use inout_by_ref() or inout_by_ptr() for this purpose, e.g.
246cdf0e10cSrcweir
247cdf0e10cSrcweir <pre>
248cdf0e10cSrcweir using namespace vcl::solarthread;
249cdf0e10cSrcweir
250cdf0e10cSrcweir long n = 3;
251cdf0e10cSrcweir // calling foo( long & r ):
252cdf0e10cSrcweir syncExecute( boost::bind( &foo, inout_by_ref(n) ) );
253cdf0e10cSrcweir // calling foo( long * p ):
254cdf0e10cSrcweir syncExecute( boost::bind( &foo, inout_by_ptr(&n) ) );
255cdf0e10cSrcweir
256cdf0e10cSrcweir char const* pc = "default";
257cdf0e10cSrcweir // calling foo( char const** ppc ):
258cdf0e10cSrcweir syncExecute( boost::bind( &foo, inout_by_ptr(&pc) ) );
259cdf0e10cSrcweir // calling foo( char const*& rpc ):
260cdf0e10cSrcweir syncExecute( boost::bind( &foo, inout_by_ref(pc) ) );
261cdf0e10cSrcweir </pre>
262cdf0e10cSrcweir
263cdf0e10cSrcweir @tpl ResultT result type, defaults to FuncT::result_type to seamlessly
264cdf0e10cSrcweir support mem_fn and bind
265cdf0e10cSrcweir @tpl FuncT functor type, let your compiler deduce this type
266cdf0e10cSrcweir @param func functor object to be executed in solar thread
267cdf0e10cSrcweir @return return value of functor
268cdf0e10cSrcweir */
269cdf0e10cSrcweir template <typename ResultT, typename FuncT>
syncExecute(FuncT const & func)270cdf0e10cSrcweir inline ResultT syncExecute( FuncT const& func )
271cdf0e10cSrcweir {
272cdf0e10cSrcweir return detail::GenericSolarThreadExecutor<FuncT, ResultT>::exec(func);
273cdf0e10cSrcweir }
274cdf0e10cSrcweir
275cdf0e10cSrcweir template <typename FuncT>
syncExecute(FuncT const & func)276cdf0e10cSrcweir inline typename FuncT::result_type syncExecute( FuncT const& func )
277cdf0e10cSrcweir {
278cdf0e10cSrcweir return detail::GenericSolarThreadExecutor<
279cdf0e10cSrcweir FuncT, typename FuncT::result_type>::exec(func);
280cdf0e10cSrcweir }
281cdf0e10cSrcweir
282cdf0e10cSrcweir } // namespace solarthread
283cdf0e10cSrcweir } // namespace vcl
284cdf0e10cSrcweir
285