1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #ifndef INCLUDED_VCL_THREADEX_HXX
21 #define INCLUDED_VCL_THREADEX_HXX
23 #include <osl/conditn.h>
24 #include <osl/thread.h>
25 #include <tools/link.hxx>
26 #include <vcl/dllapi.h>
28 #include <cppuhelper/exc_hlp.hxx>
29 #include <boost/optional.hpp>
34 class VCL_DLLPUBLIC SolarThreadExecutor
36 oslCondition m_aStart
;
37 oslCondition m_aFinish
;
41 DECL_DLLPRIVATE_LINK( worker
, void* );
44 SolarThreadExecutor();
45 virtual ~SolarThreadExecutor();
47 virtual long doIt() = 0;
48 long execute() { return impl_execute( NULL
); }
49 // caution: timeout for getting the solar mutex, not for ending
50 // the operation of doIt(). If doIt actually gets called within
51 // the specified timeout, execute will only return after
53 long execute( const TimeValue
& _rTimeout
) { return impl_execute( &_rTimeout
); }
56 bool didTimeout() const { return m_bTimeout
; }
59 long impl_execute( const TimeValue
* _pTimeout
);
62 namespace solarthread
{
67 template <typename FuncT
, typename ResultT
>
68 class GenericSolarThreadExecutor
: public SolarThreadExecutor
71 static ResultT
exec( FuncT
const& func
)
73 typedef GenericSolarThreadExecutor
<FuncT
, ResultT
> ExecutorT
;
74 ::std::unique_ptr
<ExecutorT
> const pExecutor( new ExecutorT(func
) );
76 if (pExecutor
->m_exc
.hasValue())
77 ::cppu::throwException( pExecutor
->m_exc
);
78 return *pExecutor
->m_result
;
82 explicit GenericSolarThreadExecutor( FuncT
const& func
)
83 : m_exc(), m_func(func
), m_result() {}
85 virtual long doIt() SAL_OVERRIDE
88 m_result
.reset( m_func() );
90 catch (::com::sun::star::uno::Exception
&) {
91 // only UNO exceptions can be dispatched:
92 m_exc
= ::cppu::getCaughtException();
97 ::com::sun::star::uno::Any m_exc
;
99 // using boost::optional here omits the need that ResultT is default
101 ::boost::optional
<ResultT
> m_result
;
104 template <typename FuncT
>
105 class GenericSolarThreadExecutor
<FuncT
, void> : public SolarThreadExecutor
108 static void exec( FuncT
const& func
)
110 typedef GenericSolarThreadExecutor
<FuncT
, void> ExecutorT
;
111 ::std::unique_ptr
<ExecutorT
> const pExecutor( new ExecutorT(func
) );
112 pExecutor
->execute();
113 if (pExecutor
->m_exc
.hasValue())
114 ::cppu::throwException( pExecutor
->m_exc
);
118 explicit GenericSolarThreadExecutor( FuncT
const& func
)
119 : m_exc(), m_func(func
) {}
121 virtual long doIt() SAL_OVERRIDE
126 catch (::com::sun::star::uno::Exception
&) {
127 // only UNO exceptions can be dispatched:
128 m_exc
= ::cppu::getCaughtException();
133 ::com::sun::star::uno::Any m_exc
;
137 template <typename T
>
138 class copy_back_wrapper
141 operator T
*() const { return &m_holder
->m_value
; }
142 operator T
&() const { return m_holder
->m_value
; }
144 explicit copy_back_wrapper( T
* p
) : m_holder( new data_holder(p
) ) {}
146 // no thread-safe counting needed here, because calling thread blocks
147 // until solar thread has executed the functor.
148 copy_back_wrapper( copy_back_wrapper
<T
> const& r
)
149 : m_holder(r
.m_holder
) { ++m_holder
->m_refCount
; }
150 ~copy_back_wrapper() {
151 --m_holder
->m_refCount
;
152 if (m_holder
->m_refCount
== 0) {
160 sal_Int32 m_refCount
;
161 data_holder( T
* p
) : m_value(*p
), m_ptr(p
), m_refCount(1) {}
162 ~data_holder() { *m_ptr
= m_value
; }
164 data_holder
* const m_holder
;
167 } // namespace detail
169 /** Makes a copy back reference wrapper to be used for inout parameters.
170 Only use for syncExecute(), the returned wrapper relies on its
171 implementation, i.e. the function object is stored in free store.
172 Type T needs to be copy constructable assignable.
175 @param r reference to a stack variable
176 @return reference wrapper
178 template <typename T
>
179 inline detail::copy_back_wrapper
<T
> inout_by_ref( T
& r
)
181 return detail::copy_back_wrapper
<T
>(&r
);
184 /** Makes a copy back ptr wrapper to be used for inout parameters.
185 Only use for syncExecute(), the returned wrapper relies on its
186 implementation, i.e. the function object is stored in free store.
187 Type T needs to be copy constructable assignable.
190 @param p pointer to a stack variable
193 template <typename T
>
194 inline detail::copy_back_wrapper
<T
> inout_by_ptr( T
* p
)
196 return detail::copy_back_wrapper
<T
>(p
);
199 /** This function will execute the passed functor synchronously in the
200 solar thread, thus the calling thread will (eventually) be blocked until
201 the functor has been called.
202 Any UNO exception that came up calling the functor in the solar thread
203 will be caught and rethrown in the calling thread. Any non-UNO
204 exception needs to be handled by the called functor.
205 The result type of this function needs to be default constructable.
206 Please keep in mind not to pass addresses to stack variables
207 (e.g. for out parameters) to foreign threads, use inout_by_ref()
208 for this purpose. For in parameters, this may not affect you, because
209 the functor object is copy constructed into free store. This way
210 you must not use \verbatim boost::cref()/boost::ref() \endverbatim or similar
211 for objects on your thread's stack.
212 Use inout_by_ref() or inout_by_ptr() for this purpose, e.g.
215 using namespace vcl::solarthread;
218 // calling foo( long & r ):
219 syncExecute( boost::bind( &foo, inout_by_ref(n) ) );
220 // calling foo( long * p ):
221 syncExecute( boost::bind( &foo, inout_by_ptr(&n) ) );
223 char const* pc = "default";
224 // calling foo( char const** ppc ):
225 syncExecute( boost::bind( &foo, inout_by_ptr(&pc) ) );
226 // calling foo( char const*& rpc ):
227 syncExecute( boost::bind( &foo, inout_by_ref(pc) ) );
230 @tpl ResultT result type, defaults to FuncT::result_type to seamlessly
231 support mem_fn and bind
232 @tpl FuncT functor type, let your compiler deduce this type
233 @param func functor object to be executed in solar thread
234 @return return value of functor
236 template <typename ResultT
, typename FuncT
>
237 inline ResultT
syncExecute( FuncT
const& func
)
239 return detail::GenericSolarThreadExecutor
<FuncT
, ResultT
>::exec(func
);
242 template <typename FuncT
>
243 inline typename
FuncT::result_type
syncExecute( FuncT
const& func
)
245 return detail::GenericSolarThreadExecutor
<
246 FuncT
, typename
FuncT::result_type
>::exec(func
);
249 } // namespace solarthread
252 #endif // INCLUDED_VCL_THREADEX_HXX
254 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */