xref: /aoo41x/main/vcl/inc/vcl/threadex.hxx (revision 0d63794c)
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